指针对于不少人来说:是多么一个难的代名词呀!!当然这个里面也包括笔者!所以……笔者对于指针满满的后怕!但是也有着更多的期待!毕竟阴影是用来打破的!后怕打破了,也就是龙腾虎跃的时候了!!下面进入正题:
笔者将用代码+解析的方式来带领大家走进:指针!! 第一题!
#include <stdio.h>
int main()
{
int arr[3][2] = { (0,1),(2,3),(4,5) };
int* p;
p = arr[0];
printf("%d\n", p[0]); //1
return 0;
}
注意,笔者的代码是在vs2022 的x86环境下进行演示的!请注意细节,若是在vs2022的x64环境下,出现不一样或者一样的结果!但结果都是正确的!(笔者亲测,在vs2022中x64的环境下,笔者讲解的部分指针笔试题解析,有着不一样的结果!但都是正确的!!)
若是有老铁能直接看懂,并且能够跟答案对上号,那么这篇博客,这位老铁就没有看的必要了,下面内容主要是对上面的代码的讲解!并不做其他的内容!但若是有兴趣,可以进一步欣赏!
下面进入讲解部分:
1.首先对于数组:int arr[3][2] = { (0,1),(2,3),(4,5) }; 笔者在这里面,小小的考验一下读者:对于前面所讲述的逗号表达式,是否已经忘记??在这儿强调一下!!所以上述数组初始化后实际初始化的内容为:1,3,5,因此整个数组初始化后内容为:int arr[3][2] = { 1,3,5,0,0,0}!笔者在刚刚接触到这个数组时候,也是巧妙地被……栽坑里面了!!
2.对于数组: arr[3][2] = { 1,3,5,0,0,0}
int *p :整型指针,arr[0] 为第一行的数组名,arr[0]没有单独放在sizeof内部,也没有进行&arr[0], 所以,数组名表示首元素的地址,即元素1的地址!p=arr[0],指的意思为:p=&arr[0][0],所以指向元素1, 对于: p[0]指: *(p+0)—》*p ;指向第一个元素1,即打印结果为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]); //FFFFFFFC -4
return 0;
}
对于这个题目,感觉很有难度!!若是读者能够自己看懂!已经很算是大佬级别人物!!下面请看笔者解析!
首先,笔者先进行简单提示一下:指针(地址)减去指针(地址)计算的是两个指针之间的元素个数!!
1.对于:int(p)[4] ;p是一个指针,它能指向一个数组,4个元素,每个元素都为int (整型)!p=a;将a赋值给p, a是数组名,表示数组首元素的地址!即为第一行的地址!a的类型为:int ()[5]是一个指针数组,而p 的类型为: int (*)[4]; 与a的类型不一样,会发生警告!!
2.int (*p) [4] : 指向4个元素,每个元素为int 类型!p+1, p+2, p+3,p+4,在图上分别标注出来:
p[4][2]相当于: *(*p+4)+2) ; 整型的数组指针:解引用的时候,有权利访问4个字节!
3.随着数组下标的增长,地址由低到高!
对于:&p[4][2] - &a[4][2] 以%d打印时候:小地址减去大地址!(之间的元素个数为4个)所以结果为-4!!
&p[4][2] - &a[4][2] 以%p打印时候:
-4的原码为:1000000000000000000000000000000100
反码为: 111111111111111111111111111111111111011
补码为: 111111111111111111111111111111111111100
但是以%p的形式打印,并不讲究原码,反码,补码的问题!但是由于在内存中存放的是补码!所以将:补码: 111111111111111111111111111111111111100当作了地址来进行打印!
4个二进制位为一个16进制位!而且4个1为一个F,所以上面划算后的结果为:FFFFFFFC!!
代码的运行结果为:
第三题
#include <stdio.h>
int main()
{
int arr[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
int* ptr1 = (int*)(&arr + 1);
int* ptr2 = (int*)(*(arr + 1));
printf("%d %d \n", *(ptr1 - 1), *(ptr2 - 1)); //10 5
return 0;
}
1.对于数组: int arr[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
我们也可以写为:
更为方便使用!!
- &arr : 取出的是二维数组的地址!&arr+1,跳过整个数组,通过:(int*)(&arr + 1) 强制类型转化为:整型指针!
&arr+1是一个数组指针!
ptr1的类型为:int* ; ptr1-1向前挪动一个整型,指向10的地址!再通过*(ptr-1)解引用操作,得到10;
3.arr是二维数组的数组名,数组名表示二维数组的首元素的地址!二维数组的首元素为第一行,即表示第一行的地址!arr+1 :跳过第一行,对*(arr+1)进行解引用得到第二行!(arr+1) 相当于arr[1],即,第二行的数组名!而arr[1]并没有单独放在sizeof内部,也没有进行&(取地址操作),即指:arr[1][0]的地址!也为元素6的地址!而对于:6的地址,不需要转化为:int * 故 题目中的(int)(*(arr + 1)):int 是迷惑人的!!ptr2拿到6的地址!而对ptr2-1,向前挪动一位,(ptr2-1)解引用,得到元素5!!
代码的运行结果为:
第二题
#include <stdio.h>
int main()
{
char* arr[] = { "wolk","at","ailibaba" };
char** pa = arr;
pa++;
printf("%s\n", *pa); //at
return 0;
}
对于: char* arr[] = { "wolk","at","ailibaba" }; 数组的每个元素都为: char * ,即,数组arr里面存放的都是char *的指针(地址)!而字符串作表达式的时候,它的值,实际上为首字符的地址!!
而对于:char** pa = arr; pa是一个二级指针,而将arr赋值给pa, a 是数组名,表示首元素的地址!每个元素都是char* ;
但是对于:char **pa,该如何理解?
pa指的是:pa为指针!char 告诉我们,pa指向的对象为:char *类型!
pa++: 跳过一个char* 类型的元素大小,即指向at!!
代码的运行结果为:
对于指针的笔试题,经过4个博客,笔者终于写完了!!在最后,为了考验一下!请自主完成……
#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;
}
非常有难度!代码的运行结果为: