目录
数组名的意义:
1. sizeof(数组名),数组名表示整个数组,计算整个数组的大小。
2. &数组名,数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。
一维数组
int a[] = { 1,2,3,4 };
1. printf("%d\n", sizeof(a));
2. printf("%d\n", sizeof(a + 0));
3. printf("%d\n", sizeof(*a));
4. printf("%d\n", sizeof(a + 1));
5. printf("%d\n", sizeof(a[1]));
6. printf("%d\n", sizeof(&a));
7. printf("%d\n", sizeof(*&a));
8. printf("%d\n", sizeof(&a + 1));
9. printf("%d\n", sizeof(&a[0]));
10. printf("%d\n", sizeof(&a[0] + 1));
1.sizeof(数组名)表示整个数组的大小,答案为4*sizeof(int)=16
2.a没有单独放在括号中,则a表示首元素地址,地址大小为4/8(32位平台下地址4字节,64位平台下地址8字节)
3.a表示首元素地址,*a表示首元素,首元素为int类型,大小为4
4.同问题二,大小为4/8,a+1表示下标为2的地址
5.a[1]表示下标为1的元素,大小为4
6.&a表示整个数组的地址,地址大小为4/8
7.&a表示整个数组的地址,类型为int (* )[4],如果解引用,则访问4个int的数组,大小为16
8.&a+1表示地址,大小为4/8
9.&a[0]表示首元素地址,大小为4/8
10.&a[0]+1表示第二个元素的地址,大小为4/8
字符数组
char arr[] = { 'a','b','c','d','e','f' };
1. printf("%d\n", sizeof(arr));
2. printf("%d\n", sizeof(arr + 0));
3. printf("%d\n", sizeof(*arr));
4. printf("%d\n", sizeof(arr[1]));
5. printf("%d\n", sizeof(&arr));
6. printf("%d\n", sizeof(&arr + 1));
7. printf("%d\n", sizeof(&arr[0] + 1));
1.sizeof(数组名)表示整个数组的大小,答案为6*sizeof(char)=6
2.arr表示首元素地址,地址大小为4/8
3.*arr表示首元素,首元素为char类型,大小为1
4.arr[1]表示第二个元素,大小为1
5.&arr表示整个数组的地址,大小为4/8
6.&arr+1表示地址,大小为4/8
7.&arr[0]表示首元素地址,+1表示第二个元素的地址,大小为4/8
8. printf("%d\n", strlen(arr));
9. printf("%d\n", strlen(arr + 0));
10. printf("%d\n", strlen(*arr));
11. printf("%d\n", strlen(arr[1]));
12. printf("%d\n", strlen(&arr));
13. printf("%d\n", strlen(&arr + 1));
14. printf("%d\n", strlen(&arr[0] + 1));
8.arr表示首元素地址,但数组中没有'\0',strlen计算停止位置未知,结果是随机值
9.同8
10.*arr表示首元素,不是地址,程序无法运行
11.arr[1]表示第二个元素,程序无法运行
12.&arr表示整个数组的地址,类型为char (* ) [6],但strlen参数类型为char*,传入参数后按char*类型计算,结果仍是随机值
13.&arr+1表示整个数组之外的地址,仍是随机值
14.&arr[0]+1表示第二个元素的地址,结果仍是随机值
总结:
sizeof用来计算占用内存空间的大小
strlen用来计算字符串中\0为止,之前出现的字符的个数
char arr[] = "abcdef";
1. printf("%d\n", sizeof(arr));
2. printf("%d\n", sizeof(arr + 0));
3. printf("%d\n", sizeof(*arr));
4. printf("%d\n", sizeof(arr[1]));
5. printf("%d\n", sizeof(&arr));
6. printf("%d\n", sizeof(&arr + 1));
7. printf("%d\n", sizeof(&arr[0] + 1));
"abcdef"末尾有'\0',相当于char arr[] = { 'a','b','c','d','e','f','\0'};
1.sizeof(数组名)表示整个数组的大小,答案为7*sizeof(char)=7
2.arr+0表示首元素地址,大小为4/8
3.*arr表示首元素,首元素为char类型,大小为1
4.arr[1]表示第二个元素,大小为1
5.&arr表示整个数组的地址,大小为4/8
6.&arr+1仍然表示地址,大小为4/8
7.&arr[0]+1表示第二个元素的地址,大小为4/8
8. printf("%d\n", strlen(arr));
9. printf("%d\n", strlen(arr + 0));
10. printf("%d\n", strlen(*arr));
11. printf("%d\n", strlen(arr[1]));
12. printf("%d\n", strlen(&arr));
13. printf("%d\n", strlen(&arr + 1));
14. printf("%d\n", strlen(&arr[0] + 1));
8.arr表示首元素地址,数组中\0前有6个字符,答案为6
9.arr+0表示首元素地址,答案为6
10.*arr表示首元素,不是地址,程序无法运行
11.arr[1]表示第二个元素,程序无法运行
12.&arr表示整个数组的地址,类型为char (* ) [6],但strlen参数类型为char*,传入参数后按char*类型计算,结果为6
13.&arr+1表示整个数组之外的地址,结果为随机值
14.&arr[0]+1表示第二个元素的地址,结果为5
char* p = "abcdef";
1. printf("%d\n", sizeof(p));
2. printf("%d\n", sizeof(p + 1));
3. printf("%d\n", sizeof(*p));
4. printf("%d\n", sizeof(p[0]));
5. printf("%d\n", sizeof(&p));
6. printf("%d\n", sizeof(&p + 1));
7. printf("%d\n", sizeof(&p[0] + 1));
1.p为指针变量,大小为4/8
2.p+1表示第二个字符的地址,大小为4/8
3.*p表示一个char类型,大小为1
4.p[0]->*(p+0)->*p,大小为1
5.&p表示指针变量p所在的地址,大小为4/8
6.&p+1表示的仍是地址,大小为4/8
7.&p[0]+1->&*p+1->p+1,大小为4/8
8. printf("%d\n", strlen(p));
9. printf("%d\n", strlen(p + 1));
10. printf("%d\n", strlen(*p));
11. printf("%d\n", strlen(p[0]));
12. printf("%d\n", strlen(&p));
13. printf("%d\n", strlen(&p + 1));
14. printf("%d\n", strlen(&p[0] + 1));
8.p表示字符a的地址,直到\0前有6个字符,答案为6
9.p+1表示字符b的地址,直到\0前有5个字符,答案为5
10.*p不是地址,无法运行
11.p[0]不是地址,无法运行
12.&p是指针变量p的地址,不是数组中的元素地址,结果为随机值
13.同12,结果为随机值
14.&p[0]+1表示字符b的地址,答案为5
二维数组
int a[3][4] = { 0 };
1. printf("%d\n", sizeof(a));
2. printf("%d\n", sizeof(a[0][0]));
3. printf("%d\n", sizeof(a[0]));
4. printf("%d\n", sizeof(a[0] + 1));
5. printf("%d\n", sizeof(*(a[0] + 1)));
6. printf("%d\n", sizeof(a + 1));
7. printf("%d\n", sizeof(*(a + 1)));
8. printf("%d\n", sizeof(&a[0] + 1));
9. printf("%d\n", sizeof(*(&a[0] + 1)));
10. printf("%d\n", sizeof(*a));
11. printf("%d\n", sizeof(a[3]));
1.sizeof(数组名)表示整个数组的大小,答案为12*sizeof(int)=48
2.a[0][0]表示第一行第一个元素,大小为4
3.a[0]相当于第一行数组的数组名,答案为4*sizeof(int)=16
4.a[0]相当于第一行数组的数组名,数组名相当于首元素地址,a[0]表示第一个元素的地址,+1表示第一行第二个元素的地址,大小为4/8
5.*(a[0] + 1)->a[0][1],表示第一行第二个元素,大小为4
6.a代表第一行数组的地址,+1表示第二行数组的地址,大小为4/8
7.*(a + 1)->a[1]相当于第二行的数组名,答案为4*sizeof(int)=16
8.&a[0]+1->a+1,同6,大小为4/8
9.*(&a[0] + 1)->*(a+1)->a[1],表示第二行数组的数组名,答案为4*sizeof(int)=16
10.*a->a[0],同3,答案为4*sizeof(int)=16
11.a[3]表示第四行数组的数组名,答案为4*sizeof(int)=16
指针笔试题
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
&a+1表示元素5后面的地址,强制类型转换为int*赋给ptr。
*(a+1)表示第二个元素,为2。*(ptr-1)表示元素5。答案为2,5
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
0x开头代表16进制,20即0x14。
p+0x1->p+1,结构体类型指针变量加1跳过一个结构体,即0x100014
将p强制转换为unsigned long类型,加1就是加1,答案为0x100001
将p强制转换为unsigned int*,加1跳过一个整型,即0x100004
结果为0x100014 0x100001 0x100004
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;
}
&a+1表示整个数组后的地址,后转换为int*类型赋给ptr1。
(int)a+1,表示数组首元素地址转换为int类型然后加一,后转换为int*类型赋给ptr2。
ptr1[-1]->*(ptr1-1),表示数组最后一个元素4。
ptr2目前指向数组的第二个字节,根据小端存储,数组在内存中的存储方式为:01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00。解应用访问灰色部分的数据,答案为0x2000000
结果为0x4 0x2000000
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf("%d", p[0]);
return 0;
}
注意括号表达式,数组相当于int a[3][2] = { 1, 3, 5 };
a[0]代表数字1的地址,赋给p。p[0]->*p=1
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;
}
&p[4][2]->*(p+4)+2 ,p是数组指针,+1表示跳过4个int,*(p+4)相当于数组名,表示首元素地址,+1跳过1个int,最终&p[4][2]表示a[3][3]的地址,&p[4][2] - &a[4][2],由于是int*类型相减,答案表示两个地址间int变量的个数,又是小地址减大地址,所以答案为-4,以%p形式打印为FFFFFFFC。
最终答案FFFFFFFC,-4
数组a 元素地址 | 0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|---|
0 | p/a | p+1 | ||||
1 | p+2 | |||||
2 | p+3 | |||||
3 | p+4 | *(p+4)+2 | ||||
4 | &a[4][2] |
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;
}
&aa+1表示整个数组后面的地址,转换成int*类型赋给ptr1
*(aa+1)表示第二行数组首元素地址,赋给ptr2。
*(ptr1-1)表示最后一个元素10,*(ptr2-1)表示第一行最后一个元素5。
答案为10,5
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
a为指针数组的数组名,数组名代表首元素地址,赋给pa。
pa++,跳过一个char*,指向数组的第二个元素。
对pa解引用找到第二个元素,由于数组的每个元素都是char*类型,所以可以以%s形式打印,
结果为at
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;
}
cpp即cp,++cp指向元素c+2,解引用表示元素c+2,c+2指向元素"POINT"的首字母P的地址,再解引用即表示元素P的地址,为char*类型,以%s形式打印为POINT
由于上一条cpp已经自增一次,这里*++cpp表示元素c+1,--*++cpp表示c,c指向元素"ENTER"的首字母E的地址,解引用表示E的地址,+3指向第4个字母E,结果为ER
*cpp[-2]+3->**(cpp-2)+3,cpp-2回到cp数组的首元素地址,解引用表示首元素c+3,c+3指向元素"FIRST"的首字母F的地址,再解引用表示F的地址,+3指向S,结果为ST
cpp[-1][-1]+1->*(*(cpp-1)-1)+1,cpp-1回到cp数组的第二个元素地址,解引用表示元素c+2,然后-1表示c+1,c+1指向元素"NEW"的首字母N的地址,再解引用表示N的地址,+1则指向E,结果为EW