strlen和sizeof

定义

strlensizeof 是 C 语言中两个用于确定字符串或数据类型大小的常用操作符,但它们的工作方式和目的有所不同。下面是对这两个操作符的详细解释:

strlen

strlen 是一个库函数,定义在 <string.h> 头文件中。它用于计算以空字符(\0)结尾的字符串的长度。

函数原型

size_t strlen(const char *str);

参数

  • str:指向以空字符结尾的字符串的指针。

返回值

  • 返回字符串中字符的个数,不包括末尾的空字符。

示例

#include <stdio.h>  
#include <string.h>  
  
int main() {  
    char str[] = "Hello";  
    printf("Length of str: %zu\n", strlen(str)); // 输出:Length of str: 5  
    return 0;  
}

注意事项

  • strlen 只能用于以空字符结尾的字符串。如果传递给 strlen 的指针没有指向一个以空字符结尾的字符串,strlen 会继续读取内存,直到遇到空字符为止,这可能导致未定义行为(包括程序崩溃)。
  • strlen 的计算开销较大,因为它需要遍历整个字符串来查找空字符。因此,如果字符串的长度是已知的或者不会改变,使用 strlen 可能不是最高效的方法。

sizeof

sizeof 是一个编译器内置的操作符,用于确定变量或类型所占用的内存大小(以字节为单位)。

语法

size_t sizeof(object);  
size_t sizeof(type);

参数

  • object:可以是变量、数组、结构体等。
  • type:可以是数据类型(如 int, float, char 等)。

返回值

  • 返回对象或类型所占用的内存大小(以字节为单位)。

示例

#include <stdio.h>  
  
int main() {  
    char c = 'A';  
    int i = 42;  
    double d = 3.14;  
    char str[] = "Hello";  
  
    printf("Size of char: %zu bytes\n", sizeof(c));       // 输出:Size of char: 1 byte  
    printf("Size of int: %zu bytes\n", sizeof(i));        // 输出可能是:Size of int: 4 bytes(取决于平台)  
    printf("Size of double: %zu bytes\n", sizeof(d));     // 输出可能是:Size of double: 8 bytes(取决于平台)  
    printf("Size of str: %zu bytes\n", sizeof(str));      // 输出:Size of str: 6 bytes(包括末尾的空字符)  
    printf("Size of pointer: %zu bytes\n", sizeof(&c));   // 输出指针的大小,通常是 4 或 8 字节(取决于平台)  
    return 0;  
}

注意事项

  • sizeof 在编译时就能确定结果,因此它是一个常量表达式。
  • sizeof 计算的是对象或类型在内存中的大小,而不是它存储的值的数量。例如,对于数组 strsizeof(str) 返回的是整个数组(包括末尾的空字符)所占用的字节数,而不是字符串的长度。
  • sizeof 可以用于任何数据类型和对象,包括基本类型、结构体、联合、数组和指针等。

总结来说,strlen 用于计算字符串的长度(不包括末尾的空字符),而 sizeof 用于确定变量或类型在内存中的大小(以字节为单位)。在处理字符串时,如果你想知道字符串包含多少个字符,应该使用 strlen;如果你想知道存储字符串的数组或变量需要多少内存,应该使用 sizeof

详细示例及结论

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    char name[24]="haha ";
    int iLen = strlen(name);
    printf("strlen name has " " = %d\n",iLen);
    iLen = sizeof(name);
    printf("sizeof name has " "  = %d\n",iLen);
// strlen name has  = 5
// sizeof name has   = 24
//结论 空格占用一个字符

    char name1[24]="haha";
    iLen = strlen(name1);
    printf("strlen name  = %d\n",iLen);
    iLen = sizeof(name1);
    printf("sizeof name  = %d\n",iLen);
// strlen name  = 4 
// sizeof name  = 24

    char name2[24]="haha\n";
    iLen = strlen(name2);
    printf("strlen name has \\n = %d\n",iLen);
    iLen = sizeof(name2);
    printf("sizeof name has \\n = %d\n",iLen);
// strlen name has \n = 5
// sizeof name has \n = 24
//结论 换行符占用一个字符
    char name3[24]="haha\0";
    iLen = strlen(name3);
    printf("strlen name has \\0 = %d\n",iLen);
    iLen = sizeof(name3);
    printf("sizeof name has \\0  = %d\n",iLen);
