C语言指针操作(四)用数组名作函数参数

您所在的位置:网站首页 otcv3参数组名 C语言指针操作(四)用数组名作函数参数

C语言指针操作(四)用数组名作函数参数

2024-07-06 18:46| 来源: 网络整理| 查看: 265

指针操作系列文章:

C语言指针操作(一)地址,指针,指针变量是什么

C语言指针操作(二)指针变量作为函数参数

C语言指针操作(三)通过指针引用数组

C语言指针操作(四)用数组名作函数参数

C语言指针操作(五)通过指针引用多维数组

C语言指针操作(六)通过指针引用字符串

C语言指针操作(七)指向函数的指针

C语言指针操作(八)返回指针值的函数

C语言指针操作(九)指针数组和多重指针

C语言指针操作(十)动态内存分配与指向它的指针变量

C语言指针操作(十一)有关指针的小结

用数组名作函数参数的详解,以及形参实参采用数组名,形参实参采用指针变量的几种情况解析。

关于地址,指针,指针变量可以参考一下这篇文章:

C语言指针操作(一)地址,指针,指针变量是什么

目录

一、引入

1.1实例

1.2解释

1.3变量名和数组名作函数参数的比较

二、程序举例

2.1引入

三、总结

3.1归纳

3.2用指针变量作实参、形参举例

3.3用指针变量作实参,数组名作形参举例

一、引入 1.1实例 #include int main() { void fun(int arr[], int n); //对fun函数进行声明 int array[10]; //定义array数组 ... //一系列操作 fun(array, 10); //用数组名作函数参数 ... //一系列操作 return 0; } void fun(int arr[], int n) //定义fun函数 { ... //一系列操作 }

array 是实参数组名,arr 为形参数组名,当用数组名作参数时,如果形参数组中各元素的值发生变化,实参数组元素的值随之变化。这究竟为什么呢?请继续往下看。

1.2解释

(1)先看数组元素作实参时的情况

如果已定义一个函数

void swap(int x, int y);

假设函数的作用是将两个形参( x , y )的值交换,进行函数调用

swap (a[1],a[2]);

用数组元素 a[1] 和 a[2] 作实参的情况,与用变量作实参时一样,是 “值传递” 方式,将 a[1] 和 a[2] 的值单向传递给 x 和 y 。当 x 和 y 的值改变时,a[1] 和 a[2] 的值并不改变。

(2)再看用数组名作函数参数的情况

实参数组名代表该数组首元素的地址,而形参是用来接收从实参传递过来的数组首元素地址的。因此,形参应该是一个指针变量(只有指针变量才能存放地址)。实际上,C编译都是将形参数组名作为指针变量来处理的。例如:

fun(int arr[],int n);

但在程序编译时是将 arr 按指针变量处理的,相当于将函数 fun 的首部写成

fun(int* arr,int n);

以上两种写法是等价的。在该函数被调用时,系统会在 fun 函数中建立一个指针变量 arr,用来存放从主调函数传递过来的实参数组首元素的地址。如果在fun函数中用运算符 sizeof 测定 arr 所占的字节数,可以发现 sizeof(arr) 的值为 4 (用 VisualC++ 时)。这就证明了系统是把 arr 作为指针变量来处理的(指针变量在 Visual C++ 中占4个字节)。

当 arr 接收了实参数组的首元素地址后,arr 就指向实参数组首元素,也就是指向 array[0]。因此,*arr 就是 array[0]。arr+1 指向 array[1],arr+ 2 指向 array[2],arr+3 指向 array[3]。也就是说,*(arr+1),*(arr+2), *(arr+3) 分别是 array[1],array[2],array[3]。

根据前面介绍过的知识,*(arr+i) 和 arr[i] 是无条件等价的。

因此,在调用函数期间,arr[0] 和 *arr 以及 array[0] 都代表数组 array 序号为 0 的元素,依此类推,arr[3],*(arr+ 3),array[3] 都代表 array 数组序号为 3 的元素。

1.3变量名和数组名作函数参数的比较 实参类型要求的形参类型传递的信息能否改变实参的值变量名变量名变量的值不能数组名数组名或指针变量实参数组首元素的地址能

说明: C 语言调用函数时虚实结合的方法都是采用 “值传递” 方式,当用变量名作为函数参数时传递的是变量的值,当用数组名作为函数参数时,由于数组名代表的是数组首元素地址,因此传递的值是地址,所以要求形参为指针变量。

在用数组名作为函数实参时,既然实际上相应的形参是指针变量,为什么还允许使用形参数组的形式呢?这是因为在 C 语言中用下标法和指针法都可以访问一个数组(如果有一个数组 a,则 a[i] 和 *(a+i) 无条件等价),用下标法表示比较直观,便于理解。因此许多人愿意用数组名作形参,以便与实参数组对应。从应用的角度看,用户可以认为有一个形参数组,它从实参数组那里得到起始地址,因此形参数组与实参数组共占同一段内存单元,在调用函数期间,如果改变了形参数组的值,也就是改变了实参数组的值。在主调函数中就可以利用这些已改变的值。

注意:实参数组名代表一个固定的地址,或者说是指针常量,但形参数组名并不是一个固定的地址,而是按指针变量处理。

二、程序举例 2.1引入

