当前位置:嗨网首页>书籍在线阅读

12-函数、数组和指针

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

10.4 函数、数组和指针

假设要编写一个处理数组的函数,该函数返回数组中所有元素之和,待处理的是名为 marblesint 类型数组。应该如何调用该函数?也许是下面这样:

total = sum(marbles); // 可能的函数调用

那么,该函数的原型是什么?记住,数组名是该数组首元素的地址,所以实际参数 marbles 是一个存储 int 类型值的地址,应把它赋给一个指针形式参数,即该形参是一个指向 int 的指针:

int sum(int * ar);    // 对应的函数原型

sum() 从该参数获得了什么信息?它获得了该数组首元素的地址,知道要在该位置上找出一个整数。注意,该参数并未包含数组元素个数的信息。我们有两种方法让函数获得这一信息。第一种方法是,在函数代码中写上固定的数组大小:

int sum(int * ar) // 相应的函数定义
{
     int i;
     int total = 0;
     for (i = 0; i < 10; i++)    // 假设数组有10个元素
          total += ar[i];        // ar[i] 与 *(ar + i) 相同
     return total;
}

既然能使用指针表示数组名,也可以用数组名表示指针。另外,回忆一下, += 运算符把右侧运算对象加到左侧运算对象上。因此, total 是当前数组元素之和。

该函数定义有限制,只能计算10个 int 类型的元素。另一个比较灵活的方法是把数组大小作为第2个参数:

int sum(int * ar, int n)        // 更通用的方法
{
     int i;
     int total = 0;
     for (i = 0; i < n; i++)    // 使用 n 个元素
          total += ar[i];       // ar[i] 和 *(ar + i) 相同
     return total;
}

这里,第1个形参告诉函数该数组的地址和数据类型,第2个形参告诉函数该数组中元素的个数。

关于函数的形参,还有一点要注意。只有在函数原型或函数定义头中,才可以用 int ar[] 代替 int * ar

int sum (int ar[], int n);

int * ar 形式和 int ar[] 形式都表示 ar 是一个指向 int 的指针。但是, int ar[] 只能用于声明形式参数。第2种形式( int ar[] )提醒读者指针 ar 指向的不仅仅是一个 int 类型值,还是一个 int 类型数组的元素。

注意 声明数组形参 因为数组名是该数组首元素的地址,作为实际参数的数组名要求形式参数是一个与之匹配的指针。只有在这种情况下, C 才会把 int ar[]int * ar 解释成一样。也就是说, ar 是指向 int 的指针。由于函数原型可以省略参数名,所以下面 4 种原型都是等价的:

int sum(int *ar, int n);
int sum(int *, int);
int sum(int ar[], int n);
int sum(int [], int);

但是,在函数定义中不能省略参数名。下面两种形式的函数定义等价:

int sum(int *ar, int n)
{
     // 其他代码已省略
}
int sum(int ar[], int n);
{
     //其他代码已省略
}

可以使用以上提到的任意一种函数原型和函数定义。

程序清单10.10演示了一个程序,使用 sum() 函数。该程序打印原始数组的大小和表示该数组的函数形参的大小(如果你的编译器不支持用转换说明 %zd 打印 sizeof 返回值,可以用 %u%lu 来代替)。

程序清单10.10  sum_arr1.c 程序

// sum_arr1.c -- 数组元素之和
// 如果编译器不支持 %zd,用 %u 或 %lu 替换它
#include <stdio.h>
#define SIZE 10
int sum(int ar[], int n);
int main(void)
{
     int marbles[SIZE] = { 20, 10, 5, 39, 4, 16, 19, 26, 31, 20 };
     long answer;
     answer = sum(marbles, SIZE);
     printf("The total number of marbles is %ld.\n", answer);
     printf("The size of marbles is %zd bytes.\n",
          sizeof marbles);
     return 0;
}
int sum(int ar[], int n)     // 这个数组的大小是?
{
     int i;
     int total = 0;
     for (i = 0; i < n; i++)
          total += ar[i];
     printf("The size of ar is %zd bytes.\n", sizeof ar);
     return total;
}

该程序的输出如下:

The size of ar is 8 bytes.
The total number of marbles is 190.
The size of marbles is 40 bytes.

注意, marbles 的大小是40字节。这没问题,因为 marbles 内含10个 int 类型的值,每个值占4字节,所以整个 marbles 的大小是40字节。但是, ar 才8字节。这是因为 ar 并不是数组本身,它是一个指向 marbles 数组首元素的指针。我们的系统中用8字节存储地址,所以指针变量的大小是8字节(其他系统中地址的大小可能不是8字节)。简而言之,在程序清单10.10中, marbles 是一个数组, ar 是一个指向 marbles 数组首元素的指针,利用C中数组和指针的特殊关系,可以用数组表示法来表示指针 ar