// strlen name has \0 = 4
// sizeof name has \0  = 24
//结论 结束符不占用字符
    char name4[24]="";
    iLen = strlen(name4);
    printf("strlen name has no member = %d\n",iLen);
    iLen = sizeof(name4);
    printf("sizeof name has no member  = %d\n",iLen);

// strlen name has no member = 0
// sizeof name has no member  = 24


    char name5[24]="haha\\n";
    iLen = strlen(name5);
    printf("strlen name has \\n = %d\n",iLen);
    iLen = sizeof(name5);
    printf("sizeof name has \\n = %d\n",iLen);
//     strlen name has \n = 6
// sizeof name has \n = 24
    return 0;
}

编译运行结果

常见问题

每一个字符串默认自带什么字符

在C语言中,每一个字符串默认自带一个结束字符,即空字符(null character),用 \0 表示。这个空字符用于标识字符串的结束位置。因此,当你定义一个字符串时,编译器会自动在字符串的末尾添加一个 \0 字符。例如,当你写下以下代码:

char str[] = "Hello";

实际上,在内存中,str 数组的内容会是:

H e l l o \0

这里,\0 就是字符串的结束符,它告诉 strlen 和其他字符串处理函数在哪里停止读取字符串。这个特性使得C语言的字符串函数能够正确地处理变长字符串,而不需要提前知道字符串的确切长度。

stren 字符串长度 不包含结束符吧

是的,strlen 函数计算字符串的长度时,是不包含末尾的空字符(null character,即 \0)的。strlen 函数返回的是从字符串开始到第一个空字符之前的字符数,即实际存储的可见字符的数量。因此,如果你有一个字符串 "Hello"strlen 函数会返回 5,因为字符串包含五个字符 'H', 'e', 'l', 'l', 'o',而不包括末尾的 \0

这个特性是设计 strlen 函数时有意为之的,因为空字符在C语言中被用作字符串的结束标志,而不是字符串内容的一部分。因此,在计算字符串长度时,空字符不被计入长度内。这样,strlen 和其他字符串处理函数就能够正确地处理字符串,直到遇到结束标志为止。

字符串拷贝 目的字符串的长度是不是要比strlen计算的拷贝的字符串长度加1

是的,当进行字符串拷贝操作时,目的字符串(即目标缓冲区)的长度应该至少要比源字符串的长度(通过 strlen 计算得出)多 1。这是因为 strlen 函数返回的是源字符串中字符的数量,不包括末尾的空字符(null terminator, \0)。在拷贝字符串时,你需要确保目的字符串有足够的空间来容纳源字符串的所有字符,以及额外的空字符作为结束符。

例如,如果你有一个源字符串 "Hello",它的长度是 5(通过 strlen 计算得出)。当你拷贝这个字符串到另一个缓冲区时,你需要一个至少长度为 6 的缓冲区来确保能够存储所有的字符以及末尾的空字符。

char src[] = "Hello";  
char dest[6]; // 长度至少为 strlen(src) + 1  
  
strcpy(dest, src); // 拷贝字符串,包括末尾的空字符

在上面的代码中,dest 数组的长度是 6,这足够存储源字符串 "Hello" 的 5 个字符以及一个空字符。使用 strcpy 函数进行拷贝时,它会将源字符串的所有字符(包括末尾的空字符)复制到目的字符串中。

注意,如果目的字符串的长度小于源字符串的长度加一,就会发生缓冲区溢出(buffer overflow),这是一种常见的安全漏洞,可能导致程序崩溃或更严重的安全问题。因此,在进行字符串拷贝操作时,务必确保目的字符串有足够的空间。

不加1 会有什么影响 举例说明

如果在进行字符串拷贝操作时,目的字符串(即目标缓冲区)的长度没有比源字符串的长度多 1,即没有为末尾的空字符(null terminator, \0)预留空间,那么将会发生缓冲区溢出(buffer overflow)。这会导致一系列的问题,包括但不限于:

  1. 数据损坏:拷贝操作会覆盖目的字符串缓冲区末尾之后的内存区域,可能损坏该区域存储的其他重要数据。

  2. 程序崩溃:如果溢出的数据破坏了程序的执行状态(比如函数返回地址),程序可能会立即崩溃。

  3. 安全漏洞:攻击者可以利用缓冲区溢出漏洞执行恶意代码,获取系统的敏感信息或控制权限。