将数组 a 中 n 个整数按相反顺序存放,实参用数组名 a,形参可用数组名,也可用指针变量名。

(1)形参用数组名

#include int main() { void inv(int x[], int n); //函数声明 int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; for (int i = 0; i < 10; i++) //输出未交换时数组各元素的值 { printf("%d ", a[i]); } printf("\n"); inv(a, 10); //调用函数 for (int i = 0; i < 10; i++) //输出交换后数组各元素的值 { printf("%d ", a[i]); } } void inv(int x[], int n) //形参x是数组名 { int temp; for (int i = 0; i < (n - 1) / 2; i++) { int j = n - 1 - i; temp = x[i]; x[i] = x[j]; x[j] = temp; } }

运行结果:

分析:

程序分析:在main函数中定义整型数组 a,并赋予初值。函数 inv 的形参数组名为 x。在定义 inv 函数时,可以不指定形参数组 x 的大小(元素的个数)。因为形参数组名实际上是一个指针变量,并不是真正地开辟一个数组空间(定义实参数组时必须指定数组大小,因为要开辟相应的存储空间)。inv 函数的形参 n 用来接收需要处理的元素的个数。在 main 函数中有函数调用语句 “inv(a,10);",表示要求对 a 数组的 10 个元素实行题目要求的颠倒排列。如果改为 “inv(a,5);",则表示要求将 a 数组的前 5 个元素实行颠倒排列,此时,函数 inv 只处理5个数组元素。

(2)形参用指针变量名

#include int main() { void inv(int* x, int n); //函数声明 int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; for (int i = 0; i < 10; i++) //输出未交换时数组各元素的值 { printf("%d ", a[i]); } printf("\n"); inv(a, 10); //调用函数 for (int i = 0; i < 10; i++) //输出交换后数组各元素的值 { printf("%d ", a[i]); } } void inv(int* x, int n) //形参x是指针变量 { int temp; int* i = x; int* j = x + n - 1; for (; i < x + (n - 1) / 2; i++, j--) { temp = *i; *i = *j; *j = temp; } }

运行结果:

三、总结 3.1归纳

如果有一个实参数组,要想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下 4 种情况。

(1)实参和形参都用数组名

int main() { void f(int x[], int n); int a[10]; ... f(a, 10); //实参用数组名 ... } void f(int x[], int n) //形参用数组名 { ... }

(2)实参用数组名,形参用指针变量

int main() { void f(int* x, int n); int a[10]; ... f(a, 10); //实参用数组名 ... } void f(int* x, int n) //形参用指针变量 { ... }

(3)实参和形参都用指针变量

int main() { void f(int* x, int n); int a[10]; int* p = a; ... f(p, 10); //实参用指针变量 ... } void f(int* x, int n) //形参用指针变量 { ... }

(4)实参用指针变量,形参用数组名

int main() { void f(int x[], int n); int a[10]; int* p = a; ... f(p, 10); //实参用指针变量 ... } void f(int x[], int n) //形参用数组名 { ... } 3.2用指针变量作实参、形参举例

改写(二)中的实例

#include int main() { void inv(int* x, int n); //函数声明 int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = a; for (int i = 0; i < 10; i++) //输出未交换时数组各元素的值 { printf("%d ", a[i]); } printf("\n"); inv(p, 10); //调用函数 for (int i = 0; i < 10; i++) //输出交换后数组各元素的值 { printf("%d ", a[i]); } } void inv(int* x, int n) //形参x是指针变量 { int temp; int* i = x; int* j = x + n - 1; for (; i < x + (n - 1) / 2; i++, j--) { temp = *i; *i = *j; *j = temp; } }

运行结果:

3.3用指针变量作实参,数组名作形参举例

对数组 a[10] 由大到小进行排序,采用选择排序的算法

#include int main() { void sort(int x[], int n); //函数声明 int a[10] = { 1,3,5,7,9,2,4,6,8,10 }; int* p = a; for (int i = 0; i < 10; i++) //输出未交换时数组各元素的值 { printf("%d ", a[i]); } printf("\n"); sort(p, 10); //调用函数 for (int i = 0; i < 10; i++) //输出交换后数组各元素的值 { printf("%d ", a[i]); } } void sort(int x[], int n) { for (int i = 0; i < n - 1; i++) //i的取值范围[0,n-1) { int max_idx = i; //记录最大数值所在位置 for (int j = i + 1; j < n; j++) //j的取值范围[1,n) { if (x[j] > x[max_idx]) { max_idx = j; } //更新最大值所在位置 } if (max_idx != i) //进行交换 { int temp; temp = x[i]; x[i] = x[max_idx]; x[max_idx] = temp; } } }

运行结果:

上面 sort 函数中是用数组名作为形参,也可以用指针变量作为形参

void sort(int* x, int n) { for (int i = 0; i < n - 1; i++) //i的取值范围[0,n-1) { int max_idx = i; //记录最大数值所在位置 for (int j = i + 1; j < n; j++) //j的取值范围[1,n) { if (*(x + j) > *(x + max_idx)) { max_idx = j; } //更新最大值所在位置 } if (max_idx != i) //进行交换 { int temp; temp = *(x + i); *(x + i) = *(x + max_idx); *(x + max_idx) = temp; } } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3