C-指针

指针

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:取得[ax
4+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;
	}
}

参考

关于c的运算符优先性和结合性问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值