29.指针作为参数传递
首先我们得明确两个概念:实参 和 形参
实参:主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”。
形参:被调函数中调用一个函数时的,用来接收调用该函数时传递的参数。
简单来说,就是实参在主函数上的参数,形参就是在被调函数中的传递参数。
明确了实参与形参后,接下来我们从三个方面来介绍指针作为参数传递
一、实参与形参相互独立
我们用一个例子证明实参与形参相互独立
#include<stdio.h>
void swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
//此处为定义一个函数,此函数的作用是进行 数值的交换
int main() //定义了一个主函数
{
int a, b;
int temp;
a = 1;
b = 2;
printf("a=%d b=%d\n", a, b);
swap(a, b);
printf("a=%d b=%d\n", a, b);
}
//主函数的 目的 是将a=1,b=2输入 数值的交换的swap函数
运行函数后,由结果可以看出数值还是一样的,无法进行交换。
原因:这是由于形参x,y与实参a,b相互独立
函数swap可以修改变量x、y但是无法影响到主调函数中的a,b
现在从内存地址的层面分析
#include<stdio.h>
void swap(int x, int y)
{
printf("&x=%u\n", &x);
printf("&y=%u\n", &y);//&为取地址运算符,分别打印x,y的首地址
int temp = x;
x = y;
y = temp;//将x和y的值进行交换
}
int main()
{
int a, b;
a = 1;
b = 2;
printf("&x=%u\n", &a);
printf("&y=%u\n", &b);//分别打印a,b的首地址
swap(a, b);
return 0;
}
运行之后可以看出它们的首地址是完全不同
主调函数中的swap只是将a,b的数值传给了x,y,首地址没有变化
因此x和y的值无论怎么变换都不会改变a和b的值
二、指针作为参数传递
还是上面的那个例子,但是这次将指针地址作为参数
#include<stdio.h>
//通过指针交换数据对象的值,是交换a和b的值,而不是交换x和y的值
//因此在交换的时候带上取值运算符*
void swap(int* x, int* y)//可以理解成 int* x=&a
{
int temp = *x;// *x表示取指针x的值
*x = *y;
*y = temp;
}//两个指针的值进行交换
int main()
{
int a, b;
int temp;
a = 1;
b = 2;
printf("a=%d b=%d\n", a, b);
swap(&a, &b); //&为取地址运算符,交换的是地址
printf("a=%d b=%d\n", a, b);
return 0;
}
运行后,a和b的数值成功交换了
简单来说,就是定义一个指针的函数,取到要交换参数的地址,在这个地址上重新取值
由此也可以解释scanf("%d",&n);
scanf会先读取从键盘上的输入转换后存储到变量n当中
被调函数scanf无法直接修改在主调函数中的变量n
因此将变量n的指针传入scanf函数
通过指针使得scanf函数能够间接修改变量n
三、void*类型指针
void swap(void* x,void* ,int size)
void类型的指针只保存首地址,不保存储存空间大小,所以不能对void对象进行取值
int n;
void* p = &n;
void任意类型的指针都可以直接赋值,但是指针类型丢弃,只保存首地址
p + 1;只有首地址,没有步长,因此无法加减运算
*p;只有首地址,无法取值
#include<stdio.h>
void swap(void* x, void* y, int size)//获取size字节的数据并交换
{
char* pX = (char*)x;//由于void指针不能加减,因此将其强制转换为char类型,char*可以对一个字节进行操作
char* pY = (char*)y;
char temp[128];
for (int i = 0; i < size; i++)
temp[i] = pX[i];
for (int i = 0; i < size; i++)
pX[i] = pY[i];
for (int i = 0; i < size; i++)
pY[i] = temp[i];
}