指针与函数
指针与函数
指针做函数参数
参数为变量
可以将指针作为函数的参数,从而在函数内部直接访问并修改指针所指向的变量。最经典的就是数值交换函数的编写。
#include <stdio.h>
void swap1(int x, int y)
{
int tmp;
tmp = x;
x = y;
y = tmp;
printf("x=%d,y=%d\n", x, y);
printf("addr_x=%p,addr_y=%p\n", &x, &y);
}
void swap2(int* x, int* y)
{
int tmp;
tmp = *x;
*x *y;
*y = tmp;
printf("*x=%d,*y=%d\n", *x, *y);
printf("addr_x=%p,addr_y=%p\n", x, y);
}
int main()
{
int a = 3;
int b = 5;
printf("before swap1, a=%d, b=%d, addr_a:%p, addr_p:%p\n", a, b, &a, &b);
swap1(a, b); // 值传递
printf("after swap1, a=%d, b=%d\n", a, b);
a = 3;
b = 5;
printf("before swap2, a=%d, b=%d, addr_a:%p, addr_p:%p\n", a, b, &a, &b);
swap2(&a, &b); // 地址传递
printf("after swap1, a=%d, b=%d\n", a, b);
return 0;
}
/*
before swap1, a=3, b=5, addr_a:0x7ffee70759e0, addr_p:0x7ffee70759e4
x=5,y=3
addr_x=0x7ffee70759bc,addr_y=0x7ffee70759b8
after swap1, a=3, b=5
before swap2, a=3, b=5, addr_a:0x7ffee70759e0, addr_p:0x7ffee70759e4
*x=5,*y=3
addr_x=0x7ffee70759e0,addr_y=0x7ffee70759e4
after swap1, a=5, b=3
*/
在上面代码中一共编写了两个交换函数swap1和swap2,参数个数相同但是类型不同,通过输出的结果可以看出swap2函数完成了变量之间的数据交换,swap1没有,其主要原因是这样的:
-
swap1函数的参数是数值,参数传递的是值,在传递过程中实参会发生拷贝,此时形参和实参变量对应的内存地址是不同的,在函数体内部交换的是参数的值,而不是外部实参的值
-
swap2函数的参数是指针,参数传递的是地址,形参指针指向的地址和实参变量的地址是相同的,因此在函数体内部通过形参指针就可以交换实参变量内部的数值了。
参数为数组
在C语言中,数组名在大多数情况下会被转换为指向数组首元素的指针。因此,当数组作为函数参数时,实际上传递的是指向数组第一个元素的指针。数组作为函数参数传递有2大重要特性:
-
大小信息丢失:
-
数组作为参数传递时会"退化"为指针,sizeof运算符无法获取数组大小
-
必须额外传递数组大小参数
-
-
修改影响原数组:
-
函数内对数组元素的修改会影响原数组
-
因为传递的是指针,不是数组的副本
-
一维数组作为函数参数
#include <stdio.h>
void printArray(int arr1[], int size1, int *arr2, int size2)
{
for(int i = 0; i < size1; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
arr1[4] = 15;
for(int j = 0; j < size2; j++)
{
printf("%d ", arr2[j]);
}
printf("*arr2 size:%ld\n", sizeof(arr2));
}
int main()
{
int str1[5] = {1,2,3,4,5};
int str2[3] = {10, 20, 30};
printArray(str1, 5, str2, 3);
printf("str1[4]:%d\n", str1[4]);
}
/*
1 2 3 4 5
10 20 30 *arr2 size:8
str1[4]:15
*/
数组作为函数入参时,int arr[]和int *arr是等价的,两种方式都是以指针的形式传入数组,因此函数内做的修改,都可以保留到函数外。如果如果不希望函数修改数组内容,可以使用const限定符。
多维数组作为函数参数
对于多维数组,需要指定除第一维外的所有维度大小:
#include <stdio.h>
void print2DArray(int arr1[][4], int rows1, int (*arr2)[3], int rows2)
{
for(int i = 0; i < rows1; i++)
{
for(int j = 0; j < 4; j++)
{
printf("%d ", arr1[i][j]);
}
printf("\n");
}
arr1[1][1] = 12;
for(int m = 0; m < rows2; m++)
{
for(int n = 0; n < 3; n++)
{
printf("%d ", arr2[m][n]);
}
printf("\n");
}
arr2[1][1] = 15;
}
int main() {
int matrix1[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
int matrix2[2][3] = {{11,12,13}, {15,16,17}};
print2DArray(matrix1, 3, matrix2, 2);
printf("matrix1[1][1]:%d, matrix2[1][1]:%d\n", matrix1[1][1], matrix2[1][1]);
return 0;
}
/*
1 2 3 4
5 6 7 8
9 10 11 12
11 12 13
15 16 17
matrix1[1][1]:12, matrix2[1][1]:15
*/
指针函数与函数指针
指针函数
指针函数(Pointer Function)是指返回值类型为指针的函数,即该函数返回一个指针(内存地址)。它本质上是一个函数,只不过它的返回值是一个指针,而不是普通的数据类型(如 int、float 等)。格式如下:
返回类型 *函数名(参数列表) {
// 函数体
return 指针; // 返回一个地址
}
测试用例
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;
};
struct Node *create_node(int data);
int *get_max(int *a, int *b);
int main()
{
struct Node *p1, *p2;
p1 = create_node(1);
p2 = create_node(2);
int *max_num = get_max(&p1->data, &p2->data);
printf("p1_data:%d, p2_data:%d, max:%d\n", p1->data, p2->data, *max_num);
int x = 5;
int y = 6;
int *max = get_max(&x, &y);
printf("max:%d\n", *max);
free(p1);
free(p2);
}
//返回指向较大值的指针
int *get_max(int *a, int *b)
{
if(*a > *b)
{
return a;
}
else
{
return b;
}
}
struct Node *create_node(int data)
{
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
new_node->data = data;
new_node->next = NULL;
return new_node;
}
/*
p1_data:1, p2_data:2, max:2
max:6
*/
在上面的例子中,我们通过指针函数返回了入参的指针和动态分配内存的指针。
注意事项
#include <stdio.h>
int y = 20;
int *return_global_num()
{
return &y;
}
int *return_static_num()
{
//静态变量的生命周期是到程序结束,而普通变量生命周期是到函数结束,这里不能用普通变量
static int x = 10;
return &x;
}
char* return_const_num()
{
return "abcd";
}
int main()
{
int *a = return_static_num();
int *b = return_global_num();
char* c = return_const_num();
printf("a:%d, b:%d, c:%s\n", *a, *b, c);
}
/*
a:10, b:20, c:abcd
*/
在使用指针函数时注意,比如在return_static_num函数中,如果使用的是局部变量是不行的。局部变量放在栈上面,函数调用结束后会被回收,返回它的指针会导致 悬垂指针(Dangling Pointer),访问它可能引发未定义行为(UB)
函数指针
函数指针(Function Pointer)是指向函数的指针变量,它存储的是函数的入口地址,可以通过该指针间接调用函数。函数指针最常用的就是回调机制。其格式如下:
返回类型 (*指针名)(参数列表);
int (*func_ptr)(int, int); // 定义一个函数指针,指向返回 int,接受两个 int 参数的函数
回调函数
回调函数是一种通过函数指针实现的编程机制,它允许将一个函数作为参数传递给另一个函数,并在适当的时候被调用。其工作原理如下:
-
定义回调函数:编写一个符合特定签名的函数。
-
注册回调函数:将函数指针传递给另一个函数(如库函数)。
-
触发回调:在特定条件满足时(如事件发生),调用注册的函数。
#include <stdio.h>
// 定义回调函数类型
typedef void (*Callback)(int);
// 接收回调函数作为参数
void process_data(int data, Callback callback) {
printf("处理数据: %d\n", data);
callback(data * 2); // 触发回调
}
// 实际回调函数
void print_result(int result) {
printf("回调结果: %d\n", result);
}
int main() {
process_data(10, print_result); // 传递回调函数
return 0;
}
/*
处理数据: 10
回调结果: 20
*/
区别
在声明时,函数指针的*号被括号括起来,这是区分两者的关键语法特征。
| 特征 | 指针函数 | 函数指针 |
|---|---|---|
| 本质 | 函数 | 指针 |
| 声明形式 | int *func(...) |
int (*func_ptr)(...) |
| 用途 | 返回指针 | 指向函数 |
| 调用方式 | 直接调用 | 通过指针间接调用 |

浙公网安备 33010602011771号