指针
int i=1;
int *p=&i;
画出内存的图就是如下
内存里是没有P,i的。
p的值就是0x00f1, *p =*0X00f1 也就是取得 i的值为1
转成汇编,就是lea rax,[rpb-0xc]
获取[rpb-0xc]处的内存地址放到rax中
然后放到[rbp-0x8]
就是最上面的那个图。
理解了这个后,很多指针的东西就能理解。
指针加减
由上面可知
int *p 实际上就是一个内存里存了另个内存的地址
p的话就是另个内存的地址的值,内存从0开始,如果是4g内存,就到4g结束
是数字相当支持加减。用的最典型就是数组的加减。如下
int main(){
//规定了 arr就是数组的第一个元素的地址
int arr[]={1,2,3,4};
// arr不支持加减,而int *p=arr 就可以进行p++操作
int *p=arr;
for(int i=0;i<4;i++){
//p+i就是移动了4个字节(int)
printf("%d \n",*(p+i));
}
return 0;
}
为何知道移动4个字节,因为定义int p 的时候指定了 int。
转成汇编如下:
+58:[rbp-0x4] 的值付给ax , 由+49得知 一开始[rbp-0x4]为0。
+63:取得[ax4+0X0]的地址给了dx
+71: 取得数组的第一元素的地址,也就是1的地址给了ax
+75: ax+dx 也就是dx+ax个字节,ax=4 这就是回答上面的答案
+94:[rbp-0x4]+1
+98: 比较是否=3
+102:jle 如果小于的话,就跳到main+58的地方
数组指针
打印出下面的二维数组
printf("---------------------------\n");
int s2_arr[3][4]={
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
//定义了一个指向 int[4] 的指针 s2_p
int (*s2_p)[4]=s2_arr;
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
//由于*比+运算级别高,所以必须*(s2_p+i)表示取得指向第i行的首地址
//*(s2_p+i)+j表示第i行第j列的地址
//*(*(s2_p+i)+j) 取得表示第i行第j列的地址的值
printf("%d ",*(*(s2_p+i)+j));
}
printf("\n");
}
printf("---------------------------\n");
打印结果
也可以写成如下
printf("---------------------------\n");
int s2_arr[3][4]={
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
int (*s2_p)[4]=s2_arr;
int (*s2_p2)[3][4]=&s2_arr; //指针的指针,s2_p2指向了s2_arr的首地址
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
printf("%d ",*(*(*s2_p2+i)+j));
}
printf("\n");
}
printf("---------------------------\n");
函数指针
指向函数的指针
实例1:
/**********************************************/
/** 3.函数指针,指向函数的指针
/**********************************************/
#include <stdio.h>
int add(int,int);
int sub(int,int);
//int (*)(int,int) 定义了一个函数指针,该函数有2个int输入,1个int return
int calc(int (*)(int,int),int,int);
int add(int p1,int p2){
return p1+p2;
}
int sub(int p1,int p2){
return p1-p2;
}
int calc(int (*p)(int p1,int p2),int i1,int i2){
//(*p)表示获取的函数的地址
//如果写成p(i1,i2); 也可以,但这样就变成了函数调用
return (*p)(i1,i2);
}
int main(){
int s3_p1;
int s3_p2;
char op;
printf("请输入算式!");
scanf("%d%c%d",&s3_p1,&op,&s3_p2);
switch(op){
case '+': printf("%d%c%d=%d \n",s3_p1,op,s3_p2,calc(add,s3_p1,s3_p2)); break;
case '-': printf("%d%c%d=%d \n",s3_p1,op,s3_p2,calc(sub,s3_p1,s3_p2)); break;
default : printf("无效算式!");
}
}
实例2:
int add(int,int);
int sub(int,int);
int calc(int (*)(int,int),int,int);
//如何解释这个定义
//参照c运算优先和结合性,()优先级最高,函数有2个(),优先级相同则参照结合性
//()的结合性从左到右,所以先(*select(char))
//
int (*select(char))(int,int);
int add(int p1,int p2){
return p1+p2;
}
int sub(int p1,int p2){
return p1-p2;
}
//函数指针作为参数
int calc(int (*p)(int p1,int p2),int i1,int i2){
//return p(i1,i2);
return (*p)(i1,i2);
}
//函数指针作为返回值
int (* select(char op))(int,int){
switch(op){
case '+': return add; break;
case '-': return sub; break;
}
}