3. 二维数组和指针
3.1 例题
#include <stdio.h> 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; }
3.2 解析
#include <stdio.h> int main() { int a[3][4] = { 0 }; printf("%d\n", sizeof(a)); //结果:48字节 //解释:a是数组名,数组名单独放在sizeof内部,计算的是整个二维数组大小,所以sizeof(a)=4*3*4=48,单位是字节 printf("%d\n", sizeof(a[0][0])); //结果:4字节 //解释:a[0][0]得到的第一行第一列的元素,元素类型是int,所以sizeof(a[0][0])=sizeof(int)=4,单位是字节 printf("%d\n", sizeof(a[0])); //结果:16字节 //解释:a[0]表示二维数组的第一行,第一行是一个有四个元素的一维数组,在二维数组中a[0]就相当于一维数组名, // 数组名单独放在sizeof内部,计算的是整个一维数组的大小,a[0]类型是int [4],所以sizeof(a[0])=4*4=16,单位是字节 printf("%d\n", sizeof(a[0] + 1)); //结果:4/8字节 //解释:a[0]表示二维数组的第一行,,第一行是一个有四个元素的一维数组,在二维数组中a[0]就相当于一维数组名,并不是单独放在二维数组中,所以他就是一维数组首元素地址,地址就是指针, // 指针类型是int*,a[0]+1就是跳过一个int大小,得到a[0][1]的地址,地址就是指针,所以sizeof(a[0]+1)计算的是整个指针的大小,单位是字节 printf("%d\n", sizeof(*(a[0] + 1))); //结果:4字节 //解释:a[0]表示二维数组的第一行,,第一行是一个有四个元素的一维数组,在二维数组中a[0]就相当于一维数组名,并不是单独放在二维数组中,所以他就是一维数组首元素地址,地址就是指针, // 指针类型是int*,a[0]+1就是跳过一个int大小,得到a[0][1]的地址,地址就是指针,拿到a[0][1]这个元素,元素类型是int类型,所以sizeof(*(a[0]+1))=sizeof(int),单位是字节 printf("%d\n", sizeof(a + 1)); //结果:4/8字节 //解释:a是数组名,并没有单独放在sizeof内部,所以a是二维数组首行地址,地址就是指针,类型是int (*arr)[4],a+1跳过一个有4个int类型元素的数组,得到a[1], // 也就是二维数组第二行地址,地址就是指针,所以sizeof(a+1)计算的是指针大小 printf("%d\n", sizeof(*(a + 1))); //结果:16字节 //解释:a是数组名,并没有单独放在sizeof内部,所以a是二维数组首行地址,地址就是指针,类型是int (*arr)[4],a+1跳过一个有4个int类型元素的数组,得到a[1], // 也就是二维数组第二行地址,对其解引用得到的是二维数组中第二行一维数组,sizeof(*(a+1))=sizeof(a[1])=4*4=16,单位是字节 printf("%d\n", sizeof(&a[0] + 1)); //结果:4/8字节 //解释:a[0]表示二维数组的第一行,,第一行是一个有四个元素的一维数组,&a[0]得到的是二维数组的第一行整个数组的地址,地址就是指针,指针类型是int (*arr)[4],&a[0]+1跳过一个一维数组的大小, // 得到的就是二维数组中第二行整个一维数组的地址,地址就是指针,所以sizeof(&a[0]+1)计算的就是指针的大小 printf("%d\n", sizeof(*(&a[0] + 1))); //结果:16字节 //解释:a[0]表示二维数组的第一行,,第一行是一个有四个元素的一维数组,&a[0]得到的是二维数组的第一行整个数组的地址,地址就是指针,指针类型是int (*arr)[4],&a[0]+1跳过一个一维数组的大小, // 得到的就是二维数组中第二行整个一维数组的地址,*(&a[0]+1)得到的就是二维数组中的第二行一维数组,sizeof(*(&a[0] + 1))=sizeof(a[1])=4*4=16,单位是字节 printf("%d\n", sizeof(*a)); //结果:16字节 //解释:a是二维数组的数组名,数组名不没有单独放在sizeof内部,所以a是第一行的地址,地址就是指针,指针类型是int (*arr)[4], // *a得到的就是二维数组中的整个第一行一维数组,sizeof(*a)=sizeof(a[0])=4*4=16,单位是字节 printf("%d\n", sizeof(a[3])); //结果: 16字节 //解释:a[3]在二维数组中就相当于拿到下标为3的一整行一维数组,a[3]也就是第四行的一维数组名,数组名在sizeof内部,计算的是整个数组的大小, // 虽然没有数组没有第四行,但是可以给a[3]预分配一个空间,所以给a[3]预分配一个int [4]的空间,sizeof计算的只是类型的大小,这里a[3]的类型就是int [4],所以sizeof(a[3])=4*4=16,单位是字节 return 0; }
3.3 输出结果
3.3.1 32位平台
3.3.2 64位平台
4. 例题4.指针
4.1 例题
#include <stdio.h> int main() { int a[5] = { 1, 2, 3, 4, 5 }; int* ptr = (int*)(&a + 1); printf("%d,%d", *(a + 1), *(ptr - 1)); return 0; }
4.2 解析
5. 例题5.指针
5.1 例题
struct Test { int Num; char* pcName; short sDate; char cha[2]; short sBa[4]; }*p; //假设p 的值为0x100000。 如下表表达式的值分别为多少? //已知,结构体Test类型的变量大小是20个字节 int main() { p = (struct Test*)0x100000; printf("%p\n", p + 0x1); printf("%p\n", (unsigned long)p + 0x1); printf("%p\n", (unsigned int*)p + 0x1); return 0; }
5.2 解析
6. 例题6.指针
6.1 例题
#include <stdio.h> int main() { int a[4] = { 1, 2, 3, 4 }; int* ptr1 = (int*)(&a + 1); int* ptr2 = (int*)((int)a + 1); printf("%x,%x", ptr1[-1], *ptr2); return 0; }
6.2 解析
7. 例题7.指针
7.1 例题
#include <stdio.h> int main() { int a[3][2] = { (0, 1), (2, 3), (4, 5) }; int* p; p = a[0]; printf("%d", p[0]); return 0; }
7.2 解析
8. 例题8.指针
8.1 例题
#include <stdio.h> int main() { int a[5][5]; int(*p)[4]; p = a; printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]); return 0; }
8.2 解析
9. 例题9.指针
9.1 例题
#include <stdio.h> int main() { int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int* ptr1 = (int*)(&aa + 1); int* ptr2 = (int*)(*(aa + 1)); printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1)); return 0; }
9.2 解析
10. 例题10.指针
10.1 例题
#include <stdio.h> int main() { char* a[] = { "work","at","alibaba" }; char** pa = a; pa++; printf("%s\n", *pa); return 0; }
10.2 解析
11. 例题11.指针
11.1 例题
#include <stdio.h> int main() { char* c[] = { "ENTER","NEW","POINT","FIRST" }; char** cp[] = { c + 3,c + 2,c + 1,c }; char*** cpp = cp; printf("%s\n", **++cpp); printf("%s\n", *-- * ++cpp + 3); printf("%s\n", *cpp[-2] + 3); printf("%s\n", cpp[-1][-1] + 1); return 0; }
11.2 解析
![](https://ucc.alicdn.com/images/user-upload-01/img_convert/24baf958d698b0ac8197755d5762942d.png
12. 总结
sizeof计算大小的时候,首先关心计算对象,是一个变量还是一个数组名,还是什么,这里重点放在计算数组上,如果sizeof内部包含一个单独的数组名,说明这个sizeof计算的是整个数组的大小,否则不是,单位是字节,这个很重要,假如说sizeof(arr[2][2]),这个二维数组的类型是int,那么这个sizeof(arr[2][2])= 224=16,单位是字节。计算字符串数组的时候,sizeof(arr)计算包含’\0’的计算,'\0’也是占空间。
strlen计算的是’\0’之前的元素个数,在数组中,数组中不包含’\0’的话,一般这里就是随机值,另外注意strlen库函数再求一个字符解引用的时候会出现报错,原因就是非法访问。
&数组名,取的是整个数组的地址,&arr+1也是跳过整个数组的大小
对指针进行解引用的时候,要关注指针对应的元素类型,这决定了拿取多少个字节的空间,指针±操作的时候要关注类型,决定步长。