【C语言】一篇就够了(建议收藏)——超详解sizeof与strlen的用法(三)

简介: 【C语言】一篇就够了(建议收藏)——超详解sizeof与strlen的用法(三)

字符串数组

微信图片_20220415161705.png


sizeof用法


  char arr[] = "abcdef";

   printf("%d\n", sizeof(arr));

   printf("%d\n", sizeof(arr+0));

   printf("%d\n", sizeof(*arr));

   printf("%d\n", sizeof(arr[1]));

   printf("%d\n", sizeof(&arr));

   printf("%d\n", sizeof(&arr+1));

   printf("%d\n", sizeof(&arr[0]+1));



解:


   printf("%d\n", sizeof(arr)); 7字节

abcdef\0 一共7个字节


   printf("%d\n", sizeof(arr+0)); 4/8


arr表示首元素字符地址,+0之后还是首元素字符 a 的地址,大小为4/8字节


  printf("%d\n", sizeof(*arr)); 1字节


arr是首元素地址,解引用*arr后就是首元素 字符a,大小为1字节


  printf("%d\n", sizeof(arr[1])); 1字节


arr[1] 表示第二个元素,也就是字符 b ,大小为1字节


  printf("%d\n", sizeof(&arr)); 4/8字节


&arr 是整个数组的地址,数组的地址也是地址,大小为4/8字节


  printf("%d\n", sizeof(&arr+1)); 4/8字节


&arr 是数组的地址,&arr+1是跳过整个数组,得到数组后一位的地址,4//8字节


  printf("%d\n", sizeof(&arr[0]+1)); 4//8字节


&arr[0]是第一个元素地址,&arr[0]+1 是第二个元素地址,大小为4/8字节


strlen的用法


   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));

   printf("%d\n", strlen(&arr+1));

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


解:


  printf("%d\n", strlen(arr)); 6


strlen只对abcdef计数, 不算\0一共6个字符,也就是6字节


  printf("%d\n", strlen(arr+0)); 6


arr是首元素地址,+0后还是首元素的地址,从首地址开始计数,仍然为6字节


   printf("%d\n", strlen(*arr)); 系统报错

   printf("%d\n", strlen(arr[1])); 系统报错

*arr传入的是数组首元素,就是字符a,strlen接收到的其实是字符a的ASCII码值97,97不是合法地址,相当于野指针,所以会报错

arr[1]同理,传入的是第二个元素字符 b ,strlen接收到的是字符b 的ASCII码值98,是非法地址,所以也会报错


  printf("%d\n", strlen(&arr)); 6


&arr是取得整个数组的地址,数值上等于首元素地址,strlen接收到的就是首元素地址,于是从首元素开始计数,结果为6字节


  printf("%d\n", strlen(&arr+1)); 随机值


微信图片_20220415162120.png

&arr+1得到的地址如上图所示,一直向后读取,不知道什么时候才能读取到\0,所以strlen得到的结果为随机值


  printf("%d\n", strlen(&arr[0]+1));5字节

&arr[0]是第一个元素地址,+1之后得到第二个元素地址,从第二个元素地址开始读取,读到\0前,一共5个字节


指针与字符串


sizeof用法


   const 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));

   printf("%d\n", sizeof(&p+1));

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


解:


  printf("%d\n", sizeof(p)); 4/8字节


p是一个指针变量,存的是字符串首元素地址,所以是4/8字节


  printf("%d\n", sizeof(p+1)); 4/8字节


p是一个指针变量,存的是字符串首元素址,+1之后就是字符串第二个元素的地址,也就是 b 的地址,是4/8个字节


  printf("%d\n", sizeof(*p)); 1字节


p是一个指针变量,存的是字符串首元素地址,对其解引用,*p得到的是字符 a ,类型为char,大小为1个字节


  printf("%d\n", sizeof(p[0])); 1字节


p[0] = *(p+0) = *p,这三种写法表示的都是首元素字符 a ,大小为1个字节


  printf("%d\n", sizeof(&p)); 4/8字节


p是一个指针变量,是一个地址,对指针变量取地址,得到的是一个地址的地址,还是一个地址,所以大小还是4/8字节


  printf("%d\n", sizeof(&p+1)); 4/8字节


