在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?
1. 一维数组传参
一维数组传参指的是将一个一维数组作为参数传递给一个函数。
在C/C++中,可以使用以下两种方法传递一维数组:
1.1 在函数中将数组作为指针传递
函数定义如下:
void func(int *arr, int size) { // ... }
在调用函数时,可以直接传递数组名作为实参:
int arr[10]; func(arr, 10);
在函数内部,可以通过指针访问数组中的元素,例如:
void func(int *arr, int size) { for (int i = 0; i < size; i++) { printf("%d ",arr[i]); } }
1.2 在函数中使用数组形式的参数
函数定义如下:
void func(int arr[], int size) { // ... }
在调用函数时,也直接传递数组名作为实参:
int arr[10]; func(arr, 10);
和第一种方法类似,可以通过数组形式的参数访问数组中的元素:
void func(int arr[], int size) { for (int i = 0; i < size; i++) { printf("%d ",arr[i]); } }
1.3 知道了上面的方法,下面来看一个例子:
#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); }
arr是存放整形的数组
arr2是存放整形指针的数组
我们从上往下看:
一维数组传参,形参可以是
不带容量的一维数组,也可以带容量,也可以是指针,所以前三个很容易判断,都是正确的;
整形指针数组传参,可以类比整形数组传参:
整形数组传参:形参可以是整形数组,也可以是一级指针
整形指针数组传参:形参可以是整形指针数组,也可以是二级指针(arr2是存放整形指针的数组)
所以答案如下:
总的来说就是一维数组传参,形参可以是数组,也可以是指针,但当形参是指针的时候,要注意类型。
2. 二维数组传参
二维数组是一个由多个一维数组组成的数组,每个一维数组又由多个元素组成。在传参时,可以将二维数组传递给函数。
首先,定义一个二维数组并赋值:
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
然后,定义一个函数接受二维数组作为参数:
void printArr(int (*arr)[3]) { for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { printf("%d ", arr[i][j]); } printf("\n"); } }
在调用函数时,将二维数组作为参数传递给函数即可:
printArr(arr);
其中,int (*arr)[3]表示一个指向由3个整数组成的一维数组的指针(也可以写成int arr[2][3]),arr代表整个二维数组的首地址。在函数内部,可以使用arr[i][j]来访问数组元素。
下面来看一个例题:
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); }
二维数组传参,形参可以是指针,也可以是数组,
如果是数组,行可以省略,但列不能省略
如果是指针,传过去的是第一行的地址,形参就应该是数组指针
所以,答案如下:
但是,有的老铁可能用了上面错误的形参格式,但是最后还是能正常访问遍历数组,这是怎么一回事呢?
其实这是因为在参数传递的过程中编译器自动把代码给优化了,因为是指针,只要来的是个地址,它就接,但是我们应该尽量避免写出这样的代码,让我们的代码更加严密以及符合逻辑。
总结:
二维数组传参,函数形参的设计只能省略第一个[]的数字。
因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算。
3. 一级指针传参
一级指针是指向变量的指针。当使用一级指针作为函数参数时,函数会接收该指针所指向的变量的地址,从而使函数能够直接修改该变量的值。
下面是一个使用一级指针传参的示例:
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; }
在上面的示例中,print函数的形式参数是一个指向整型的指针p,而实际参数是一个指向整型数组的指针p或者数组名arr。这样,print函数就可以通过p加上i来访问或打印数组arr的第i个元素,从而实现打印数组的功能。
在main函数中,定义一个长度为10的整型数组arr,并用1到9初始化。
定义一个指向整型的指针p,并让它指向arr的首元素,即p = arr。
定义一个整型变量sz,并用数组arr的总字节数除以单个元素的字节数得到,即sz = sizeof(arr) / sizeof(arr[0]),这样就得到了数组的长度。
调用print函数,传入指针p和数组长度sz,打印出数组arr的所有元素。
思考:当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
一个指针变量,例如int* p = &a;,其中a是一个整型变量,p是一个指向整型的指针变量,可以将p作为参数传给函数。
一个数组名,例如int arr[10];,其中arr是一个长度为10的整型数组,arr也是一个指向数组首元素的指针,可以将arr作为参数传给函数。
一个地址常量,例如&b;,其中b是一个整型变量,&b表示b的地址,也是一个指向整型的指针常量,可以将&b作为参数传给函数。
如下:
4.二级指针传参
二级指针传参的意思是,函数的形式参数是一个指向指针的指针类型,而实际参数是一个指向指针的指针变量或者一个指针数组名。这样,函数就可以通过指针操作符来访问或修改实际参数所指向的指针或者指针数组的元素。
来看一个简单的例子:
void swap(int** p1, int** p2) { int* tmp = *p1; *p1 = *p2; *p2 = tmp; } int main() { int a = 10; int b = 20; int* pa = &a; int* pb = &b; //二级指针pa和pb,传给函数 swap(&pa, &pb); printf("a=%d b=%d\n", a, b); //输出a=20 b=10 printf("*pa=%d *pb=%d\n", *pa, *pb); //输出*pa=10 *pb=20 return 0; }
在上面这个例子中,swap函数的形式参数是一个指向整型指针的指针p1和p2,而实际参数是一个指向整型指针的指针变量pa和pb。这样,swap函数就可以通过p1和p2来交换pa和pb所指向的整型变量的值。二级指针传参的好处是,可以实现对指针的间接操作,提高程序的灵活性和扩展性。
思考:当函数的参数为二级指针的时候,可以接收什么参数?
一个指向指针的指针变量,例如int** pp = &p;,其中p是一个指向整型的指针变量,pp是一个指向整型指针的指针变量,可以将pp作为参数传给函数。
一个指针数组名,例如int* arr[10];,其中arr是一个长度为10的整型指针数组,arr也是一个指向整型指针的指针,可以将arr作为参数传给函数。
一个地址常量,例如&c;,其中c是一个指向整型的指针变量,&c表示c的地址,也是一个指向整型指针的指针常量,可以将&c作为参数传给函数。
如下: