当前位置: 首页 > news >正文

C语言内存机制深度解析:指针运算、数组与字符串实战指南

一、sizeof与strlen对比

1.1 sizeof

sizeof是一个操作符,绝对不是函数,如果操作数是变量,则计算变量所占内存空间的大小,如果操作数是类型,则计算使用该类型创建变量所占内存空间的大小
sizeof只关注占内存空间的大小,不在乎内存中存放的是什么数据

  • sizeof里的表达式不会运算
    表达式是在产生.exe可执行程序时双击运行时才会运行表达式,而sizeof运算是在编译时就计算好了,编译完以后表达式就没在代码里面了,自然就不会算表达式

1.2 strlen

是一个库函数,只针对字符串,求字符串的长度,把首地址的地址传给函数,统计\0之前的个数
三种写法:

错误写法:

1.3 sizeof与strlen对比

二、sizeof练习

2.1 整形数组

已知:int arr[]={1,2,3,4}

sizeof(arr+0)的结果

计算机假设计算arr+0运行,算出结果的类型,但是实际并不会进行真正的运算,arr没有单独与sizeof结合,arr就是首元素的地址,arr+0还是首元素的地址,sizeof(arr+0)的结果就是4/8

sizeof(&arr)的结果

&arr也是数组的地址,数组的地址也是地址,sizeof计算出来为4/8

sieof(*&a)的结果

  • 方法1:*与&相抵消,就是sizeof(arr)也就是整个数组的大小
  • 方法2:&arr取出的是数组的地址,类型是int(*)[4],对数组指针解引用,而旁边直接有sizeof,所以访问的是一个数组,也就是一个数组的大小

sizeof(&arr+1)

&arr+1没有访问内存空间,是跳过这个数组后那个位置的地址,是地址就是4/8

2.2 字符数组

已知: char arr[] = { 'a','b','c','d','e','f' };

sizeof(arr)的结果

arr与sizeof()结合求整个数组的大小

sizeof(arr+0)的结果

arr就是首元素的地址,arr+0还是首元素的地址,sizeof(arr+0)的结果就是4/8

sizeof(&arr)的结果

&arr为整个数组的地址,类型是int (*)[6]

sizeof(&arr[0]+1)的结果

&arr[0]为第一个元素的地址,&arr[0]+1为第二个元素的地址

2.3 存字符串数组

  • 存到数组中
    已知: char arr[] = "abcdef";

sizeof(arr)的结果

arr是数组名,单独放在sizeof()内部,计算的是数组总大小,加上\0有7个

sizeof(arr+0)的结果

arr表示数组首元素的地址,arr+0还是首元素的地址,是地址就是4/8

  • 还有一种也是字符串,但是放到指针类型
    const char *p="abcdef"

printf("%d",sizeof(p))的结果

p是指针变量,我们计算的是指针变量的大小,4/8个字节

printf("%d",sizeof(p+1))的结果

p+1是b的地址,是地址大小就是4/8个字节

printf("%d",sizeof(*p))的结果

*p的类型是const char*,*p就是char类型了,1个字节

printf("%d",sizeof(p[0]))的结果

理解方式:

  1. p[0]–>*(p+0)–>‘a’,大小是一个字节
  2. 把常量字符串想象成数组,p可以理解为数组名,p[0],就是首元素

printf("%d",sizeof(&p))的结果

p是个指针变量,&p去的是p空间的地址,与"abcdef"没关系,结果为4/8

printf("%d",sizeof(&p+1))的结果

跳过char*类型的地址,也是地址

2.4 二维数组

已知:int arr[3][4] = { 0 };

printf("%d", sizeof(arr))的结果

arr单独与sizeof结合,计算的是整个数组的大小,结果为3* 4 *4等于48

printf("%d", sizeof(arr[0]))的结果

a[0]第一行的数组名,数组名单独放在sizeof内部了,计算的是数组的总大小16个
理解方式:

printf("%d", sizeof(arr[0]+1))的结果

arr[0]没有单独放在sizeof()内部,所以arr[0]就是首元素的地址,就是arr[0][0],+1后变成arr[0][1]的地址,结果为4/8

printf("%d", sizeof(*(arr[0] + 1)))的结果

(arr[0] + 1)代表的是第二个元素的地址,*(arr[0] + 1)指的是第二个元素

printf("%d", sizeof(arr + 1))的结果

arr没有放在sizeof内部,arr表示二维数组的首地址,也就是一维数组的地址(第一行的地址),+1就是第二行的地址,a+1是数组指针,结果是4/8

printf("%d", sizeof(*(arr + 1)))的结果

理解方式:

  1. (arr+1)是第二行的地址,数组指针解引用,访问的是第二行,*(arr+1)计算的是第二行的大小
  2. *(arr+1)==arr[1],arr[1]是第二行的数组名,相当于把第二行的数组名放在sizeof()里面,计算的是第二行的大小

printf("%d", sizeof(&arr[0] + 1))的结果

arr[0]是第一行的数组名,与sizeof结合,就是第一行的地址,arr[0]+1就是第二行的地址,是地址结果就是4/8

