详解sizeof()和strlen()的细节及用法

简介: 详解sizeof()和strlen()的细节及用法

sizeof和strlen的对比

  1. sizeof() 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小
    sizeof ()只关注占⽤内存空间的大小,不在乎内存中存放什么数据
  2. strlen()是C语言库函数,功能是求字符串长度。 函数原型:
size_t strlen ( const char * str );

统计的是从 strlen()函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。strlen()函数会⼀直向后找\0 字符,直到找到为止,所以可能存在越界查找。

那我们思考一下如果我们传一个字符给strlen()会怎么样?详细请看下面求strlen(*arr),这时我们会讲到实际案例!!!

那我们再思考一下如果我们传一个数组地址给strlen()会怎么样?详细请看下面求strlen(&arr),这时我们会讲到实际案例!!!

在开始下面的介绍前还有一点非常重要,数组名的意义:

3. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小

4. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址

5. 除此之外所有的数组名都表示首元素的地址

计算一维数组

整形数组

    int a[] = {1,2,3,4};
    printf("%d\n",sizeof(a));
    printf("%d\n",sizeof(a+0));
    printf("%d\n",sizeof(*a));
    printf("%d\n",sizeof(a+1));
    printf("%d\n",sizeof(a[1]));
    printf("%d\n",sizeof(&a));
    printf("%d\n",sizeof(*&a));
    printf("%d\n",sizeof(&a+1));
    printf("%d\n",sizeof(&a[0]));
    printf("%d\n",sizeof(&a[0]+1));

我们先看一下输出的结果:

1.sizeof(a);//sizeof(数组名) 计算的是数组的总大小-=单位字节–16

2.sizeof(a+0);//肯定有人想问上一个还是16字节,怎么这儿就变成8了?其实这里a+0是一个表达式,并不满足sizeof(数组名)形式,所以这里a还是首元素地址,a+0还为首元素地址,地址大小都为4 / 8字节

3.sizeof(*a);//这里a是首元素地址,所以*a就是首元素的类型(int)的大小,即为4

4.sizeof(a+1);//这里a为首元素地址,则a+1就是第二个元素地址,类比于2.,为4 / 8字节

5.sizeof(a[1]);//第二个元素大小,4

6.sizeof(&a);//&a取出的是数组的地址,是地址都是4 / 8

7.sizeof(*&a);//&a是数组a的地址,*解引用后则就是数组a,此处计算的还是数组的大小,16字节

8…sizeof(&a+1);//根据上面我们不难想到,此处&a+1相当于&a跳过了一个数组,但还是一个地址,为4 / 8字节

9…sizeof(&a[0]);//首元素地址,4 / 8字节

10…sizeof(&a[0]+1);//第二个元素的地址,4 / 8字节

字符数组

字符数组与整形数组的sizeof()用法极其相似,这里就不多介绍了!

    char arr[] = { 'a','b','c','d','e','f' };
    printf("%d\n", strlen(arr));
    printf("%d\n", strlen(arr+0));
    printf("%d\n", strlen(*arr));
    printf("%d\n", strlen(arr[1]));
    printf("%d\n", strlen(&arr));
    printf("%d\n", strlen(&arr+1));
    printf("%d\n", strlen(&arr[0]+1));

运行结果:

1.strlen(arr);

2.strlen(arr+0);

我们可以看出这个字符数组并没有以'\0'结尾,所以strlen()计算首元素地址时,就产生了随机值!所以第一个和第二个是随机值!

3.strlen(*arr);

4. strlen(arr[1]);

开头我们介绍了strlen()函数接收的是一个地址。此处的*arr是数组首元素,arr[1]是数组第二个元素。所以编译器就会报错。还可以再深入讲一下,既然strlen()接收的是一个地址,而*arr是字符a,ASCII表的值为97,,此时strlen()就会把97当成一个地址去访问空间,但这个地址不是我们所拥有的空间,就形成了非法访问。

这里0x0000000000000061其实就是97,这也就印证了我们的说法。

5.strlen(&arr);

6.strlen(&arr+1);

7.strlen(&arr[0]+1);

&arr,&arr+1,&arr[0]+1其实都是地址,虽然第一个是一个数组的地址,但他的地址与首元素地址一样,所以为随机值,第二个跳过了一个数组所以为随机值-6,6是数组大小,第三个以为跳过了数组中的一个元素,所以为随机值-1

可以看出虽然&arr是一个数组地址,类型为数组指针char(*p)[6],事实上这只是当成一个地址看待,并不会真正影响结果。

字符串

    char arr[]="abcdef";
    printf("%d\n", strlen(arr));
    printf("%d\n", strlen(arr+0));
    printf("%d\n", strlen(&arr));
    printf("%d\n", strlen(&arr+1));
    printf("%d\n", strlen(&arr[0]+1));

我们看到这其实就会想到这不就是char arr[] = { 'a','b','c','d','e','f' ,'\0'};吗?没错!这里sizeof()计算方法还是与上面是一样的,但strlen()还是要说一下的。

1.strlen(arr);

2.strlen(arr+0);

既然有了'\0'为结尾,那结果肯定就是字符串长度了,即为6

3.strlen(&arr);//这就会返回'\0'之前字符个数,即为6

4.strlen(&arr+1);//但是这里&arr+1跳过了数组arr,于是返回了一个随机值

5.strlen(&arr[0]+1);//这指向的是'b'的地址,于是返回5

计算常量字符串

    char *p = "abcdef";
    printf("%d\n", sizeof(p));
    printf("%d\n", sizeof(p+1));
    printf("%d\n", sizeof(*p));
    printf("%d\n", sizeof(p[0]));
    printf("%d\n", sizeof(&p));

