引言:在C语言中,所有函数参数的传递都是通过值传递进行的,本文将介绍函数参数传递的基本原理,及如何使用指针和二级指针来修改函数外部的数据。
1. 基本类型的传递
- 对于基本类型(如int、char、float等),传递的是变量的值的副本。
- 因此,在函数内对参数的修改不会影响函数外的实际参数。
实例:
#include <stdio.h>
void Value(int x)
{
x = 10; // 仅仅修改了副本 x
}
int main() {
int a = 5;
Value(a);//传入变量a
printf("%d\n", a); // 输出依然是5
return 0;
}
在上述代码中,函数Value中的参数x是a的一个副本,对x的修改不影响main函数中的变量a。
2.指针类型的传递
- 当传递指针时,传递的是指针的副本。
- 虽然实参指针自身的地址是按值传递的,但可以通过这个副本指针修改它所指向的内存中的值
实例:
#include <stdio.h>
void Value(int *p)
{
*p = 10; //通过解引用操作 修改副本指针 p 所指向的值
}
int main() {
int a = 5;
Value(&a);
printf("%d\n", a); // 输出10
return 0;
}
图解:
3.简单数组的传递
- 在C语言中,数组名在表达式中通常会转换为指向数组第一个元素的指针。
- 因此,传递数组给函数时,实际上创建的是指向数组第一个元素的指针。
- 这样函数可以通过这个指针访问和修改数组的内容。
实例:
#include <stdio.h>
void Array(int arr[])
{
arr[1] = 10; // 修改数组的第二个元素
//等价于*(arr+1)=10;
//这里加1是因为创建的是一个 int类型的指针副本;加1,使这个副本指针增加4个字节
//此时&arr[1],arr+1,与主函数中brr1+1,&brr[1]数值相等,均指向brr1[1]这个元素
}
int main()
{
int brr1[3] = {1, 2, 3};
Array(brr1);
printf("%d\n", brr1[1]); // 输出10
return 0;
}
在这个例子中,函数Array接收数组的首元素指针brr1,并修改了第二个元素的值,这种修改在函数外也是可见的。
理解了上述传参的特性,来解决如何通过 自定义函数 来改变 主函数中 指针变量 的值
4.通过指针修改指针的值(使用二级指针)
这里我们可以将主函数中 “被修改的指针变量”
看做第二种情况中的:副本指针所指向的内存中的值
- 当需要在函数中修改指针本身所存储的地址
- 即需要函数能够修改传入的指针(这个传入的指针就是需要改变的值) 使其指向新的内存位置时
- 必须传递指针的地址(即二级指针):
实例:
#include <stdio.h>
#include <stdlib.h>
void allocateMemory(int **p)
{
*p = (int *)malloc(sizeof(int)); // 为整数分配内存并让 *p 指向它
//改变了 传入的二级指针p所指向的 指针变量
if (*p == NULL)
{
printf("内存分配失败!\n");
return;
}
**p = 10; // 给分配的内存赋值
//解引用两次,改变传入的二级指针(指向的指针(指向的内存中的值))
}
int main()
{
int *ptr = NULL; // 定义一个指针,初始化为NULL
allocateMemory(&ptr); // 传入指针的地址,即二级指针
if (ptr != NULL)
{
printf("ptr指向的值是: %d\n", *ptr); // 输出10
free(ptr); // 释放分配的内存
}
return 0;
}
- 在这个例子中,allocateMemory函数通过二级指针int **p来接收指向指针ptr的地址。
- 函数内部通过*p修改了ptr的值,使其指向新的内存块。
- 这种修改在函数外是可见的,因此main函数中可以访问并使用新分配的内存。
只要我们理解了这个套娃的过程,就明白了如何改变主函数中指针变量的值
5.总结:
- 值传递:C语言中所有函数参数传递都是值传递。
- 基本类型:传递变量值的副本,函数内的修改不影响外部变量。
- 指针类型:传递指针的副本,可以通过指针修改指向的内存内容。
- 数组:传递的是数组首元素的指针,可以通过指针访问和修改数组内容。
- 二级指针:用于修改指针本身,使其指向新的内存位置或对象。