本次学习sizeof
与 strlen
的输出
前提知识:
- 有指针基础(学习过 指针数组、数组指针,函数指针)
- 有数组基础(对 一维数组 与 二维数组 的 传参有了解)
这次学习有个非常非常非常重要的知识点,贯彻了整篇文章,请大家务必要牢记
大家都知道,数组名 是首元素的地址
但是有两个例外:
sizeof(数组名)
,这里的数组名是表示整个数组的,计算的是整个数组的大小,单位是字节。
&数组名
,这里的数组名也表示整个数组,取出的是数组的地址
一定要牢记这两个例外
开始我们的练习,大家可以先不看我的注释,自己分析一下输出结果是多少。
指针(地址)的大小是根据系统来定义的
32位(x86)的机器 指针大小为4个字节
64位(x64)的机器 指针大小为8个字节
第一轮 数组1
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a)); //16 在sizeof中,单独存放一个数组名,表示整个数组的地址,所以得到的是整个数组的字节
printf("%d\n", sizeof(a + 0)); //4 or 8 这里的a不是单独存放了,所以a示首元素的地址,a+0还是首元素的地址的
printf("%d\n", sizeof(*a)); //4 a表示首元素地址,*a是对首元素地址的解引用,也就是首元素
printf("%d\n", sizeof(a + 1)); //4 or 8 表示第二个元素的地址,这里的a不是单独存放了,所以a示首元素的地址,+1后就是第二个元素的地址
printf("%d\n", sizeof(a[1])); //4 数组下标索引1,得到第二个元素
printf("%d\n", sizeof(&a)); //4 or 8 表示是数组的地址,数组的地址也是地址,地址大小就是 4 or 8
printf("%d\n", sizeof(*&a)); //16 1.可以理解为*和&相互抵消,*&a相当于a,所以sizeof(a) = 16;
//2.&a是数组的地址,它的类型是int (*)[4] 数组指针,如果解引用,访问的就是4个int的数组,大小是16byte。
printf("%d\n", sizeof(&a + 1)); //4 or 8 &a是整个数组的地址,&a+1后跳过整个数组,虽然已经不是数组内的地址了,但越界的地址也是地址,地址也是4 or 8
printf("%d\n", sizeof(&a[0])); //8 &a[0]取出的就是第一个元素的地址
printf("%d\n", sizeof(&a[0] + 1));//4 &a[0]+1 就是第二个元素的地址,地址大小就是4 or 8 byte
return 0;
}
以上就是第一轮的分析,掌握了在进入下一轮
第二轮 数组2
本轮含有 strlen
求取字符串长度
再次普及一下:
strlen
只能计算出 字符串 的长度,单位是byte,当strlen
在字符串中找到'\0'
后计算结束,计算的是'\0'
之前出现了多少个字符,'0'
是字符串的结束标志。需要导入头文件 :string.h
sizeof
可以计算所有类型的长度,单位也是byte,但是sizeof
在计算字符串时,会把'\0'
也当作一个字符
这次着重看strlen
,所以请掌握了第一轮的知识在进入下一轮。
#include <stdio.h>
#include <string.h)
int main()
{
char arr[] = { 'a','b','c','d','e','f' };//注意!!这个数组中的,都是字符,但并不包括 '\0'
printf("%d\n", sizeof(arr)); //6
printf("%d\n", sizeof(arr + 0)); //4/8 首元素地址
printf("%d\n", sizeof(*arr)); //4/8 首元素
printf("%d\n", sizeof(arr[1])); //4 第二个元素
printf("%d\n", sizeof(&arr)); //4/8 数组的地址
printf("%d\n", sizeof(&arr + 1)); //4/8 跳过整个数组的地址
printf("%d\n", sizeof(&arr[0] + 1));//4/8 第二个元素的地址
printf("%d\n", strlen(arr)); //随机值; arr是首元素的地址。但是arr数组中没有'\0',而strlen要找到‘0’后才会停止。结果:随机值,strlen函数关注的是'\0'这个结束符,因为没有 '\0' 这个字符串结束字符
printf("%d\n", strlen(arr + 0)); //随机值; arr是首元素的地址,arr+0还是首元素的地址,结果是:随机值
printf("%d\n", strlen(*arr)); //error,编译不过; strlen需要的是一个地址,从这个地址向后找'\0',统计字符个数,但是*arr表示数组的首元素,也就是‘a’,这时传个strlen的就是‘a’的ascii码值97,就会把97作为起始位置,统计字符串,就会形成内存访问冲突
printf("%d\n", strlen(arr[1])); //error,通上一个一样
printf("%d\n", strlen(&arr)); //随机值: &arr是 arr数组的地址,虽然类型有所差异,但是传参过去后,还是从第一个字符的位置向后数字符,结果还是随机值。
printf("%d\n", strlen(&arr + 1)); //随机值
printf("%d\n", strlen(&arr[0] + 1));//随机值
return 0;
}
本轮的难点在于strlen
这个库函数能接收数值吗?答案是:不能,传入数值得话会形成内存访问冲突。
还有就是strlen
没哟找到 '\0'
时会怎样,答案:直到在内存中找到'\0'
为止,而我们不知道什么时候会出现,所以它是一个随机值。
第三轮 数组3
第三轮只是第二轮的一些衍生,所以难度并不是很大,但也要谨慎看待
从这轮开始,简单的一些题我就直接在后面注释结果了
#include <string.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr)); // 7 sizeof的计算会包括 '\0'
printf("%d\n", sizeof(arr + 0)); // 4/8
printf("%d\n", sizeof(*arr)); // 1
printf("%d\n", sizeof(arr[1])); // 1
printf("%d\n", sizeof(&arr)); //4/8
printf("%d\n", sizeof(&arr + 1)); // 4/8
printf("%d\n", sizeof(&arr[0] + 1));// 4/8
printf("%d\n", strlen(arr)); // 6
printf("%d\n", strlen(arr + 0)); // 6
printf("%d\n", strlen(*arr)); // err
printf("%d\n", strlen(arr[1])); // err
printf("%d\n", strlen(&arr)); // 6
printf("%d\n", strlen(&arr + 1)); // 随机
printf("%d\n", strlen(&arr[0] + 1));// 5 从第二个元素开始计算,所以得到5
return 0;
}
第四轮 指针
之前的是数组的,这组是指针的,虽然指针的和数组的大同小异,但也还是有细微的差别
#include <string.h>
#include <stdio.h>
int main()
{
char* p = "abcdef";
printf("%d\n", sizeof(p)); // 4/8 p是地址
printf("%d\n", sizeof(p + 1)); // 4/8 p+1还是地址
printf("%d\n", sizeof(*p)); // 1 解引用访问到字符‘a’
printf("%d\n", sizeof(p[0])); // 1 下标访问第一个元素,'a'
printf("%d\n", sizeof(&p)); // 4/8 将p指向的字符指针数组,整个&, 但也还是地址。
printf("%d\n", sizeof(&p + 1)); // 4/8 跳过整个字符串后的地址还是地址;&p+1,就是跳过p指针在内存中指向的所有内容的地址。
printf("%d\n", sizeof(&p[0] + 1)); // 4/8 第二个元素的地址
printf("%d\n", strlen(p)); // 6 从我们传入的这个地址,找到'\0'为止,我们传入的是第一个地址
printf("%d\n", strlen(p + 1)); // 5 我们传入的是第二个地址,找到'\0'为止
printf("%d\n", strlen(*p)); // error 不能在strlen中传入数值,会造成内存冲突
printf("%d\n", strlen(p[0])); // error 同上
printf("%d\n", strlen((&p))); // 随机 存入的是p指向的字符指针数组,会以它为第一个地址,但是之后的在哪里出现'\0',我们不得而知
printf("%d\n", strlen((&p+1))); //随机 同上,加一以后不过是跳过了p这个指针指向的字符串,但是之后的在哪里出现'\0',我们也不知道
printf("%d\n", strlen((&p[0] + 1)));// 5 从第二个元素的地址找'\0'.
return 0;
}
第五轮 二维数组的sizeof
最终之轮~~(最难一轮)~~,加油!!欧力给
本轮是二维数组的sizeof
计算,
科普:
在二维数组中,数组名表示第一行的地址,在
sizeof(数组名)和 &(数组名)
中例外在二维数组中,a[0]表示,第一行的数组名,在
sizeof
中计算的也就是第一行的数组大小,以此类推。
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a)); // 48 数组名单独放在sizeof内部,计算的是整个数组的大小
printf("%d\n", sizeof(a[0][0])); // 4 计算的是第一行,第一个元素的大小
printf("%d\n", sizeof(a[0])); // 16 a[0]表示第一行的数组名。a[0]作为数组名放在sizeof内部,计算的是数组的第一行的大小
printf("%d\n", sizeof(a[0] + 1)); // 4/8 a[0]作为第一行的数组名,没有&,没有单独放在sizeof内部,所以a[0]表示的就是首元素的地址也就是a[0][0],+1就是表示访问第一行的第二个地址;
printf("%d\n", sizeof(*(a[0] + 1)));// 4 访问到第二个元素
printf("%d\n", sizeof(a + 1)); // 4/8 a是第一行的地址,+1后就是第二行的地址
printf("%d\n", sizeof(*(a + 1))); // 16 *(a+1)就是第二行,相当于第二行数组名,*(a+1) ==a[1];
printf("%d\n", sizeof(&a[0] + 1)); //4/8 a[0]是第一行的地址,&a[0]就是第一行的地址,&a[0]+1 就是第二行的地址
printf("%d\n", sizeof(*(&a[0] + 1)));//16 &a[0]+1是第二行的地址,解引用后就是 a[1];
printf("%d\n", sizeof(*a)); // 16 a二维数组的数组名,a表示首元素的地址,也就是第一行
printf("%d\n", sizeof(a[3])); // 16 感觉a[3]越界了,但是没关系,编译器它会根据数组来推断
return 0;
}
第五轮的二维数组是最绕的,同志们学习的时候,可以多看几遍
本次分享到此结束
若有错误欢迎批评指正,在下感激不尽,愿你我都能在编程的道路上越走越远!!!!