sizeof()
我们在求一个数组的长度时,经常会用到这个”函数”,这看上去是一个求变量总字节的”函数”,其实别看它带着一个小括号,它和 int void const等一样是关键字.带上括号只是为了看上去更直观明了,而且有一个细节是括号里面的值不进行计算的,
例如
int a=3;
int b=2;
sizeof(a+b);
我们虽然知道sizeof在32位系统返回的是4.但是在不计算a+b括号怎么知道呢?我们要了解一个变量在内从空间中会开辟地址空间,然后在地址空间里存放数据.
sizeof在程序的编译期就已经确定,因为在编译期就可以确定变量开辟空间的大小,而空间里存放的数据要到运行期间才会确定.
a和b都是整型,所以在编译期间就会给a+b的结果开辟一片4字节大小的空间.
sizeof()和strlen()的练习
在开始之前要说明一点,当sizeof()括号中单独放数组名的时候,sizeof()求的是整个数组的字节大小.其他的情况出现数组名都表示指向首元素的指针.
Part 1
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));//16 整个数组的字长
printf("%d\n",sizeof(a+0));//4 第一个元素地址的字长
printf("%d\n",sizeof(*a)); //4 *a==*(a+0)==a[0] 第一个元素的字长
printf("%d\n",sizeof(a+1));//4 第二个元素的地址
printf("%d\n",sizeof(a[1]));//4 第二个元素地址字长
printf("%d\n",sizeof(&a)); //4 整个数组地址的字长(地址是4个字长)
printf("%d\n",sizeof(*&a)); //16 &a取整个数组地址的地址 然后*(&a)等于*p 表示里面所存的值, 所以是里面值的字长16
printf("%d\n",sizeof(&a+1));//4 跳过此数组后的地址的字长
printf("%d\n",sizeof(&a[0]));//4 第1个元素的地址字长
printf("%d\n",sizeof(&a[0]+1));//4 第二个元素的地址字长
通过上面的练习,我们可以总结到:
数组名广义上是一个指向首元素的指针
但在sizeof()中单独出现就代表所有的元素(注意这里就不代表指针了)
a[0]就等于 *a(把指针解引用)
&a[0]就等于a(指针指向a[0]的地址)
Part 2
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));//随机值 首元素地址往后数数组有\0才表示结束 这里不知道在哪结束
printf("%d\n", strlen(arr+0));//随机值
printf("%d\n", strlen(*arr));//err strlen(这里面传的是地址呀)
// *arr解引用后是一个值"a"的ASII(98) 98这个地址你是不能随便访问的
printf("%d\n", strlen(arr[1]));//err 同上不过换成b的ASII码
printf("%d\n", strlen(&arr));//随机值 这里是整个数组的地址,不过也是首个元素的地址
printf("%d\n", strlen(&arr+1));//随机值 从整个数组地址+1后的地址开始往后数
printf("%d\n", strlen(&arr[0]+1)); //随机值从第二个元素的地址开始往后数
printf("%d\n", sizeof(arr));//6 一个 char 1个字节 sizof(单独的数组名表示整个数组长度)
printf("%d\n", sizeof(arr+0));//4 a首元素的地址 4个字节
printf("%d\n", sizeof(*arr));//1 解引用 表示第一个元素'a' 长度是1
printf("%d\n", sizeof(arr[1]));//1 同上 不过是'b'
printf("%d\n", sizeof(&arr));//4 整个数组的地址 ,地址长度4个字节
printf("%d\n", sizeof(&arr+1));//4 整个数组的地址后面一个地址的 地址长度
printf("%d\n", sizeof(&arr[0]+1));//4 第二个元素地址的长度
通过上面练习,我们又可以发现
- strlen函数传参的参数是一个char*,也就是字符类型的指针
- strlen计算结束标志是表示是碰见’\0’(‘\0’不计入总长度)
- 地址变量占4个字节空间
Part 3
char arr[] = "abcdef";
printf("%d\n", strlen(arr));//6 //字符串默认后面有\0 表示首元素地址往后数
printf("%d\n", strlen(arr+0));//6 和上面一样 注意strlen 和size of的区别!!!
printf("%d\n", strlen(*arr));//err 错 不可能访问的内存地址
printf("%d\n", strlen(arr[1]));//err 错 同上
printf("%d\n", strlen(&arr));//6 整个元素的地址 其实也是第一个元素的地址 数到\0 刚好6个
printf("%d\n", strlen(&arr+1));//随机值 跳出数组地址了(也跳出了\0)
printf("%d\n", strlen(&arr[0]+1));//5 从第二个元素地址开始数 数到\0 5个
printf("%d\n", sizeof(arr));//7 全部字长字符串默认包含 \0
printf("%d\n", sizeof(arr+0));//4 首地址
printf("%d\n", sizeof(*arr));//1 'a'
printf("%d\n", sizeof(arr[1]));//1 ' b'
printf("%d\n", sizeof(&arr));//4 整个数组的地址 的地址字长
printf("%d\n", sizeof(&arr+1));//4 整个数组的地址下一个地址 的地址字长
printf("%d\n", sizeof(&arr[0]+1));//4 'b'的地址 的字长 4个
通过以上的练习,我们可以发现
- 如果把数组定义为 char a[]=”abcd” 数组已经包换’\0’了
- 数组的长度就是5(包换’\0’),用sizeof(a)/sizeof(a[0])求得
- 但用strlen求得字符串长度为4
Part 4
char *p = "abcdef";
printf("%d\n", sizeof(p));//4
// p是个指针,和地址字长一样是4个字节 区分sizeof(p) 和 sizeof(arr) 注意这个不是一个数组!!!! p指向第一个元素的首地址
printf("%d\n", sizeof(p+1));//4 同上 是第二个元素的地址
printf("%d\n", sizeof(*p));//1 解引用 不解释
printf("%d\n", sizeof(p[0]));//1 第一个元素字长
printf("%d\n", sizeof(&p));//4 地址的地址永远是4个字长 注意p里存的"值"是"一片地址" p里能存"值",那P也得有地址 &p就是p地址
printf("%d\n", sizeof(&p+1));//4 地址的地址+1还是4个字长
printf("%d\n", sizeof(&p[0]+1));//4 地址的地址+1还是4个字长
printf("%d\n", strlen(p)); // 6
printf("%d\n", strlen(p+1)); // 5
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));//同上 随机值??
通过以上练习发现 char *p和char *arr 大体上是相似的,不同的是
- sizeof(p) 此时p是指针,不是数组名,所以没有数组名单独出现在sizeof里面的特性
Part 4
int a[3][4] = {0};
/*printf("%p\n", &a[0][0]);
printf("%p\n", a[0]+1);*/
printf("%d\n",sizeof(a));//48 easy
printf("%d\n",sizeof(a[0][0]));//4 第零个元素字长
printf("%d\n",sizeof(a[0]));//16
//第1个数组元素字长 这里 a[0]表示二维数组的第一个元素 sizof(数组名) 总长
printf("%d\n",sizeof(a[0]+1));//4 这里是第一行第二个元素的字长
printf("%d\n",sizeof(a+1));//4 //第二个元素的字长
// 第二行的整个数组的地址 二维数组中 a表示首数组的地址
printf("%d\n",sizeof(&a[0]+1));//4 第二行的整个数组的地址 (第一行数组取地址加+)
printf("%d\n",sizeof(*a));// 16 二维数组的首地址是第一行数组的地址 *a表示对第一行进行解引用
printf("%d\n",sizeof(a[3]));//16 sizeof内部不进行运算,也就是不判断合法性.但知道其分配的地址空间大小
通过对第四部分练习可以发现二维数组中的元素类型是一维数组.
具体详解请见本人另一篇博客
原来二维数组内部隐藏着这样不为人知的秘密……
总结
- sizeof()是求的类型所占字节大小,所以很多关于地址和指针求字节大小,都是占4个字节,但是要明白是谁的地址.
- strlen函数的声明是 char* strlen(const char*str) 注意传进的形参类型是字符指针char *类型
- 区分char *p = “abcdef”和char arr[] = “abcdef”在sizeof()和strlen()上的差别