C语言----指针形参(指向指针的指针形参)

一、通过指针形参在子函数改变常量

大家都知道,C语言子函数的形参,是可以为普通数据类型,也可以为指针的。最初遇到这问题,是在学习STM32的库函数的使用。当初刚接触库函数,对于函数初始化接口,如:

GPIO_Init(GPIOA, &GPIO_InitStructure); 

为什么要取初始化结构体变量的地址传递进库函数(&GPIO_InitStructure),而不是直接将结构体变量本身(GPIO_InitStructure)传递进去,不甚了解。直到后来,程序中指针用得多了才有所理解,在这里做个记录。先上代码:

#include <stdio.h>

void AddNum1(int data)
{
	data++;
}

void AddNum2(int *data)
{
	(*data)++;  //自增运算符“++”优先级高于取值符“*”

	printf("AddNum2()运行结果:\r\n\r\n*data = %d\r\n", *data);
	printf(" data = 0x%08X\r\n", data);
	printf("&data = 0x%08X\r\n\r\n", &data);
}

int main(void) 
{
	int Num1 = 1;

	//测试AddNum1
	AddNum1(Num1);
	printf("AddNum1()运行结果:\r\n\r\nNum1 = %d\r\n", Num1);

	Num1 = 1;
	printf("\r\n\r\n");

	//测试AddNum2
	AddNum2(&Num1);
	printf(" Num1 = %d\r\n", Num1);
	printf("&Num1 = 0x%08X\r\n", &Num1);


	getchar();
}

运行结果如图:


编译环境为VS2015。

可知,AddNum1没有改变Num1的值,而AddNum2将Num1的值自增了1。分析:

(1)对于子函数形参的理解:

        主函数中的代码“AddNum1(Num1);”。实质上,它将Num1的值赋值给了子函数的形参“data”。

        可将“AddNum1(Num1);”代码理解为运行了以下代码:

void AddNum1()
{
	int data = Num1;
	data++;
}

        通俗的解释就是,子函数声明了一个整型常量“data”,用“data”缓存“Num1”的值。函数中的其他代码,是针对“data”进行运算的,而“Num1” 除了把它自身的值传递给“data”外没有其他任何操作。所以,“AddNum1();” 这个函数并有没改变“Num1”的值。

(2)指针形参的作用:

        我们在对常量,或者是指针进行操作的时候,实质上是对其对应的内存进行操作。对“AddNum2(&Num1);”运行结果以 内存分布图诠释如下:

        


1、可知,Num1的地址是0x00600FFA0C,”AddNum2(int *data)“;声明了一个指针data,并且将Num1的地址赋值给了指  针 data,相当于执行了”data = 0x00600FFA0C;“,此时”*data“ 等同于”Num1“。

2、接下来的”(*data)++;“,操作的是指针data指向的内存”0x00600FFA0C“,这行代码使这个内存块上存储的常量自    增了1,所以”*data = 2“。由1可知,”*data“ 等同于 ”Num1“,所以“*data = 2 = Num1”。


     总结:通过将变量地址传递进子函数,在子函数内操作该地址的内存上存储的数据可达到改变变量的目的。



二、通过指向指针的指针在子函数改变指针的值

  

这种情况我用得比较少。不过在调用内存管理函数的时候可能会用到。如下代码:

主函数声明了一个指向0x00000001地址的char型指针pMemory,并通过子函数申请内存,将申请得到的地址赋值给pMemory

#include <stdio.h>
#include <stdlib.h>


void GetMemory1(char  *pAddr)
{
	 pAddr = (char  *)malloc(sizeof(char) * 100);
}

void GetMemory2(char  **pAddr)
{
	*pAddr = (char  *)malloc(sizeof(char) * 100);
	printf("  *pAddr = 0x%08x\r\n", *pAddr);
	printf("   pAddr = 0x%08x\r\n", pAddr);
	printf("  &pAddr = 0x%08x\r\n\r\n", &pAddr);
}


int main(void) 
{
	char *pMemory = 0x00000001;

	printf(" pMemory = 0x%08x\r\n", pMemory);
	printf("&pMemory = 0x%08x\r\n\r\n", &pMemory);


	GetMemory1(pMemory);

	printf("/*******GetMemory1();********/\r\n\r\n");
	printf(" pMemory = 0x%08x\r\n", pMemory);
	printf("&pMemory = 0x%08x\r\n\r\n", &pMemory);


	printf("/*******GetMemory2();********/\r\n\r\n");
	GetMemory2(&pMemory);
	printf(" pMemory = 0x%08x\r\n", pMemory);
	printf("&pMemory = 0x%08x\r\n", &pMemory);


	getchar();
}

运行结果:



如上,GetMemory1();并不能将地址赋值给pMemory,而GetMemory2();成功将申请得到的地址赋值给pMemory。分析:

(1)GetMemory1();

        类似于“AddNum1();”,声明了一个指针pAddr,然后将pMemory的值赋值给pAddr。后续代码改变的是pAddr的数据 而没有改变pMemory。所以没有成功地将申请得到的地址赋值给pMemory。

(2)GetMemory2();

        先上图:


       进入函数后,pMemory的地址0x008FF718赋值给了pAddr。malloc();申请得到的内存空间的地址0x02BB4D80赋值给了pAddr所指向的内存“*pAddr”(0x008FF718)。又因为*pAddr = pMemory; ,所以申请得到的内存地址成功赋值给了pMemory。




       综上所述,当数据被传递进子函数,如需通过子函数改变数据的值,需将它的地址作为形参传递进函数(无论常量亦或是指针)。



猜你喜欢

转载自blog.csdn.net/a3748622/article/details/79286974