sizeof 和 strlen 这两者易混淆,常常让我们不能很容易地分清楚在不同情况下使用所输出的不同结果,我希望通过一些例子能够解释清楚这两者的区别。
首先,我们应该知道:1. 内存中的一个内存单元(字节)对应一个地址。
2. 在32位平台上指针的大小是4个字节,64位平台上是8个字节。
3. 数组在内存中是连续存放的,访问是通过下标的方式,下标从0开始。
其次,数组名代表整个数组的时候只有两种情况:1. sizeof(数组名),这里的数组名表示整个数组。
2. &数组名,这里的数组名表示整个数组。
除过这两种情况,其余的数组名均代表数组首元素的地址。
下面我们分情况讨论一下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<windows.h>
int main()
{
//一维数组
int a[] = { 1, 2, 3, 4 }; // 整形数组,四个元素,一个元素占四个字节
printf("%d\n", sizeof(a)); //16 数组名单独存放,表示整个数组的大小,4*4=16
printf("%d\n", sizeof(a + 0)); //4 数组首元素的地址,4
printf("%d\n", sizeof(*a)); //4 * 解引用,对a的首元素地址解引用还是首元素,4
printf("%d\n", sizeof(a + 1)); //4 首元素的地址+1,到第二个元素的地址,4
printf("%d\n", sizeof(a[1])); //4 数组用下标访问,第二个元素,4
printf("%d\n", sizeof(*&a)); //16 对数组的地址解引用表示整个数组的元素,整个数组元素的大小为16
printf("%d\n", sizeof(&a)); //4 对整个数组取地址,4
printf("%d\n", sizeof(&a + 1)); //4 数组地址+1,跳出此数组到下一个地址空间,4
printf("%d\n", sizeof(&a[0])); //4 对首元素取地址,4
printf("%d\n", sizeof(&a[0] + 1)); //4 首元素取地址后+1,跳到第二个元素的地址,4
//字符数组
char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' }; // 字符数组,六个元素,一个元素占一个字节
printf("%d\n", sizeof(arr)); //6 数组名单独存放,表示整个数组的大小,6
printf("%d\n", sizeof(arr + 0)); //4 数组首元素的地址,4
printf("%d\n", sizeof(*arr)); //1 * 解引用,对arr的首元素地址解引用还是首元素a,1
printf("%d\n", sizeof(arr[1])); //1 数组用下标访问,第二个元素,1
printf("%d\n", sizeof(&arr)); //4 对整个数组取地址,4
printf("%d\n", sizeof(&arr + 1)); //4 数组地址+1,跳出此数组到下一个地址空间,4
printf("%d\n", sizeof(&arr[0] + 1)); //4 首元素取地址后+1,跳到第二个元素的地址,4
printf("%d\n", strlen(arr)); //x 从'a'开始找,遇到\0结束,为随机数x
printf("%d\n", strlen(arr + 0)); //x 从'a'开始找,遇到\0结束,为随机数x
//printf("%d\n", strlen(*arr)); //语法错误 对arr的首元素地址解引用还是首元素a,也是97,求97的长度是不合法的
//printf("%d\n", strlen(arr[1])); //语法错误 第二个元素b,也是98,求98的长度是不合法的
printf("%d\n", strlen(&arr)); //x 整个数组的地址,一直寻找,直到遇到\0,为随机数
printf("%d\n", strlen(&arr + 1)); //x 数组地址+1,跳出此数组到下一个地址空间,直到遇到\0,为随机数x
printf("%d\n", strlen(&arr[0] + 1)); //x 首元素取地址后+1,跳到第二个元素的地址,直到遇到\0,为随机数x
可以看到后两个运行结果是随机值,然后程序到语法错误处崩溃,错误原因 0x00000061 是数字97。
屏蔽掉语法错误的两行程序,再次运行,显示结果如下:
此时可以发现运行结果和我们猜想的是吻合的,后五个都是随机值。
char arr[] = "abcdef"; // 字符数组,七个元素(abcdef\0),一个元素占一个字节
printf("%d\n", sizeof(arr)); //7 数组名单独存放,表示整个数组的大小,7
printf("%d\n", sizeof(arr + 0)); //4 数组首元素的地址,4
printf("%d\n", sizeof(*arr)); //1 * 解引用,对arr的首元素地址解引用还是首元素a,1
printf("%d\n", sizeof(arr[1])); //1 数组用下标访问,第二个元素,1
printf("%d\n", sizeof(&arr)); //4 对整个数组取地址,4
printf("%d\n", sizeof(&arr + 1)); //4 数组地址+1,跳出此数组到下一个地址空间,4
printf("%d\n", sizeof(&arr[0] + 1)); //4 首元素取地址后+1,跳到第二个元素的地址,4
printf("%d\n", strlen(arr)); //6 从'a'开始找,遇到\0结束,6
printf("%d\n", strlen(arr + 0)); //6 从'a'开始找,遇到\0结束,6
printf("%d\n", strlen(&arr)); //6 整个数组的地址, 从'a'开始找,遇到\0结束,6
printf("%d\n", strlen(&arr + 1)); //x 数组地址+1,跳出此数组到下一个地址空间,直到遇到\0,为随机数x
printf("%d\n", strlen(&arr[0] + 1)); //5 首元素取地址后+1,跳到第二个元素的地址,直到遇到\0,5
char *p = "abcdef"; // 字符指针,七个元素(abcdef\0),一个元素占一个字节
printf("%d\n", sizeof(p)); //4 p中存放的是a的地址,4
printf("%d\n", sizeof(p + 1)); //4 p+1指向b的地址,4
printf("%d\n", sizeof(*p)); //1 * 解引用,对p的首元素地址解引用还是首元素a,1
printf("%d\n", sizeof(p[0])); //1 首元素a,1
printf("%d\n", sizeof(&p)); //4 &p相当于**p,是二级指针,4
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 从a开始找,遇到\0结束,6
printf("%d\n", strlen(p + 1)); //5 从b开始找,遇到\0结束,6
printf("%d\n", strlen(*p)); //语法错误 对p的首元素地址解引用还是首元素a,也是97,求97的长度是不合法的
printf("%d\n", strlen(p[0])); //语法错误 首元素a,也是97,求97的长度是不合法的
printf("%d\n", strlen(&p)); //x &p相当于**p,二级指针,遇到\0结束,为随机数x
printf("%d\n", strlen(&p + 1)); //x +1跳出当前指针,指向下一个指针,遇到\0结束,为随机数x
printf("%d\n", strlen(&p[0] + 1)); //5 首元素地址+1,跳到下一地址b,遇到\0结束,5
可以看到程序到语法错误处崩溃,错误原因 0x00000061 是数字97。
屏蔽掉语法错误的两行程序,再次运行,显示结果如下:
int a[3][4] = { 0 }; // 整形数组,12个元素,一个元素占四个字节
printf("%d\n", sizeof(a)); //48 数组名单独存放,表示整个数组的大小,3*4*4=48
printf("%d\n", sizeof(a[0][0])); //4 第一行第一列首元素的地址,4
printf("%d\n", sizeof(a[0])); //16 第一行的地址,看作一维数组,4*4=16
printf("%d\n", sizeof(a[0] + 1)); //4 首元素地址+1,到第二个元素的地址,4
printf("%d\n", sizeof(a + 1)); //4 地址+1,到下一个元素的地址,4
printf("%d\n", sizeof(&a[0] + 1)); //4 对第一行取地址后+1,指向下一个地址,4
printf("%d\n", sizeof(*a)); //16 * 解引用,看作一维数组,对a的第一行地址解引用还是第一行的元素,4*4=16
printf("%d\n", sizeof(*&a)); //48 *&a相当于a,对数组的地址解引用表示整个数组的元素,整个数组元素的大小为48
printf("%d\n", sizeof(a[3])); //16 第四行的地址,虽然超出了数组范围,但为下个数组的第一行的地址,4*4=16
system("pause");
return 0;
}
以上就是我关于 sizeof 和 strlen 的验证,下面我们总结下这两者的用法区别:
sizeof :对指针,sizeof 返回这个指针所占的空间,大小为四个字节;对数组, sizeof 返回这个数组所占的空间。
strlen:不论数组或是指针,读到 \0 就结束,而且 \0 不计入字符串的长度。