p是个指针变量,字符串通过指针存到内存中,其实也可以理解成这是内存中一块连续的储存空间,就像数组一样,这里的 &p+1 ,p是一个指向字符串首元素的一级指针,&p是指针变量p的地址,是一个二级指针,+1之后,相当于二级指针+1,指向的是一块我们不知道的未知空间,但说到底还是一个地址,大小仍是4/8字节,如图所示:

微信图片_20220415162456.png


  printf("%d\n", sizeof(&p[0]+1)); 4/8字节


字符串也是一块连续空间,可以像数组一样通过 [ ] 访问p[0] = *(p+0) = *p这三种表示方法都可以表示字符串元素,这里&p[0]表示首元素地址,+1就是第二个元素字符b的地址,是地址,大小为4/8字节


strlen用法


   const char *p = "abcdef";

   printf("%d\n", strlen(p));

   printf("%d\n", strlen(p+1));

   printf("%d\n", strlen(*p));

   printf("%d\n", strlen(p[0]));

   printf("%d\n", strlen(&p));

   printf("%d\n", strlen(&p+1));

   printf("%d\n", strlen(&p[0]+1));


解:

  printf("%d\n", strlen(p)); 6


p存放的是字符串首元素地址,相当于给strlen传入了字符a的地址,strlen向后读取,直到\0,总计6个字符,就是6字节


  printf("%d\n", strlen(p+1)); 5


p存放的是字符串首元素地址,p+1就是第二个元素字符b的地址,相当于给strlen传入了字符b的地址,strlen向后读取,直到\0,总计5个字符,就是5字节


  printf("%d\n", strlen(*p));系统报错


p是首元素地址,*p相当于访问这个地址,传入strlen的是字符a的ASCII码值97,97是非法地址,是个野指针,系统报错


  printf("%d\n", strlen(p[0])); 系统报错


p[0] = *(p+0) = *p表示的都是首元素字符a,传入strlen的是字符a的ASCII码值97,97是非法地址,是个野指针,系统报错


   printf("%d\n", strlen(&p)); 随机值

   printf("%d\n", strlen(&p+1));随机值


如图所示,&p是一个二级指针究其根本还是是一个地址,strlen接收到的还是一个地址,会从这个地址向后读取,不知道在何处能读到\0,所以结果会是一个随机值,&p+1同理


微信图片_20220415162758.png

  printf("%d\n", strlen(&p[0]+1)); 5


&p[0]是首元素地址,+1变成第二个元素地址,从该地址向后读取直到\0,总计5个字符


二维数组


微信图片_20220415162821.png

sizeof


   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]));


  printf("%d\n",sizeof(a)); 48

sizeof(数组名)表示的是整个数组的大小,这个int型二维数组是3×4的,大小为12×4=48个字节


  printf("%d\n",sizeof(a[0][0])); 4


sizeof(a[0][0]) 计算的是第一行第一列的元素的大小,这是一个int型二维数组,大小为4字节


   printf("%d\n",sizeof(a[0])); 16

   printf("%d\n",sizeof(a[0]+1));4/8

我们可以将二维数组的每一行看成一个一维数组,a[0]就相当于一维数组的数组名,所以sizeof(a[0]),数组名单独放在sizeof里,计算的就是第一行数组的大小,就是16字节


sizeof(a[0]+1)表示,a[0]是第一行数组的数组名,并没有单独放在sizeof内部,也没有&

所以a[0]表示首元素的地址,也就是第一行这个数组的第一个元素的地址

所以a[0]+1就是第一行,第二个元素的地址,大小为4/8字节


微信图片_20220415163131.png


  printf("%d\n",sizeof(*(a[0]+1))); 4

(a[0]+1)表示第一行第二个元素的地址,解引用后就是第一行第二个元素,大小是4字节


   printf("%d\n",sizeof(a+1)); 4/8

这里二维数组的数组名表示首元素地址 (注意:这里的首元素指的是第一行)

a的指针类型是int(*)[4]

a+1代表的是第二行数组的地址,也就是4/8字节


  printf("%d\n",sizeof(*(a+1))); 16


*(a+1)就是第二行数组,相当于a[1],数组名单独放在sizeof内部,sizeof(a[1]), 第二行数组大小为16字节


  printf("%d\n",sizeof(&a[0]+1)); 4/8