这儿难道是把"abcdef"放到p里面?其实这里的p仅仅放了'a'的地址

1.sizeof(p);//这儿就是计算指针变量p的地址,4 / 8字节

2.sizeof(p+1);//p+1得到的是字符'b'的地址,4 / 8字节

3.sizeof(*p);//*p其实就是字符串的第一个字符'a',1字节

4.sizeof(p[0]);//事实上这里的p[0]就等价于*(p+0),就是第一个元素,1字节

5.sizeof(&p);//这里&p把指针p的地址取出来了,4 / 8字节

    char *p = "abcdef";
    printf("%d\n", strlen(p));
    printf("%d\n", strlen(&p));
    printf("%d\n", strlen(&p+1));

1.strlen(p); //上面也分析过了,p存放的就是'a'的地址,strlen()找到'\0'结束,所以就是6

2.strlen(&p);

3.strlen(&p+1);//&p是指针p的地址,这里我画了一张图来说明一下:

所以这里求出来的其实是随机值!

计算二维数组

    int a[3][4] = {0};
    printf("%d\n",sizeof(a));
    printf("%d\n",sizeof(a[0][0]));
    printf("%d\n",sizeof(a[0]));
    printf("%d\n",sizeof(a[0]+1));
    printf("%d\n",sizeof(*(a[0]+1)));
    printf("%d\n",sizeof(a+1));
    printf("%d\n",sizeof(*(a+1)));
    printf("%d\n",sizeof(&a[0]+1));
    printf("%d\n",sizeof(*(&a[0]+1)));
    printf("%d\n",sizeof(*a));
    printf("%d\n",sizeof(a[3]));

我们看看编译器输出的结果吧!!!下面讲解一下为什么。

1.sizeof(a);//这里的a代表整个二维数组的数组名,大小为124,36字节
2.sizeof(a[0][0]);//这则是数组第一个元素,4字节

3.sizeof(a[0]);//a[0]是二维数组的第一行作为一维数组的数组名,所以sizeof()所求的是数组第一行的大小,大小为44,16字节

4.sizeof(a[0]+1);//此处a[0]表示第一行的数组名,表示的是首元素地址,其实就是第一行第一个元素的地址,所以a[0]+1就表示第一行第二个元素的地址,4 / 8字节

5.sizeof(*(a[0]+1));//如上*a[0]+1就是第一行第二个元素,4字节

6.sizeof(a+1);//我们考虑一下这是谁的地址呢?a是二维数组的数组名,是首元素地址,而二维数组的首元素是他的第一行,那么a就是第一行的地址,那么加一后就是第二行的地址,4 / 8字节

从这我们也可以看出两个地址相差了16,正是4个整形的大小,所以这也验证了上面,加一后跳过了一行。

7.sizeof(*(a+1));//如6.,解引用后就代表第二行,16字节

8.sizeof(&a[0]+1);//&a[0]取出第一行地址,加一后为第二行地址,4 / 8字节

9.sizeof(*(&a[0]+1));//解引用得到数组第二行,16字节

10.sizeof(*a);//a是首元素地址,第一行地址,解引用后为第一行,16字节

11.sizeof(a[3]);//a[3]是数组第四行,虽没有第四行,但根据数组类型,计算的任是一行有四个整形的数组大小,所以还为16

目录
相关文章
|
机器学习/深度学习 数据采集 缓存
Elasticsearch与机器学习集成的最佳实践
【8月更文第28天】Elasticsearch 提供了强大的搜索和分析能力,而机器学习则能够通过识别模式和预测趋势来增强这些能力。将两者结合可以实现更智能的搜索体验、异常检测等功能。
303 0
|
11月前
|
IDE 开发工具
【通信协议讲解】单片机基础重点通信协议解析与总结之CAN(四)
【通信协议讲解】单片机基础重点通信协议解析与总结之CAN(四)
249 1
|
机器学习/深度学习 人工智能 算法
理解机器学习:AI背后的驱动力
【7月更文第15天】在人工智能的广阔领域中,机器学习作为核心驱动力,正以前所未有的速度推动着技术革新和产业升级。本文旨在深入浅出地解析机器学习的基本原理,涵盖监督学习、无监督学习、以及强化学习这三大基石,并通过具体代码示例帮助读者更好地把握这些概念。
335 3
|
机器学习/深度学习 数据采集 监控
Python基于BP神经网络算法实现家用热水器用户行为分析与事件识别
Python基于BP神经网络算法实现家用热水器用户行为分析与事件识别
|
Linux 开发者 iOS开发
|
负载均衡 Ubuntu Java
nacos常见问题之升级到2.1.0重启后端服务如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
440 1
|
人工智能 自然语言处理
【AIGC】英语小助手Lingo:基于大语言模型的学习英语小帮手
【5月更文挑战第11天】英语小助手Lingo:基于大语言模型的学习英语小帮手
559 7
|
消息中间件 Kafka Linux
kafka3.0创建topic出现zookeeper is not a recognized option
kafka3.0创建topic出现zookeeper is not a recognized option
439 0
|
机器学习/深度学习 编解码 PyTorch
复旦大学提出SemiSAM | 如何使用SAM来增强半监督医学图像分割?这或许是条可行的路
复旦大学提出SemiSAM | 如何使用SAM来增强半监督医学图像分割?这或许是条可行的路
488 0
|
消息中间件 存储 Go
Golang微服务框架Kratos应用RocketMQ消息队列
RocketMQ是由阿里捐赠给Apache的一款低延迟、高并发、高可用、高可靠的分布式消息中间件。经历了淘宝双十一的洗礼。RocketMQ既可为分布式应用系统提供异步解耦和削峰填谷的能力,同时也具备互联网应用所需的海量消息堆积、高吞吐、可靠重试等特性。
372 0