目录
一、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;
}
解析:
- 计算的是整个数组,大小为16
- a+0其实是数组第一个元素的地址,是地址就是4/8字节,在指针笔记中有详细介绍
- *a是数组首元素,计算的是数组首元素的大小,单位是字节,结果:4
- a+1是第二个元素的地址,是地址大小就是4/8
- a[1]是第二个元素,计算的是第二个元素的大小-4-单位是字节
- &a是整个数组的地址,整个数组的地址也是地址,地址的大小就是4/8字节(&a--->类型:int(*)[4])
- &a是数组的地址,*&a就是拿到了数组,*&a-->a , a就是数组名,sizeof(*&a)-->sizeof(a),计算的是整个数组的大小,单位是字节-16 //计算的是整个数组的大小,单位是字节-16
- &.a是整个数组的地址,&a+1,跳过整个数组,指向数组后边的空间,是一个地址,大小是4/8字节
- &a[0]是首元素的地址,计算的是首元素地址的大小,4/8字节
- &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;
}
解析:
- arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节,结果是:6
- arr+0是数组首元素的地址,结果:4/8
- arr 是是首元素的地址,*arr是数组的首元素,首元素的大小1字节,结果:1
- 同上,结果:1
- &arr虽然是数组的地址,但还是地址。结果:4/8
- &arr + 1是跳过了整个数组后的地址。地址的大小依然是4/8。
- 第二个元素地址。 结果: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;
}
- strlen计算的是 '0' 前的有多少值。在上面数组arr中并未有 '\0' ,则strlen一直越界访问直到遇到 '\0' 后停止计算。结果为:随机值
- 同上。结果为:随机值
- 计算的是字符'a'的长度。'a'在ASCII码值中为97,此时strlen是把 97作为起始地址,而编号为97的地址是禁止访问的。所以结果是:报错。
- 同上。结果为:报错。
- 随机值
- 随机值
- 随机值
四、字符串数组
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;
}
- 计算的是数组的大小。单位是字节。结果为:7
- 计算的是地址的大小。arr+0是首元素的地址。结果为:4/8
- *arr是首元素。sizeof(*arr)计算首元素的大小。结果为:1
- arr[1]是第二个元素,计算的是第二个元素的大小。
- &arr虽然是数组的地址,但也是地址。结果为:4/8
- &arr+1虽然跳过了整个数组后的地址,但也是地址。结果为:4/8
- &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;
}
- 计算字符串的总体长度,结果为:6。
- 同上
- 计算的是字符'a'的长度。'a'在ASCII码值中为97,此时strlen是把 97作为起始地址,而编号为97的地址是禁止访问的。所以结果是:报错。
- 同上
- &arr取出的是数组的地址,随着数组的地址开始计算直到 '\0'。结果为:6
- &arr + 1跳过的是整个数组,结果为:随机值。
- (&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;
}
- 计算的是字符串长度,结果为:6。
- 从第二个元素开始计算字符串的长度,结果为:5。
- 计算的是字符'a'的长度。'a'在ASCII码值中为97,此时strlen是把 97作为起始地址,而编号为97的地址是禁止访问的。所以结果是:报错。
- 同上
- &p取出的是指针变量的地址。从指针变量的地址开始向后计算长度。结果为:随机值。
- 同上。
- (&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;
}
- 计算的是指针变量p的大小。结果为:4/8
- p+1是字符b的地址。结果为:4/8
- *p就是字符串的第一个字符 'a'。结果为:1
- 同上
- 计算的是地址。结果为:4/8
- 计算的是地址。结果为:4/8
- 计算的是地址。结果为: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;
}
- 计算的是整个二维数组的大小。结果为:48
- 计算的是第一个元素的大小。结果为:4
- a[0]相当于第一行做为一维数组的数组名,sizeof(arr[0])把数组名单独放在sizeof()内,计算的是第一行的大小。例如int a[] = {0}.sizeof(a)计算的是a数组的大小。
- a[0]是第一行数组名,数组名此时是首元素的地址。a[0]其实就是第一行第一个元素的地址,所以a[0] + 1就是第一行第二个元素地址。地址大小是4/8字节。
- (*(a[0] + 1))是第一行第二个元素,大小是4个字节。
- a是二维数组的数组名。没有sizeof(a),也没有&a,所以a是首元素地址,而把二维数组看成一维数组时,二维数组的首元素是它第一行。 a就是第一行首元素的地址。a+1这是第二行的地址。结果为:4
- sizeof(a[1])计算第二行的大小,单位是字节。 a是首元素地址,a+1是第二个元素的地址。结果为:4/8
- 计算的是第二行,大小单位是字节。结果为:16
- a是首元素地址也就是第一行的地址。*a就是第一行,sizeof(*a)就是计算第一行的大小。
以上就是本章所有内容。若有勘误请私信不才。万分感激💖💖 若有帮助不要吝啬点赞哟~~💖💖
ps:表情包来自网络,侵删🌹
若是看了这篇笔记彻底拿捏指针可以在评论区打出:小小指针!拿捏!😎