a[0]是第一行的数组名,&a[0]是对数组名取地址,拿到的是第一行数组的地址,所以这时候+1,拿到的是第二行数组的地址,所以大小为4/8


  printf("%d\n",sizeof(*(&a[0]+1))); 16字节


&a[0]+1 是第二行数组地址,对其解引用*(&a[0]+1))得到的就是第二行数组第二行数组名单独放在sizeof内部,求的是第二行数组的大小,是16字节


   printf("%d\n",sizeof(*a)); 16


a是首元素地址,就是二维数组的第一行数组,对其解引用,*a拿到的是第一行数组,第一行数组名单独放在sizeof内部,求的是第一行数组的大小,大小是16字节


  printf("%d\n",sizeof(a[3])); 16字节


sizeof内部表达式是不参与运算的,a[3]是第四行数组名,二维数组创建好了之后,元素是固定的,这个时候,假如第四行存在,sizeof会根据a这个二维数组,根据二维数组每一行的类型推导出第四行大小,所以sizeof(a[3])求出第四行大小是16字节


原创不易,以上仅为个人学习中的理解,还请大牛们多多指教~

————————————————

版权声明:本文为CSDN博主「敲代码的布莱恩特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/DerrickWestbrook/article/details/120114553

相关文章
|
1月前
|
IDE 编译器 开发工具
【C语言】全面系统讲解 `#pragma` 指令:从基本用法到高级应用
在本文中,我们系统地讲解了常见的 `#pragma` 指令,包括其基本用法、编译器支持情况、示例代码以及与传统方法的对比。`#pragma` 指令是一个强大的工具,可以帮助开发者精细控制编译器的行为,优化代码性能,避免错误,并确保跨平台兼容性。然而,使用这些指令时需要特别注意编译器的支持情况,因为并非所有的 `#pragma` 指令都能在所有编译器中得到支持。
120 41
【C语言】全面系统讲解 `#pragma` 指令:从基本用法到高级应用
|
4月前
|
C语言
C语言判断逻辑的高阶用法
在C语言中,高级的判断逻辑技巧能显著提升代码的可读性、灵活性和效率。本文介绍了六种常见方法:1) 函数指针,如回调机制;2) 逻辑运算符组合,实现复杂条件判断;3) 宏定义简化逻辑;4) 结构体与联合体组织复杂数据;5) 递归与分治法处理树形结构;6) 状态机管理状态转换。通过这些方法,可以更高效地管理和实现复杂的逻辑判断,使代码更加清晰易懂。
253 88
|
1月前
|
C语言
【C语言】sizeof 关键字详解
`sizeof` 关键字在C语言中用于计算数据类型或变量在内存中占用的字节数。它是一个编译时操作符,对性能没有影响。`sizeof` 可以用于基本数据类型、数组、结构体、指针等,了解和正确使用 `sizeof` 对于内存管理和调试程序非常重要。
83 2
|
3月前
|
Serverless 编译器 C语言
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
|
5月前
|
存储 缓存 编译器
【C语言篇】scanf和printf万字超详细介绍(基本加拓展用法)(下篇)
scanf处理⽤⼾输⼊的原理是,⽤⼾的输⼊先放⼊缓存,等到按下回⻋键后,按照占位符对缓存进⾏解读。 解读⽤⼾输⼊时,会从上⼀次解读遗留的第⼀个字符开始,直到读完缓存,或者遇到第⼀个不符合条件的字符为⽌。
212 2
|
5月前
|
存储 C语言
【C语言篇】scanf和printf万字超详细介绍(基本加拓展用法)(上篇)
printf 的作⽤是将参数⽂本输出到屏幕。它名字⾥⾯的 f 代表 format (格式化),表⽰可以定制输出⽂本的格式。
103 1
|
7月前
|
存储 C语言
c语言scanf函数用法
c语言scanf函数用法
|
6月前
|
存储 C语言
C语言中static关键字的作用与用法解析
C语言中static关键字的作用与用法解析
|
7月前
|
C语言
深入探索C语言中的sizeof关键字
深入探索C语言中的sizeof关键字
105 0
|
7月前
|
C语言
【C语言基础篇】字符串处理函数(一)strlen的介绍及模拟实现
【C语言基础篇】字符串处理函数(一)strlen的介绍及模拟实现

热门文章

最新文章