这里收录的是相关指针的练习,主要针对的是指针与sizeof之间的练习,练完你对指针的理解将更进一层喔
一维数组指针练习
一维数组相关练习,下面答案是多少呢,为什么呢?
int a[] = {1,2,3,4}; printf("%d\n",sizeof(a)); printf("%d\n",sizeof(a+0)); printf("%d\n",sizeof(*a)); printf("%d\n",sizeof(a+1)); printf("%d\n",sizeof(a[1])); printf("%d\n",sizeof(&a)); printf("%d\n",sizeof(*&a)); printf("%d\n",sizeof(&a+1)); printf("%d\n",sizeof(&a[0])); printf("%d\n",sizeof(&a[0]+1));
解析:
int main() { //一维数组 int a[] = { 1,2,3,4 }; printf("%d\n", sizeof(a)); //16 //a为数组名,但在sizeof(数组名)表示的计算整个数组的大小 printf("%d\n", sizeof(a + 0)); //4或8 //首元素地址 printf("%d\n", sizeof(*a)); //4 //首元素解引用--第一个元素1的大小为4字节 printf("%d\n", sizeof(a + 1)); //4或8 //第二个元素的地址 printf("%d\n", sizeof(a[1])); //4 //第二个元素2,4字节 printf("%d\n", sizeof(&a)); //4或8 //&数组名表示取出的是整个数组的地址,地址的大小就是4或8 printf("%d\n", sizeof(*&a)); //16 //*和&抵消还是a,sizeof(数组名)表示计算整个数组大小 printf("%d\n", sizeof(&a + 1)); //4或8 //&a取出的是整个地址大小,+1也是加上整个数组地址大小,但地址大小就是4或8 printf("%d\n", sizeof(&a[0])); //4或8 //a[0]就是 *(a+0)就是第一个元素,然后再取地址,就是首元素地址了 printf("%d\n", sizeof(&a[0] + 1)); //4或8 //第二个地址 return 0; }
答案:
字符数组指针练习
字符数组相关练习,下面答案是多少呢,为什么呢?
1.
char arr[] = { 'a','b','c','d','e','f' }; printf("%d\n", sizeof(arr)); printf("%d\n", sizeof(arr + 0)); printf("%d\n", sizeof(*arr)); printf("%d\n", sizeof(arr[1])); printf("%d\n", sizeof(&arr)); printf("%d\n", sizeof(&arr + 1)); printf("%d\n", sizeof(&arr[0] + 1)); printf("%d\n", strlen(arr)); printf("%d\n", strlen(arr + 0)); printf("%d\n", strlen(*arr)); printf("%d\n", strlen(arr[1])); printf("%d\n", strlen(&arr)); printf("%d\n", strlen(&arr + 1)); printf("%d\n", strlen(&arr[0] + 1));
解析:
int main() { char arr[] = { 'a','b','c','d','e','f' }; printf("%d\n", sizeof(arr)); //6 //sizeof(数组名)表示计算的是整个数组大小为6字节 printf("%d\n", sizeof(arr + 0)); //4或8 //这里arr+0表示首元素地址 printf("%d\n", sizeof(*arr)); //1 //这里的arr表示首元素地址,*arr表示第一个元素'a' printf("%d\n", sizeof(arr[1])); //1 //表示第二个元素'b' printf("%d\n", sizeof(&arr)); //4或8 //&arr表示取出的是整个数组地址,但还是地址 printf("%d\n", sizeof(&arr + 1)); //4或8 //&arr表示取出的整个数组大小,+1表示加上整个数组大小地址 printf("%d\n", sizeof(&arr[0] + 1)); //4或8 //第二个元素地址 printf("%d\n", strlen(arr)); //这里要注意strlen是专门用来计算字符大小的函数,遇到'\0'停止,而arr这个数组没有\0 //所以这个为随机值 printf("%d\n", strlen(arr + 0)); //无\0,所以为随机值 printf("%d\n", strlen(*arr)); //对首元素解引用,访问的是第一个元素,strlen('a')->strlen('97')---非法访问 //strlen()里面放的应该是一个地址,然后strlen跟着这个地址往后找,找到\0就停止了 //但这里strlen('a')里放的不是地址,而是97这个数,所以造成非法访问。 printf("%d\n", strlen(arr[1])); //第二个元素strlen('b')->strlen('97')---也是非法访问。 printf("%d\n", strlen(&arr)); //&arr表示取出的是整个数组地址,但不知道后面是否有\0,所以还是随机值 printf("%d\n", strlen(&arr + 1)); //这里的arr表示首元素地址,&首元素地址,取出一个地址,这个地址指向的是arr首元素地址,再+1呢,也不知道这个地址是啥了 //还是随机值 printf("%d\n", strlen(&arr[0] + 1)); //&arr[0]+1,第二个元素地址,后面无\0,为随机值。 return 0;
2.
char arr[] = "abcdef"; printf("%d\n", sizeof(arr)); printf("%d\n", sizeof(arr+0)); printf("%d\n", sizeof(*arr)); printf("%d\n", sizeof(arr[1])); printf("%d\n", sizeof(&arr)); printf("%d\n", sizeof(&arr+1)); printf("%d\n", sizeof(&arr[0]+1)); printf("%d\n", strlen(arr)); printf("%d\n", strlen(arr+0)); printf("%d\n", strlen(*arr)); printf("%d\n", strlen(arr[1])); printf("%d\n", strlen(&arr)); printf("%d\n", strlen(&arr+1)); printf("%d\n", strlen(&arr[0]+1));
解析:
int main() { char arr[] = "abcdef"; //这里是有\0的 printf("%d\n", sizeof(arr)); //7 //sizeof()计算整个数组大小,\0也算大小而strlen不算\0 printf("%d\n", sizeof(arr + 0)); //4或8 //首元素地址 printf("%d\n", sizeof(*arr)); //第一个元素大小 1 printf("%d\n", sizeof(arr[1])); //第二个元素大小 1 printf("%d\n", sizeof(&arr)); //&arr取出的是整个数组的地址,还是地址 printf("%d\n", sizeof(&arr + 1)); //4或8 //地址 printf("%d\n", sizeof(&arr[0] + 1)); //4或8 //第二个元素地址 printf("%d\n", strlen(arr)); //首元素地址,后面有\0可以停止 //6 printf("%d\n", strlen(arr + 0)); //6 //首元素地址 printf("%d\n", strlen(*arr)); //第一个元素strlen(a)-->strlen(97) //非法访问了 printf("%d\n", strlen(arr[1])); //第二个元素 //非法访问 printf("%d\n", strlen(&arr)); //6 //&arr取出的是整个数组地址,但&arr地址和首元素地址是一样的然后可以找到\0 printf("%d\n", strlen(&arr + 1)); //随机值 //&arr取出的是整个地址,+1,跳过整个数组地址,不知道后面是否有\0 printf("%d\n", strlen(&arr[0] + 1)); //第二个元素地址 //5 return 0; }
3.`
char *p = "abcdef"; printf("%d\n", sizeof(p)); printf("%d\n", sizeof(p+1)); printf("%d\n", sizeof(*p)); printf("%d\n", sizeof(p[0])); printf("%d\n", sizeof(&p)); printf("%d\n", sizeof(&p+1)); printf("%d\n", sizeof(&p[0]+1)); printf("%d\n", strlen(p)); printf("%d\n", strlen(p+1)); 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));
解析:
int main() { char* p = "abcdef"; // p表示字符指针,指向的是首元素的地址 printf("%d\n", sizeof(p)); //4或8 //计算首元素地址大小 printf("%d\n", sizeof(p + 1)); //4或8 //第二个元素地址 printf("%d\n", sizeof(*p)); //1 //第一个元素a printf("%d\n", sizeof(p[0])); //1 //第一个元素a printf("%d\n", sizeof(&p)); //4或8 //&p是二级指针,指向的是a的地址的地址 printf("%d\n", sizeof(&p + 1)); //4或8 //地址 printf("%d\n", sizeof(&p[0] + 1)); //4或8 //第二个元素的地址 printf("%d\n", strlen(p)); //6 //p表示首元素地址,strlen直达\0停止 printf("%d\n", strlen(p + 1)); //5 //从第二个元素地址开始 //printf("%d\n", strlen(*p)); *p表示a 非法访问了 //printf("%d\n", strlen(p[0])); 非法访问 strlen(a) printf("%d\n", strlen(&p)); //二级指针,指向首元素的地址的地址 //所以为随机值 printf("%d\n", strlen(&p + 1)); //随机值 printf("%d\n", strlen(&p[0] + 1)); //第二个元素地址 //5 return 0; }
二维数组指针练习
二维数组相关练习,下面答案是多少呢,为什么呢?
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]));
解析:
int main() { int a[3][4] = { 0 }; printf("%d\n", sizeof(a)); //48 //sizeof(数组名)表示计算的整个数组大小 printf("%d\n", sizeof(a[0][0])); //4 //第一行第一个元素大小 printf("%d\n", sizeof(a[0])); //a[0]表示第一行数组名,sizeof(数组名)表示计算的是第一行数组大小 //16 printf("%d\n", sizeof(a[0] + 1)); //a[0]表示第一行数组名,但没有单独放进sizeof()中也没有&,所以表示首元素地址,首元素地址+1表示第二个元素地址 //4或8 printf("%d\n", sizeof(*(a[0] + 1))); //4 //(a[0]+1)表示第一行第二个元素地址,解引用访问第二个元素 printf("%d\n", sizeof(a + 1)); //a是数组名,表示首元素地址,表示第一行的数组地址,+1表示第二行地址 //4或8 printf("%d\n", sizeof(*(a + 1))); //16 //(a+1)表示第二行地址,解引用表示整个第二行元素 printf("%d\n", sizeof(&a[0] + 1)); //a[0]表示第一行数组名,&数组名,表示取出的是第一行整个地址,+1跳过整个第一行数组地址大小所以表示第二行地址 //4或8 printf("%d\n", sizeof(*(&a[0] + 1))); //16 //第二行数组地址解引用 printf("%d\n", sizeof(*a)); //a数组名,没有单独放进sizeof中也没有&,所以表示的是首元素地址,表示第一行地址 //4或8 printf("%d\n", sizeof(a[3])); //arr[3]表示第四行数组名,单独放进sizeof()内部表示计算整个数组大小 // a[3]类型是int[4]----sizeof(int[4]) // 答案是16,而不是越界访问 //根据类型来计算大小,不会真实访问内部空间 //表达式不参与运算,不进行计算 return 0; }
练习总结:
- sizeof(数组名)表示计算的整个数组大小,数组名单独放进sizeof()才可以
- &数组名表示取出的整个数组的地址
- 处以上两个情况,其他数组名都表示首元素地址。
- sizeof()内部不参与运算,不进行真实的空间访问
- sizeof() 只关注占用内存空间的大小,单位是字节,不关心内存中放的是什么
- strlen是求字符串长度的,统计的是\0之前出现的字符个数,一定要找到\0才能结束,所以可能存在越界访问的可能
- sizeof 是操作符 strlen是库函数
指针笔试真题
第一题:考察&数组名表示什么意思
int main() { int a[5] = { 1, 2, 3, 4, 5 }; int* ptr = (int*)(&a + 1); printf("%d,%d", *(a + 1), *(ptr - 1)); return 0; } //程序的结果是什么?
结果:
解析:
int main() { int a[5] = { 1, 2, 3, 4, 5 }; int* ptr = (int*)(&a + 1); //ptr是个int*类型的指针,这里的&a表示取出的是整个数组的地址再+1的话,表示跳过整个数组大小的地址 //(&a+1)的类型是数组指针,然后这里将它强制类型转化成int *类型 printf("%d,%d", *(a + 1), *(ptr - 1)); //*(a+1),这里的a表示首元素地址,+1表示第二个元素地址,解引用访问第二个元素,2 //*(ptr-1),ptr被强制类型转换成int*类型,减1后就访问到最后一个元素的地址了 return 0; }
总结:
&数组名表示取出的是整个数组的地址,+1表示跳过整个数组大小。
第二题:考察指针加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; }
结果:
解析:
int main() { p = (struct Test*)0x100000; printf("%p\n", p + 0x1); //p+1取决于指针类型,这个指针是结构体类型大小为20,所以加1就跳过一个结构体大小20 //16进制的20为14 //0x100014 printf("%p\n", (unsigned long)p + 0x1); //这里将p强制类型转换成无符号长整形,也就变成了整数了,整数加1就是简单的加减运算 //0x100001 printf("%p\n", (unsigned int*)p + 0x1); //这里将p强制类型转换成int*类型,所以p+1跳过一个整形大小,也就是4个字节 //0x100004 return 0; }
总结:
指针加+1到底加几呢?
指针加1跳过多少取决于指针类型
整数加一就是加1
第三题:考察指针解引用访问多大空间?
//环境是小段字节序存储,X86 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; }
结果:
解析:
int main() { int a[4] = { 1, 2, 3, 4 }; int* ptr1 = (int*)(&a + 1); //&a取出的是整个数组地址,+1跳过整个数组大小,然后又被强制转换成int*类型 int* ptr2 = (int*)((int)a + 1); //a表示首元素地址,强制类型转换成整形,这个地址+1,就是整数+1,然后又被强制转换成int*类型 printf("%x,%x", ptr1[-1], *ptr2); //ptr1[-1]可以这样表示--> *(ptr-1) //对ptr2这个指针解引用,能访问多大空间呢? return 0; }
总结:
指针解引用访问多少空间也取决于指针类型,要记住指针解引用是要看访问多少空间的喔,不要忘记啦。
第四题:考察观察,逗号表达式
#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; }
结果:
解析:
int main() { int a[3][2] = { (0, 1), (2, 3), (4, 5) }; //注意这个不是将(0,1),(2,3),(4,5)放进数组,括号里是个逗号表达式,最终结果应该是{1,3,5}; //所以这个二维数组放的是1,3,5,0,0,0 int* p; p = a[0]; //a[0]表示数组第一行的数组名,没有单独放进sizeof中,也没有&,所以表示首元素地址,放进p里 printf("%d", p[0]); //p[0]表示*(p+0),就是第一个元素 1 return 0; }
第五题:考察指针-指针表示什么意思
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; }
结果:
解析:
指针-指针表示指针之间的元素个数,由于低地址减去高地址,所以为都为-4,但注意到,第一个是以%p的形式进行打印,是打印地址的,-4在内存中是以补码的形式进行保存,-4的原码反码补码分别是:
//100000000000000000000000000000100原码 //111111111111111111111111111111011反码 //111111111111111111111111111111100补码 补码直接转换成16进制形式就是
总结:指针-指针表示指针之间的元素个数
第6题:不同类型的指针+1表示跳过多少?
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; }
结果:
解析:
上面有题目和这个类似
第7题:考察pa++,到底指什么意思呢?
int main() { char* a[] = { "work","at","alibaba" }; char** pa = a; pa++; printf("%s\n", *pa); return 0; }
结果:
解析:
总结:
pa++,其实是pa指向的元素进行++














