对C/C++指针问题的彻底理解(复习1)
理解第一篇
上完大学不是我吹(仅仅说我认识的本学校本专业)估计很明白指针的人绝对不超过百分之50,学校low不low另说(因为问他们讲得断断续续的自己也说不明白,只知道那样可以用) 学链表树形结构.......等结构的时候一直困扰一个问题 例如int* a 和int *a ,*a,**a,int**a 或者说*******a 或者说Node n 和Node *n到底什么意思?大家都知道这是指针 ,指针本质是什么都说是地址.每次编程的时候都是报错了才能发现指针错误再去改正其实就是不太理解
例子 1
void Functionc() { int** a= (int** )5; printf("%d\n" ,a); } //结果 a仍然是5
对应汇编指令 可以看到只是把5存到堆栈
00410A56 rep stos dword ptr [edi]
26: int** a= (int** )5;
00410A58 mov dword ptr [ebp-4],5
27: printf("%d\n" ,a);
00410A5F mov eax,dword ptr [ebp-4]
解: 不光是两个** 就算写成一万个星 打印结果仍然是5 因为不管是什么类型的或者你定义的结构体后面加*或者说加** 都相当于一个新的类型
例二 & 和 * 的联系
假如你定义一个char a=10 假如你 &a 可以取到变量a的地址,你可以用char b=*a接收吗?不可以 !因为 &a 相当于 char* 类型的
那么假如char* b=&a 那么&b 是什么类型的? 对他是char** 类型的 每次加一个取地址符号就相当于类型后加个*
&取地址符条件 常量无法使用其他貌似都可以
例三
int* a 和int *a 没有任何区别!!我们好多书上写第二种 其实第一种看的比较清楚 第二种代码比较好看
例如 int* x 其中x 和*x 区别 x 是int* 类型的,*x是 int 类型的 同理 int** y y是int**类型的 *y 是int*类型的 **y是int 类型的
前面可以用*x的条件 他的类型必须是个指针类型意思就是带一个或多个*
从汇编角度理解*p的意思如图
把10赋值给了堆栈 x值存储到【ebp-4】的地址 然而px把 ebp-4的值存到了【ebp-8】 相当于把 指向x的指针(地址)存到了【ebp-8】,
下面的int x1 =*px 把指向x的指针(地址)取出来放到ecx 又把指针指向的值(10)放到了 edx ,又把edx 放到了 【ebp-c】所在内存地址
一个用指针找数组问题
int arr[5]={1,2,3,4}; int* px=arr; for(int i=0;i<=3;i++) { printf("%d\n" ,*(px++)); }
都知道能打印出来1 2 3 4 都知道指针后移动一个本质是这样的
首先了解这段代码
functionss() { int* a; a=(int*)100; printf("%d\n" ,a++); }
你以为输出101吗其实输出 104 ,那如果是char 类型输出多少 是101 short 呢?102
如果是一个* 就相当于加上那个类型(意思是相当于砍掉一个*所占字节数 如果是int** 的一个变量相加要看int* 所占字节)所占用字节数 (+1的情况 如果加2 的话就是 2*所占字节数)
【int** short** 所有** 所占的都是四字节】 这个说的不大明白.......不理解也没事
进入正题
int arr[5]={1,2,3,4}; int* px=arr; for(int i=0;i<=3;i++) { printf("%d\n" ,*(px++)); }
为什么 px++ 能准确找到下一个数组值村的数呢? 数组里面的值是连续存放的大家都知道 ..... px 为int* 类型 这里px++加的时候相当于 加上4 内存里加上四刚好是下一个数的地址 *px 相当于取出px地址里面的值显示出来
指针数组
void funcs() { int a=1; int b=2; int c=13; int* arr[5]={&a,&b,&c};// 指针数组占用20个字节 (int)4*5 数组里面只能存放int* 类型数据 char* keyword[] = {"if","for","whille"};//这样也能赋值 因为这里面的数据存在常量区(没法改) 这里面存的是地址 }
唯一要记住的就是int* 数组里面存的也是int* 类型的就行 char* a[] 数组里面存的是char* 类型的 其实说白了汇编里面都是地址
*( ) 可以和[ ]互换
void funcs1() { char* a="nihaoya"; printf("%c \n",a[0]);//输出n char** b=&a; printf("%c \n",b[0][0]);//输出n b[0][1]输出i //出现这个情况原因是b[0]==a 再[]一下是取出一个字符 }
同理一个* 可以用p【 】 三个*可以用p【】【】【】来遍历
数组指针(认为很难理解的一种)
int main(int argc, char* argv[]) { int arr[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; int (*px)[2]; //数组指针 px=(int (*)[2])arr; printf("%d \n",px);//*px和px值一样但是进行运算时宽度不一样 *px为数组类型 *px为数组首地址 printf("%d \n",*px);//*px和px值一样 但是进行运算时宽度不一样 *px为数组类型 *px为数组首地址 printf("%d \n",**(px+1));// px时这里加了8字节 一个int 占四字节相当于后移两位 输出3 printf("%d \n",*(*px+1));// *px为数组首地址 这里加一就下移动一位 输出 2 printf("%d \n",*(*(px+1)+1)); //自行判断 getchar(); return 0; }
总结: int (*px)[2] 里面的2(应该是写成大于0的都行)跟访问 arr[16]没有任何关系(不管arr有多大) *px为数组首地址一定要记住
你也可以用nt (*px)[2][1] 来访问 arr[16] 此时**px 为数组首地址
不是很常用........
下一篇结构体数组