《彻底搞懂C指针》一些读书笔记

一.指针与数组名

两条关系:

  1. pa[i] = *(pa+i)
  2. pa = &pa[0]
  • 数组名是该数组的首地址,是个地址常量,也及指针变量的一个值,不是指针。本质上是变量和常量的区别。
  • 因此指针可以自增加,而数组名不可以自增加。由此可以看出指针与数组名的区别。

二.int *pi指针指向const int i常量的情况

/* begin */ 
const int i1 = 40;
int *pi; 
pi = &i1; 
//VC下报错,因为不能通过指向整型变量的指针来修改常整形的值。
pi = (int *) &i1;
/* VC下编译通过,但是仍不能通过 *pi = 80来修改 i1 的值。去试试 吧!看看具体的怎样。*/
//我认为强制转换只是在该条语句中起作用,后续通过该指针改变i,i仍然是常整形。
/* end */

三.函数参数的传递

1.值传递

void Exchg1(int x, int y)
{
int x = a; /* ← */ 
int y = b; /* ← 注意这里,头两行是调用函数时的隐含操作 */
int tmp; 
tmp = x;
x = y;
y = tmp;
printf("x = %d, y = %d\n", x, y); 
}
main() 
{
int a = 4,b = 6; Exchg1(a, b);
printf("a = %d, b = %d\n", a, b); 
return(0);
}

其实函数在调用时是隐含地把实参 a、b 的值分别赋值给了 x、y, 之后在你写的 Exchg1 函数体内再也没有对 a、b 进行任何的操作了。交换的只 是 x、y 变量。并不是 a、b。当然 a、b 的值没有改变啦!函数只是把 a、b 的 值通过赋值传递给了 x、y,函数里头操作的只是 x、y 的值并不是 a、b 的值。这就是所谓的参数的值传递了。

2.地址传递

void Exchg1(int x, int y) 
{
px = &a; 
py = &b;//隐含操作

int tmp; 
tmp = x; 
x = y; 
y = tmp;
printf("x = %d, y = %d\n", x, y);
}
main()
{
int a = 4,
b = 6;
Exchg1(a, b);
printf("a = %d, b = %d\n", a, b);
return(0);
}

3.引用传递

void Exchg3(int &x, int &y)
{ 
int tmp = x;
x = y;
y = tmp;
printf("x = %d,y = %d\n", x, y);
}
main()
{
int a = 4;
int b = 6Exchg3(a, b);
printf("a = %d, b = %d\n", a, b); return(0);
}

引用传递 Exchg3(a, b)函数里是用 a、b 分别代替了 x、y。函数里操作 的就是 a、b 变量的本身,因此 a、b 的值可在函数里被修改的。

四.指向另一指针的指针

1.内存实质

image-20210514004238074

2.应用实例

image-20210514004432023

错误示例:

void find1(char array[], char search, char *pa) 
{
	int i;
	for (i = 0; *(array + i) != 0; i++) 
	{	
		if ( *(array+i) == search) 
		{
		pa = array + i;//错误,如果误以为函数外部的pa的值为该值,则会导致出错。
		break; 
		}
		else if (*(array+i) == 0) 
        {
		pa = 0;
        break;
		} 	
   }
}

参数 pa 与参数 search 的传递并没有什么不同,都是值传递嘛(小语:地 址传递其实就是地址值传递嘛)!所以对形参变量 pa 值(当然值是一个地址值) 的修改并不会改变实参变量 p 值,因此 p 的值并没有改变(即 p 的指向并没有被改变)。

修正:

void find2(char array[], char search, char **ppa)//利用二级指针可以实现
{
	int i;
	for (i=0; *(array + i) != 0; i++)
	{
		if(*(array + i) == search) 
		{
		*ppa = array + i; 
		break;
		}
		else if(*(array + i) == 0) 
		{
		*ppa = 0;
        break;
		} 
	}
}

我的理解:假设int a=10,int b =20,当我们想利用函数对a b进行互换, 则传入的是a b 两个变量的地址,所以函数的形参写为:(int *,int *),实参为(&a, &b)。

假设int *c = &a, int *d = &b,当我们想利用函数对c d交换地址,则传入的是c d 两个指针变量的地址,所以指针的地址的用形参表示为(int * *, int * *),实参为(&c,&d )。

总结:当我们想用函数实现对某数据的改变,则应传入该数据的所在的地址。

五.函数名与函数指针

1.函数指针变量的声明

void (*FunP)(int)//函数名加括号,并在之前加*号

2.通过函数指针变量调用函数

MyFun(10); /* 这是直接调用 MyFun 函数 */
FunP = &MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量 */
(*FunP)(20);//第一种方式


MyFun(10); /* 这里是调用 MyFun(10)函数 */
FunP = MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量 */
FunP(20);//第二种方式


MyFun(10); /* 这里是调用 MyFun(10)函数 */
FunP = &MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量 */
FunP(20);//第三种方式


MyFun(10); /* 这里是调用 MyFun(10)函数 */
FunP = MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量 */
(*FunP)(20);//第四种方式

//1)其实,MyFun 的函数名与 FunP 函数指针都是一样的,即都是函数指针。 MyFun 函数名是一个函数指针常量,而 FunP 是一个函数数指针变量,这是它 们的关系。 
//2)但函数名调用如果都得如(*MyFun)(10)这样,那书写与读起来都是不 方便和不习惯的。所以 C 语言的设计者们才会设计成又可允许 MyFun(10)这种 形式地调用(这样方便多了并与数学中的函数形式一样,不是吗?)。 
//3)为统一起见,FunP 函数指针变量也可以 FunP(10)的形式来调用。
//4)赋值时,即可FunP = &MyFun形式,也可FunP = MyFun。

3.给函数指针类型起别名

typedef void (*FunType)(int);//给这一函数指针类型起了FunType这一别名
FunType FunP;//因此void(*FunP)(int) == FunType FunP;
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值