数组传参和指针传参
接下来,我会为大家介绍三种传参情况
一维数组传参、二维数组传参、一级指针传参、二级指针传参
一维数组传参
看看下面这段代码,思考一下那种传参方式是可行的。
#include <stdio.h> void test(int arr[])//ok? {} void test(int arr[10])//ok? {} void test(int* arr)//ok? {} void test2(int* arr[20])//ok? {} void test2(int** arr)//ok? {} int main() { int arr[10] = {0}; int* arr2[20] = { 0 }; test(arr); test2(arr2); }
答案是:这些写法都可以。
数组传参传的是数组首元素的地址。
二维数组传参
我们先看这段代码:
void test(int arr[3][5])//ok? {} void test(int arr[][])//ok? {} void test(int arr[][5])//ok? {} void test(int *arr)//ok? 这是接收一维数组的写法 {} void test(int* arr[5])//ok?这是指针数组,也不行 {} void test(int (*arr)[5])//ok?这才是对的,用数组指针 {} void test(int **arr)//ok?二级指针是用来接收一级指针的,所以也不行 {} int main() { int arr[3][5] = {0}; test(arr); }
知识点:
总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素,这样才可以运算。
一级指针传参
#include <stdio.h> void print(int* p, int sz) { int i = 0; for (i = 0; i < sz; i++) { printf("%d\n", *(p + i)); } } int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9 }; int* p = arr; int sz = sizeof(arr) / sizeof(arr[0]); //一级指针p,传给函数 print(p, sz); return 0;
用一级指针来实现打印数组。
一级指针传参,形参也要写成一级指针的形式来接收。
思考:
当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
有如下三种方式:
传入数组名(数组首元素的地址)
传入整型变量的地址
传入一级指针
二级指针传参
#include <stdio.h> void test(int** ptr) { printf("num = %d\n", **ptr); } int main() { int n = 10; int* p = &n; int** pp = &p; test(pp); test(&p); return 0; }
同样,二级指针传参要用同样是二级指针的形参来接收
思考;
当函数的参数为二级指针的时候,可以接收什么参数?
有如下三种方式:
传进去一级指针的地址
传进去二级指针
传进去指针数组的首元素地址(也就是指针的地址)
函数指针
定义:指向函数的指针,在内存空间中存放的是函数的地址。
函数地址:&函数名
或者 直接写函数名
函数名就是函数的地址
代码示例:
#include <stdio.h> void test() { printf("hehe\n"); } int main() { printf("%p\n", test); printf("%p\n", &test); return 0; }
程序输出的结果相同。
函数指针的存储
观察下面这段代码,看看那个才是函数指针
void test() { printf("hehe\n"); } //下面pfun1和pfun2哪个有能力存放test函数的地址? void (*pfun1)(); void *pfun2();
答案:第一个
因为pfun1先与8结合,是一个指针,然后才指向这个函数。
这个函数不传参,并且返回类型为void
格式:
指针的类型 (*pf)(函数参数的类型) = 函数名
运用:
想通过函数指针来实现两个数的求和,可以怎么写呢?
代码如下;
int Add(int x, int y) { return x + y; } int main() { int (* pf2)(int, int) = &Add;//这里需要把类型强转换成整型 int ret = (* pf2)(2, 3); printf("%d\n", ret); return 0; }
所以函数调用可以写成:
pf(参数)
*个数随便写,但要用括号括起来,
(*pf)(参数)
提示:
在使用函数指针时,是不用写*的,因为pf本就是地址,想要调用函数,直接解引用就行,不用多写星号,并且此处写多少个星号都行,
写星号只是为了提醒其他人这个变量是函数指针,便于理解。
题目:
下面介绍两段有趣的代码,大家可以思考一下他们的含义是什么
1.
(*(void (*)())0)();
拆开来看:
void(*)()是一个函数指针类型,
对(void (*)())0,就是强制类型转换0,把0转换成可以接收函数地址的指针变量,
那么0地址处就有void(*)()这么一个函数,
所以这段代码的意思就是:调用0地址处的函数,这个函数没有参数,返回类型是void。
2.
void (*signal(int , void(*)(int)))(int);
这行代码我们从里往外看
图解如下:
可以通过使用typedef,简化成两行代码:
typedef void(*pfun_t)(int); pfun_t signal(int, pfun_t);
结语
指针的知识暂时介绍到这里,下篇文章会继续介绍关于指针的知识,比如函数指针数组、指向函数指针数组的指针、回调函数等,我们下次见。