printf("%d", sizeof(*(&arr[0] + 1)))的结果

(&arr[0]+1)是第二行的地址,数组指针,解引用访问的是第二行,大小是16

printf("%d", sizeof(*arr))

arr是二维数组的首元素的地址,也就是第一行的地址,*arr就是第一行,计算的是第一行的大小
*a == *(a+0) == a[0]

sizeof(arr[3]), 会越界访问吗?

arr[3]无需存在,仅仅通过类型的推断就能算出长度,arr[3]是第四行的数组名,与sizeof()单独结合,计算的是第四行的大小,16个字节
注:sizeof不会真实访问空间,可以自己推断类型


总结:

三、strlen练习

3.1 字符数组

已知: char arr[] = { 'a','b','c','d','e','f' };

strlen(arr)的结果

首先分析arr既没与sizeof结合,也没与&结合,所以也是数组名表示首元素的地址,把首元素的地址传给strlen,从这个位置向后数,数到 \0就停下来统计个数,数组没有\0就会越界访问,结果为随机值

strlen(*arr)的结果

是首元素的地址,*arr是首元素,就是’a’,strlen这个函数接受的是地址,a的Ascill码值为97,拿到一个野指针97,97这个地址不允许我们访问,运行到这里程序会崩溃

sizeof(&arr)的结果

arr是数组的地址,起始位置是数组的第一个元素的位置,strlen也是从这开始的,结果为随机值

3.2 存字符串数组

  • 存到数组中
    已知: char arr[] = "abcdef";

strlen(*arr)

*arr为首元素,为’a’,Ascill码值为97,出错

strlen(&arr)

补充:strlen函数是char*类型的,而取地址数组是char * arr[6]的类型,会发生强制类型转换

&arr是数组的地址,也是从数组第一个元素开始向后找,结果是6

strlen(&arr+1)

跳过整个数组,结果为随机值

strlen(&arr[0]+1)

从第二个地址开始,结果为5

  • 还有一种也是字符串,但是放到指针类型
    已知:char* p = "abcdef";

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

p存放的是a的地址,从前往后数,到\0为止,结果为6

printf(“%d”, strlen(p+1));

p+1是b的地址,从前往后数,到\0为止,结果是5

printf(“%d”, strlen(*p));

*p是‘a’,Ascill码值是97,程序会报错

printf(“%d”, strlen(&p));


&p是指针变量p的地址,和字符串"abcdef"关系就不大了,/从p这个指针变量的起始位置开始向后数的,变量存放的地址是什么,不知道,所以答案是随机值

printf(“%d”, strlen(&p[0]+1));

从第二个地址向后数,结果为5

四、巩固指针

易错题分析

  • 指针加减
  • 逗号表达式与指针

  • 指针类型转换区别

  • 二维数组的理解
  • 字符串与指针
  • 指针综合:优先级、多级指针

++、–会把值改掉,[] (下标运算符不会改)
*得到里面的空间,会把里面的值改掉

http://www.dtcms.com/a/519680.html

相关文章:

  • 强化学习 深度学习 深度强化学习 有什么区别
  • 《FastAPI零基础入门与进阶实战》第23篇:mysql/HeidiSQL安装与利用HeidiSQL数据迁移
  • 可克达拉市建设局网站番禺厂家关键词优化
  • 注册公司在哪个网站系统微信crm系统如何添加
  • 深入 YOLOv5 数据增强:从 create_dataloader 到马赛克范围限定
  • 如果战国时候魏国,向西灭掉秦国为战略纵深,然后向东争夺天下 可行吗
  • Docker MailServer自建邮件服务器
  • 【CRC校验】CRC(循环冗余校验)算法介绍
  • SpringAI 内嵌模型 ONNX
  • 哪些平台制作网站硬件开发和软件开发
  • 网站设计功能编程网站有哪些
  • Volatility2在kali安装
  • Euler
  • 提示学习思想
  • 《图解技术体系》Wonderful talk AI ~~AI“Emerging”
  • k8s部署容器化应用-nginx2
  • 谈谈你对iOS的runtime和runloop的了解
  • Blender入门学习05 - 材质
  • 沂源网站网站页面设计图片素材
  • 做网站推广引流效果好吗黑料社2023
  • 抽水蓄能电站的最佳调度方案研究Matlab仿真
  • VTK入门:vtkPolyData——3D几何的“乐高积木盒
  • php网站做退出的代码wordpress添加字体颜色
  • 2025年--Lc208- 415. 字符串相加(双指针)--Java版
  • ELK 日志管理系统相关内容总结
  • 如何使用 Ansible 安装 Docker
  • 图片批量压缩工具,快速减小文件体积
  • 安卓 ContentProvider 详解:跨应用数据共享的核心方案
  • 光速不变性的几何本源:论张祥前统一场论中光速的绝对性与表观变异
  • 微算法科技(NASDAQ MLGO)基于区块链点阵加密算法的物联网轻量级方案:构建物联网安全基石