下面是一个具体的例子来说明不加 1 会产生的影响:

#include <stdio.h>  
#include <string.h>  
  
int main() {  
    char src[] = "Hello";  
    char dest[5]; // 长度没有比 strlen(src) + 1 大  
  
    strcpy(dest, src); // 拷贝字符串,但没有足够的空间容纳空字符  
  
    printf("dest: %s\n", dest); // 尝试打印 dest,但可能会崩溃或输出错误内容  
  
    return 0;  
}

在这个例子中,dest 数组的长度是 5,与 src 字符串的可见字符数相等,但没有额外的空间来存储末尾的空字符。当使用 strcpy 函数进行拷贝时,它会尝试将 src 中的所有字符(包括末尾的空字符)复制到 dest 中。由于 dest 没有足够的空间,最后一个空字符会被写入 dest 数组之后的内存区域,这可能会导致未定义的行为。

在实际执行时,程序可能会崩溃,或者如果 dest 数组后面恰好有其他变量的内存,那么这些变量的值可能会被意外地修改。此外,如果 dest 数组后面是程序的栈空间,并且溢出的数据覆盖了函数的返回地址,那么程序可能会跳转到错误的地址执行,导致更严重的后果。

为了避免这种情况,总是要确保目的字符串的长度至少比源字符串的长度多 1,以便有足够的空间来存储空字符。在实践中,使用像 strncpy 这样的安全字符串拷贝函数也是一个好的做法,因为它们允许你指定一个最大拷贝长度,从而防止缓冲区溢出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/488574.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

拥有超小型领先工艺射频微波电子元器件厂商兆讯授权世强硬创代理

射频前端芯片在模拟芯片中&#xff0c;属于进入门槛较高、设计难度较大的细分领域&#xff0c;由于国内射频前端芯片行业起步较晚&#xff0c;其市场份额主要被外企所占据&#xff0c;而在国产化浪潮的推动下&#xff0c;上游厂商的射频前端产品及技术逐渐具备领先的竞争优势。…

深度学习(三)vscode加jupyter notebook插件使用

0.前言 哎呀&#xff0c;我本次的实验是在新电脑上使用的&#xff0c;之前的笔记本上的环境什么的我都是很久以前弄好了的&#xff0c;结果到了新电脑上我直接忘了是该怎么配的了&#xff0c;不过万幸&#xff0c;花了点时间&#xff0c;查查补补&#xff0c;现在总算是可以了。…

论文汇总:A Closer Look at Few-shot Classification Again

文章汇总 文章是在总体上再一次地观察如何小样本领域存在的问题&#xff0c;并且发现了较为有趣的规律 1.测试误差随训练类别的数量而下降&#xff0c;而不是随每个类别的训练样本数量而下降。 2.训练算法(me&#xff1a;预训练模型)和自适应算法(me&#xff1a;预训练之后的…

参展企业和专业观众均创历届新高“2024杭州国际安防展会”

随着社会的不断发展&#xff0c;安防行业逐渐成为一个备受关注的领域。杭州作为中国的科技创新之城&#xff0c;一直以来都是安防行业的重要聚集地。本次展会的举办&#xff0c;不仅为参展企业提供了一个展示自身实力的平台&#xff0c;也为观众提供了一个了解安防行业最新技术…

深度解析JVM世界:JVM内存分配

本篇文章的主要内容是介绍JVM内存的分配方式、JVM内存的快速分配策略、JVM的逃逸分析和堆内存的分代思想几部分内容。 请同学们认真听讲&#xff0c;面试会问到。。。 1. 内存分配 大家需要注意不分配内存的对象无法进行其他操作 JVM 为对象分配内存的过程&#xff1a;首先…

[flask]http请求//获取请求体数据

