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

【C语言】指针和数组的内存使用详解

目录

一、sizeof操作符

二、一维数组的练习

三、字符数组的练习

四、字符串数组

五、指针指向字符串

六、二维数组


一、sizeof操作符

在深入学习指针和数组的内存使用详情前,我们需要深入了解一下sizeof操作符的使用

1.1 sizeof操作符是计算括号内最终结果的类型大小

                详细可看不才详细写的笔记:【C语言】基础操作符大全

int main() {
	int a = 0;
	int sz1 = sizeof(a);
	int sz2 = sizeof(int);

	printf("sz1 = %d\n", sz1);
	printf("sz2 = %d\n", sz2);

	return 0;
}

运行结果:

  • sz1计算的是a变量 占用空间的大小,得出的结果是4
  • sz2计算的是 int类型 占用空间的大小,得出的结果也是4

由此可以证明 sizeof 计算的就是 类型大小

1.2 sizeof操作符括号内如果是复杂表达式,sizeof计算的就是表达式最终的变量类型占用空间的大小

int main() {
	int a = 0;
	char b = 12;
	short c = 0;

	int sz1 = sizeof(short);
	int sz2 = sizeof(c = a + b);

	printf("sz1 = %d\n", sz1);
	printf("sz2 = %d\n", sz2);

	return 0;
}

 运行结果:

  • 在sz2中,我们看表达式: c = a + b。在正常计算中,我们会涉及整形提升,a + b会提升成为4个字节运算,然后赋值给c,c也需要进行整形提升,提升到4个字节来接收,但是sizeof的结果还是占用2个字节,说明在复杂表达式中sizeof计算的就是表达式最终的变量类型占用空间的大小

sizeof操作符内不会进行运算赋值不管是多复杂或多简单的表达式sizeof内只会判断其最终类型占用空间大小后,返回结果

 举个栗子:

int main() {
	int a = 10;
	int b = 20;
	int c = 0;

	printf("%d\n", sizeof(c = a + b));
	printf("%d\n\n", c);

	printf("%d\n", sizeof(c = 123));
	printf("%d\n", c);

	return 0;
}

运行结果:

sizeof操作符具体实现方法是使用宏实现的,所以在编译阶段sizeof处理内容时,并不知道变量a、b等的值是什么,只会找到其最终变量判断这个变量类型占用空间多少个字节


二、一维数组的练习

int main() {
	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));

	return 0;
}

解析:

  1. 计算的是整个数组,大小为16
  2.  a+0其实是数组第一个元素的地址,是地址就是4/8字节,在指针笔记中有详细介绍
  3. *a是数组首元素,计算的是数组首元素的大小,单位是字节,结果:4
  4. a+1是第二个元素的地址,是地址大小就是4/8
  5. a[1]是第二个元素,计算的是第二个元素的大小-4-单位是字节
  6. &a是整个数组的地址,整个数组的地址也是地址,地址的大小就是4/8字节(&a--->类型:int(*)[4])
  7. &a是数组的地址,*&a就是拿到了数组,*&a-->a , a就是数组名,sizeof(*&a)-->sizeof(a),计算的是整个数组的大小,单位是字节-16 //计算的是整个数组的大小,单位是字节-16
  8. &.a是整个数组的地址,&a+1,跳过整个数组,指向数组后边的空间,是一个地址,大小是4/8字节
  9. &a[0]是首元素的地址,计算的是首元素地址的大小,4/8字节
  10. &a[0] + 1是第二个元素的地址,地址的大小就是4/8字节

三、字符数组的练习

int main() {

	char arr[] = { 'a','b','c','d','e','f' };
	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));

	return 0;
}

解析:

  1. arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节,结果是:6
  2. arr+0是数组首元素的地址,结果:4/8
  3. arr 是是首元素的地址,*arr是数组的首元素,首元素的大小1字节,结果:1
  4. 同上,结果:1
  5. &arr虽然是数组的地址,但还是地址。结果:4/8
  6. &arr + 1是跳过了整个数组后的地址。地址的大小依然是4/8。
  7. 第二个元素地址。 结果:4/8
int main() {

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

	return 0;
}
  1. strlen计算的是 '0' 前的有多少值。在上面数组arr中并未有 '\0' ,则strlen一直越界访问直到遇到 '\0' 后停止计算。结果为:随机值
  2. 同上。结果为:随机值
  3. 计算的是字符'a'的长度。'a'在ASCII码值中为97,此时strlen是把 97作为起始地址,而编号为97的地址是禁止访问的。所以结果是:报错。
  4. 同上。结果为:报错。
  5. 随机值
  6. 随机值
  7. 随机值

四、字符串数组

