1.问题描述
对于给定的数组,求出该数组中各个元素之和。程序如下:
# include "stdio.h"
void main()
{
double arr[] = {1,2,3,4,5}; // 给定数组
int length = sizeof(arr) / sizeof(arr[0]); // 数组长度
double sum = 0; // 用于记录数组元素之和
for(int i = 0; i < length; i++)
sum += arr[i];
printf("sum = %.4lf\n", sum); // 显示数组元素之和
getchar();
}
上述程序中,给定数组arr,其中有5个元素,求出数组长度,然后定义变量sum(double类型),用于记录数组中元素的累加之和。依次对数组中各元素进行累加,将最后得到的sum输出如下:
可知,数组中元素之和为15,结果正确。
为了将数组元素求和的功能进行独立,新建函数GetSum,将相应功能集成到该函数中,然后在主程序中调用该函数。程序如下:
# include "stdio.h"
double GetSum(double arr[])
{
int length = sizeof(arr) / sizeof(arr[0]);
double sum = 0;
for(int i = 0; i < length; i++)
sum += arr[i];
return sum;
}
void main()
{
double arr[] = {1,2,3,4,5};
double sum = GetSum(arr);
printf("sum = %.4lf\n", sum);
getchar();
}
运行结果如下:
发现结果为0,不符合预期。
2.问题原因
考虑可能是函数GetSum的声明和调用过程中出了问题,所以对函数GetSum中的步骤进行分析。
2.1在函数中求数组长度遇到的问题
首先是求数组的长度。为了探究该步骤的执行过程,新建函数PrintLength,用于显示数组长度,然后对给定的数组进行运算:
# include "stdio.h"
void PrintLength(double arr[])
{
printf("sizeof(arr) = %d\n", sizeof(arr)); // arr的大小
printf("sizeof(arr[0]) = %d\n", sizeof(arr[0])); // arr[0]的大小
printf("sizeof(arr) / sizeof(arr[0]) = %d\n", sizeof(arr) / sizeof(arr[0])); // 希望求得数组arr的长度
getchar();
}
void main()
{
double arr[] = {1,2,3,4,5};
PrintLength(arr);
}
运行上述程序,结果如下:
由上图可知,arr的所占空间为4字节,arr[0]所占空间为8字节,不符合给定的数组长度。
而两个整型变量相除(整数相除,结果会自动取整),将其结果赋值给一个双精度浮点数,于是结果显示为0。
2.2函数中数组参数的含义
2.2.1查阅资料发现的问题
查阅书籍《C Primer Plus》,在“数组和指针”章节找到一句话:“数组名是该数组首元素的地址”,所以考虑,在上述函数中,“arr”可能表示为数组arr首元素的地址,其类型为指针变量。
2.2.2对问题的探索和猜测
由于数组arr中的元素为double类型,查询double类型数据所占空间:
void main()
{
printf("sizeof(double) = %d\n", sizeof(double));
getchar();
}
输出结果如下:
可知,double类型数据所占空间为8字节。
查询指针类型数据所占空间:
void main()
{
double *ptr;
printf("sizeof(ptr) = %d\n", sizeof(ptr));
getchar();
}
输出结果如下:
可知,指针类型数据所占空间为4字节,与上述“sizeof(arr)”计算结果相等。
所以,“arr”在函数中,很可能被视为一个指针变量,该变量占据的空间为4字节。
2.2.3对猜测的验证
为了验证上述结论,将“arr”视为一个指针变量,查询其指向的地址与该地址所保存的数值,对比数组arr中第一个元素的地址和数值,程序如下:
# include "stdio.h"
void PrintArr(double arr[])
{
printf("arr = %p\n", arr); // 指针变量arr所指向的地址
printf("*arr = %lf\n", *arr); // 指针变量arr指向地址中所保存的数值
printf("&arr[0] = %p\n", &arr[0]); // 数组元素arr[0]的地址
printf("arr[0] = %lf\n", arr[0]); // 数组元素arr[0]的数值
getchar();
}
void main()
{
double arr[] = {1,2,3,4,5};
PrintArr(arr);
}
输出结果如下:
可见,指针变量“arr”所指向的地址与数组arr中第一个元素的地址相同,指针变量“arr”指向地址中保存的数值与数组arr中第一个元素的数值相等。因此得出结论:当将数组名称作为函数的输入参数时,该数组名称在函数中被视为一个指针变量,指向该数组中第一个元素的地址。
3.解决方案
由于在函数中无法求出数组长度,所以对程序作出更改:在调用函数前,先行求出数组长度,然后将数组长度作为函数的一个参数进行输入。更改后的程序如下:
# include "stdio.h"
double GetSum(double arr[], int length) // 在函数声明中,将数组长度作为输入参数
{
double sum = 0;
for(int i = 0; i < length; i++)
sum += arr[i];
return sum;
}
void main()
{
double arr[] = {1,2,3,4,5};
int length = sizeof(arr) / sizeof(arr[0]); // 在调用函数前,先求出数组长度
double sum = GetSum(arr, length); // 调用函数时,将数组长度作为参数进行输入
printf("sum = %.4lf\n", sum);
getchar();
}
运行该程序,输出结果如下:
结果正确。