import jsonfrom flask import Flask, requestapp Flask(__name__)app.route("/form1", methods["post"]) def form1():"""获取客户端请求的请求体[表单]:return:""""""获取表单数据请求url&#xff1a;&qu…

[深度学习]yolov8+streamlit搭建精美界面GUI网页设计源码实现三

【设计思路介绍】 为了使用YOLOv8和Streamlit搭建一个精美的界面GUI网页&#xff0c;你需要遵循几个关键步骤。以下是一个简化的流程&#xff0c;帮助你设计并实现这一目标&#xff1a; 1. 环境准备 安装YOLOv8 YOLOv8是一个先进的实时目标检测模型。你需要先下载并安装YOL…

Android Studio 代理

Android Studio的代理&#xff0c;分为两级代理&#xff1a; 1. Android Studio本身的代理&#xff0c;路径在&#xff0c;右上角&#xff0c;File->Settings->Appearance & Behavior -> System Settings -> Http Proxy&#xff0c;如图所示&#xff1a; 2. G…

Mybatis中QueryWrapper的复杂查询SQL

最近在使用QueryWrapper编写查询语句时发现复杂的SQL不会写。在网上找了半天&#xff0c;终于得到了点启示。在此做个记录以备忘。 我要实现的SQL是这样的&#xff1a; -- 实现这个复杂查询 -- 查询设备表 select * from oa_device where ((dev_code BSD1003 and dev_status…

护眼灯有没有必要买?多款高口碑护眼台灯推荐

我发现目前仍有很多家长都忽视了环境光的重要性&#xff0c;在孩子学习的时候习惯只开家里的吸顶灯提供作业&#xff0c;但其实环境光线的不足&#xff0c;对孩子的眼镜危害是非常大的&#xff01;也有家长问护眼灯有没有必要买&#xff1f; 我认为是很有必要的&#xff01;因…

基于java+SpringBoot+Vue的乐校园二手书交易管理系统设计与实现

基于javaSpringBootVue的乐校园二手书交易管理系统设计与实现 开发语言: Java 数据库: MySQL技术: SpringBoot MyBatis工具: IDEA/Eclipse、Navicat、Maven 系统展示 前台展示 后台展示 系统简介 整体功能包含&#xff1a; 乐校园二手书交易管理系统是一个基于互联网的二…

纹理压缩算法

一、什么是纹理压缩 我们知道游戏中对于3D物体表面细节的表现最重要的还是靠贴图来实现的&#xff0c;那么越是高分辨率越是真彩色的贴图自然表现力也是越强&#xff0c;但是同时带来的问题是所需占用的内存会成倍的上升&#xff0c;而节省内存这一点在目前的游戏中还是非常非…

解决Spring Gateway配置单个路由超时时间不生效的问题

之前springcloud gateway项目是的路由配置都是静态配置在项目的application.yml文件中&#xff0c;不能实现路由的热更新。前期业务发展也比较缓慢&#xff0c;新增路由的场景频率不是很高&#xff0c;最近业务越来越广&#xff0c;新增项目频率明显升高&#xff0c;所以想着把…

第44期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

数据结构:Trie(前缀树/字典树)

文章目录 一、介绍Trie1.1、Trie的结点结构1.2、Trie的整体结构 二、Trie的操作2.1、Trie插入操作2.2、Trie查找操作2.3、Trie前缀匹配操作2.4、Trie删除操作 三、实战3.1、实现Trie&#xff08;前缀树&#xff09; 一、介绍Trie Trie 又称字典树、前缀树和单词查找树&#xff…

flask_restful渲染模版

渲染模版就是在 Flask_RESTful 的类视图中要返回 html 片段代码&#xff0c;或 者是整个html 文件代码。 如何需要浏览器渲染模板内容应该使用 api.representation 这个装饰器来定 义一个函数&#xff0c; 在这个函数中&#xff0c;应该对 html 代码进行一个封装&#xff…

vue2 key的作用和原理

我们在写v-for的时候都会绑定一个key值,这个key在vue中有什么作用呢,不写可以吗? 目标 1 key有什么作用 2 如何不写key会产生什么影响 3 key使用原理 key的作用 可以看vue2官网上给的解释,“给vue一个提示,以便跟踪每个节点的身份”,这样听着很模棱两可,到底是什么作用…

解决“Pycharm中Matplotlib图像不弹出独立的显示窗口”问题

matplotlib的绘图的结果默认显示在SciView窗口中, 而不是弹出独立的窗口, 这样看起来就不是很舒服&#xff0c;不习惯。 通过修改设置&#xff0c;改成独立弹出的窗口。 File—>Settings—>Tools—>Python Scientific—>Show plots in toolwindow 将√去掉即可

在for循环加判断条件当条件都满足时,同时显现的解决方法

一、代码示例 function fu(s) {str ;ste ;console.log(s);let Things s;for (let i 0; i < Things.length; i) {if (Things[i].pid kk) {console.log(Things[i].pid);ste <div class"commodity_nei"><div class"zxc_pic"><div cl…