int main() {

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

	return 0;
}
  1.  计算的是数组的大小。单位是字节。结果为:7
  2. 计算的是地址的大小。arr+0是首元素的地址。结果为:4/8
  3. *arr是首元素。sizeof(*arr)计算首元素的大小。结果为:1
  4. arr[1]是第二个元素,计算的是第二个元素的大小。
  5. &arr虽然是数组的地址,但也是地址。结果为:4/8
  6. &arr+1虽然跳过了整个数组后的地址,但也是地址。结果为:4/8
  7. &arr[0] + 1第二个元素的地址。结果为:4/8
int main() {

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

	return 0;
}
  1. 计算字符串的总体长度,结果为:6。
  2. 同上
  3. 计算的是字符'a'的长度。'a'在ASCII码值中为97,此时strlen是把 97作为起始地址,而编号为97的地址是禁止访问的。所以结果是:报错。
  4. 同上
  5. &arr取出的是数组的地址,随着数组的地址开始计算直到 '\0'。结果为:6
  6. &arr + 1跳过的是整个数组,结果为:随机值。
  7. (&arr[0] + 1) ==> (&*(arr + 0) + 1) ==> (arr + 0) + 1 ==> arr + 1,跳过首元素, 从第二个元素开始计算,直到 '\0'。结果为:5。

五、指针指向字符串

int main() {

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

	return 0;
}
  1.  计算的是字符串长度,结果为:6。
  2. 从第二个元素开始计算字符串的长度,结果为:5。
  3. 计算的是字符'a'的长度。'a'在ASCII码值中为97,此时strlen是把 97作为起始地址,而编号为97的地址是禁止访问的。所以结果是:报错。
  4. 同上
  5. &p取出的是指针变量的地址。从指针变量的地址开始向后计算长度。结果为:随机值。
  6. 同上。
  7. (&arr[0] + 1) ==> (&*(arr + 0) + 1) ==> (arr + 0) + 1 ==> arr + 1,跳过首元素, 从第二个元素开始计算,直到 '\0'。结果为:5。
int main() {

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

	return 0;
}
  1. 计算的是指针变量p的大小。结果为:4/8
  2. p+1是字符b的地址。结果为:4/8
  3. *p就是字符串的第一个字符 'a'。结果为:1
  4. 同上
  5. 计算的是地址。结果为:4/8
  6. 计算的是地址。结果为:4/8
  7. 计算的是地址。结果为:4/8

六、二维数组

int main() {

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

	return 0;
}
  1.  计算的是整个二维数组的大小。结果为:48
  2. 计算的是第一个元素的大小。结果为:4
  3. a[0]相当于第一行做为一维数组的数组名,sizeof(arr[0])把数组名单独放在sizeof()内,计算的是第一行的大小。例如int a[] = {0}.sizeof(a)计算的是a数组的大小。
  4. a[0]是第一行数组名,数组名此时是首元素的地址。a[0]其实就是第一行第一个元素的地址,所以a[0] + 1就是第一行第二个元素地址。地址大小是4/8字节。
  5. (*(a[0] + 1))是第一行第二个元素,大小是4个字节。
  6. a是二维数组的数组名。没有sizeof(a),也没有&a,所以a是首元素地址,而把二维数组看成一维数组时,二维数组的首元素是它第一行。 a就是第一行首元素的地址。a+1这是第二行的地址。结果为:4
  7. sizeof(a[1])计算第二行的大小,单位是字节。 a是首元素地址,a+1是第二个元素的地址。结果为:4/8
  8. 计算的是第二行,大小单位是字节。结果为:16
  9. a是首元素地址也就是第一行的地址。*a就是第一行,sizeof(*a)就是计算第一行的大小。

以上就是本章所有内容。若有勘误请私信不才。万分感激💖💖 若有帮助不要吝啬点赞哟~~💖💖

ps:表情包来自网络,侵删🌹

若是看了这篇笔记彻底拿捏指针可以在评论区打出:小小指针!拿捏!😎


http://www.kler.cn/news/339210.html

相关文章:

  • IIOT工业物联网的标准与互操作性—SunIOT
  • Redis面试篇1
  • 计算机网络:物理层 —— 信道复用技术
  • 20.Nginx动静分离原理与案例实现
  • 极端天气道路目标检测数据集 3400张 带标注 VOC YOLO 6类
  • Javascript-标准内置对象-值属性-globalThis-Infinity-Nan-undefined 手写实现globalThis功能
  • java8 双冒号(::)使用方法
  • 解决方案:Pandas里面的loc跟iloc,有什么区别
  • VSCode调试Vue项目方法
  • 2024四大剪辑软件推荐及下载地址介绍!
  • 关键字:extern
  • 面试题:Redis(一)
  • 提升外贸营销效果,EDM策略与实践分享
  • Spring Boot读取resources目录下文件(打成jar可用),并放入Guava缓存
  • HJDQN环境配置
  • 栈_1(2024年10月08日)
  • 机器学习-支撑向量机SVM
  • 你要一直骑,骑到越来越远|VELO Senso TT坐垫,伴你大胆向前~
  • 老古董Lisp实用主义入门教程(12):白日梦先生的白日梦
  • 【SQL】DDL语句