在我们刷笔试题之前,我们首先要知道 sizeof 和 strlen 的区别,因为下面我们讲的笔试题和 sizeof , strlen 息息相关
sizeof是计算类型和变量的大小:
char ch[10] = "abcdef";
sizeof(ch); —— 这个计算的大小为10字节
strlen是计算字符串长度:
———— 当 strlen 读到字符 ’ \0 ’ 的时候不在往后面读
char ch[10] = "abcdef";
strlen(ch); —— 这个计算的大小为6
int a[] = {
1,2,3,4};
printf("1.—— %d\n",sizeof(a)); // —————————— 1
printf("2.—— %d\n",sizeof(a+0)); // —————————— 2
printf("3.—— %d\n",sizeof(*a)); // —————————— 3
printf("4.—— %d\n",sizeof(a+1)); // —————————— 4
printf("5.—— %d\n",sizeof(a[1])); // —————————— 5
printf("6.—— %d\n",sizeof(&a)); // —————————— 6
printf("7.—— %d\n",sizeof(*&a)); // —————————— 7
printf("8.—— %d\n",sizeof(&a+1)); // —————————— 8
printf("9.—— %d\n",sizeof(&a[0])); // —————————— 9
printf("10.—— %d\n",sizeof(&a[0]+1)); // —————————— 10
1. —— 16 a为首元素地址,单独放在了sizeof中,表示整个数组 —— 整个数组的大小为(4*4 = 16)字节
2. —— 4 a为首元素地址,(a+0)也是首元素地址,首元素地址没有单独放在sizeof中,表示首元素地址 —— 首
元素地址的大小为4或8字节
3. —— 4 a为首元素的地址,*a表示为首元素,首元素为int类型 —— 占4个字节
4. —— 4 a为首元素地址,(a+1)是第二个元素的地址 —— 第二个元素地址为4或8字节
5. —— 4 a[1]表示第二个元素 —— 占4字节
6. —— 4 &a表示整个数组的地址,整个数组的地址也是地址 —— 只要是地址就是4或8字节
7. —— 16 &a表示整个数组的地址,对整个数组解引用找到整个数组 —— 数组的大小为16字节
8. —— 4 &a表示整个数组的地址,(&a+1)表示数组 + 1 —— 只要是地址就是4或8字节
9. —— 4 a[0]表示首元素,&a[0]表示首元素地址 —— 地址为4或8字节
10.—— 4 &a[0]表示首元素地址,&a[0] + 1表示第二个元素地址 —— 地址为4或8字节
char arr[] = {
'a','b','c','d','e','f'};
printf("1.—— %d\n", sizeof(arr));
printf("2.—— %d\n", sizeof(arr+0));
printf("3.—— %d\n", sizeof(*arr));
printf("4.—— %d\n", sizeof(arr[1]));
printf("5.—— %d\n", sizeof(&arr));
printf("6.—— %d\n", sizeof(&arr+1));
printf("7.—— %d\n", sizeof(&arr[0]+1));
详细解析:
1 —— 6 arr单独放在sizeof中,表示整个数组,整个数组的大小为6个字节
2 —— 4/8 arr没有单独放在sizeof中,表示首元素的地址,首元素的地址大小为4或8个字节
3 —— 1 arr为首元素地址,对arr解引用,表示首元素,首元素是字符类型,占1个字节
4 —— 1 arr[1] 表示首元素,首元素是字符类型,占1个字节
5 —— 4/8 arr为首元素地址,&arr表示整个数组的地址,地址占4或8个字节
6 —— 4/8 &arr+1表示整个数组+1,虽然是野指针了,但是还是地址,占4或8字节
7 —— 4/8 arr[0]表示首元素,&arr[0]首元素地址,&arr[0]+1表示第二个元素的地址,占4或8字节
char arr[] = {
'a','b','c','d','e','f'};
printf("1.—— %d\n", strlen(arr));
printf("2.—— %d\n", strlen(arr+0));
printf("3.—— %d\n", strlen(*arr));
printf("4.—— %d\n", strlen(arr[1]));
printf("5.—— %d\n", strlen(&arr));
printf("6.—— %d\n", strlen(&arr+1));
printf("7.—— %d\n", strlen(&arr[0]+1));
详细解析:
1 —— 随机数 strlen是接收地址,然后找\0,arr为首元素地址,但是元素中没有\0,所以为随机值
2 —— 随机值 arr+0为首元素地址,数组中没有\0,所以为随机值
3 —— err *arr为a —— a的ASCII码值为97,所以以97位地址(野指针)向后找\0 —— 报错
4 —— err arr[1]为第二个元素b —— b的ASCII码值为98, —— 报错
5 —— 随机值 &arr是整个数组的地址,整个数组的地址和数组首元素的地址是相同的,arr数组中没有\0,所以为随机值
6 —— 随机值 &arr+1是整个数组+1,在数组外面没有办法确定\0什么时候出现,所以为随机值
7 —— 随机值 arr[0]首元素,&arr[0]首元素地址,&arr[0]+1第二个元素地址,不能确定\0什么时候出现,所以为随机值
char arr[] = "abcdef";
printf("1.—— %d\n", sizeof(arr));
printf("2.—— %d\n", sizeof(arr+0));
printf("3.—— %d\n", sizeof(*arr));
printf("4.—— %d\n", sizeof(arr[1]));
printf("5.—— %d\n", sizeof(&arr));
printf("6.—— %d\n", sizeof(&arr+1));
printf("7.—— %d\n", sizeof(&arr[0]+1));
详细解析:
1 —— 7 arr单独放在了sizeof中,arr表示整个数组,字符窜的末尾隐藏这\0,大小为7
2 —— 4/8 arr没有单独放在sizeof中,arr+0表示首元素地址,地址为4或8字节
3 —— 1 arr为首元素地址,*arr表示首元素,元素为char类型,大小为1字节
4 —— 1 arr[1]第二个元素, 大小为1字节
5 —— 4/8 &arr为整个数组的地址,地址大小为4或8字节
6 —— 4/8 &arr+1表示整个数组+1的地址,地址大小为4或8个字节
7 —— 4/8 arr[0]首元素,&arr[0]首元素地址,&arr[0]+1第二个元素地址,地址大小为4或8字节
char arr[] = "abcdef";
printf("1.—— %d\n", strlen(arr));
printf("2.—— %d\n", strlen(arr+0));
printf("3.—— %d\n", strlen(*arr));
printf("4.—— %d\n", strlen(arr[1]));
printf("5.—— %d\n", strlen(&arr));
printf("6.—— %d\n", strlen(&arr+1));
printf("7.—— %d\n", strlen(&arr[0]+1));
详细解析:
1 —— 6 arr为首元素地址,从首元素向后找\0,第七个元素为\0,所以计算字符个数为6
2 —— 6 arr+0为首元素地址,所以计算字符的个数为6
3 —— err *arr为首元素a,a的ASCII码值97,访问地址97为非法访问 —— 错误
4 —— err arr[1]为第二个元素b,b的ASCII码值为98,访问地址98为非法访问 —— 错误
5 —— 6 &arr表示整个数的地址,整个数组的地址和首元素的地址相同,所以计算字符个数为6
6 —— 随机值 &arr+1表示整个数组加+1,为野指针,不在数组中,所以不能确定\0的位置。
7 —— 5 arr[0]首元素,&arr[0]首元素地址,&arr[0]+1第二个元素地址,所以计算字符个数为5
char *p = "abcdef";
printf("1.—— %d\n", sizeof(p));
printf("2.—— %d\n", sizeof(p+1));
printf("3.—— %d\n", sizeof(*p));
printf("4.—— %d\n", sizeof(p[0]));
printf("5.—— %d\n", sizeof(&p));
printf("6.—— %d\n", sizeof(&p+1));
printf("7.—— %d\n", sizeof(&p[0]+1));
详细解析:
1 —— 4/8 p为指针,为第一个元素a的地址,指针占4或8个字节
2 —— 4/8 P+1为第二个元素的地址,指针占4或8个字节
3 —— 1 *p为第一个元素a,a占一个字节
4 —— 1 p[0]为第一个元素,占1个字节
5 —— 4/8 &p是对指针p取地址,只要是地址就是占4或8个字节
6 —— 4/8 &p+1是丢指针p的地址+1,地址占4或8字节
7 —— 4/8 p[0]是第一个元素a,&p[0]是对a取地址,&p[0]+1为b的地址,地址占4或8字节
char *p = "abcdef";
printf("1.—— %d\n", strlen(p));
printf("2.—— %d\n", strlen(p+1));
printf("3.—— %d\n", strlen(*p));
printf("4.—— %d\n", strlen(p[0]));
printf("5.—— %d\n", strlen(&p));
printf("6.—— %d\n", strlen(&p+1));
printf("7.—— %d\n", strlen(&p[0]+1));
详细解析:
1 —— 6 p为字符串的首元素地址,所以字符串的大小为6
2 —— 5 p+1为第二个元素b的地址,所以计算字符个数为5
3 —— err *p为第一元素a,a的ASCII的值为97,访问地址97为非法访问 —— err
4 —— err p[0]为第一个元素,—— err
5 —— 随机值 &p为指针p的地址,从指针p的地址然后开始向后找\0,\0的位置并不确定,所以为随机值
6 —— 随机值 &p+1为指针p的地址+1,从指针p+1的地址然后找\0,\0的位置无法确定,所以为随机值
7 —— 5 p[0]为元素a,&p[0]为元素a的地址,&p[0]+1为b的地址,所以计算的字符串大小为5
int a[3][4] = {
0};
printf("1.—— %d\n",sizeof(a));
printf("2.—— %d\n",sizeof(a[0][0]));
printf("3.—— %d\n",sizeof(a[0]));
printf("4.—— %d\n",sizeof(a[0]+1));
printf("5.—— %d\n",sizeof(*(a[0]+1)));
printf("6.—— %d\n",sizeof(a+1));
printf("7.—— %d\n",sizeof(*(a+1)));
printf("8.—— %d\n",sizeof(&a[0]+1));
printf("9.—— %d\n",sizeof(*(&a[0]+1)));
printf("10.—— %d\n",sizeof(*a));
printf("11.—— %d\n",sizeof(a[3]));
详细解析:
1.当我们计算二维数组的时候要把其中sizeof中的关系是化到最简,
如*(arr+1)= arr[1]
2.可以把arr的二维数看做是有几个一维数组组成的,arr[0]为第0行数组的地址,arr[1]为第一行的数组,依次类推。
1 —— 48 a为首元素地址,单独的放在了sizeof的内部,表示整个数组的大小为48
2 —— 4 arr[0][0]为首元素,大小为4
3 —— 16 arr[0]为二维数组第一行数组首的地址,单独放在了sizeof的内部,表示第一行的数组,大小为16
4 —— 4 arr[0]为第一行数组首元素地址,没有单独放在sizeof中,所以arr[0]+1表示第二个元素的地址,大小为4或8
5 —— 4 *(arr[0]+1)可以化简为arr[0][1],表示第一行第二个元素,大小为4
6 —— 4 a为首元素地址,没有单独放在sizeof中,a+1表示第一行第二个元素,大小为4
7 —— 16 *(arr+1)可以化简为arr[1],arr[1]为第二行首元素地址,单独放在sizeof中,表示第二行的地址,大小为16
8 —— 4 arr[0]表示为第一行的首元素地址,&arr[0]对首元素的地址取地址,&arr[0]+1对首元素的地址的地址+1,地址的大小为4或8
9 —— 16 &arr[0]+1对首元素的地址的地址+1,表示第二行首元素地址的地址,解引用,表示第二行首元素的地址,单独放在sizeof中,大小为16
10 —— 16 *a 等价与 *(a+0) 等价与a[0],arr[0],单独放在sizeof中,表示第一行的地址,大小为16
11 —— 16 arr[3]单独放在sizeof中,表示第四行数组的地址,虽然越界了,但大小还是为16