我是一名新的C语言学习者,面临2个问题。 (写在同一页上,因为我认为这是两者的根本原因)
int mrr [2][3];
for (int r=0;r<2;r++)
{
for (int c=0; c<3; c++)
printf("[%d],[%d]:%d\n",r,c,mrr[r][c]);
}
我读到,如果我们不为新创建的数组提供值,它将在其所有单元格内获得默认值0。但是当我打印结果时,它显示:
[0],[0]:0
[0],[1]:4201072
[0],[2]:6422224
[1],[0]:6422280
[1],[1]:6422476
[1],[2]:1977208000
第二,下面的代码返回一个完全意外的值(平均值)431374336.000000
double getAverage(int arr[], int size) {
int i;
double avg;
double sum = 0;
for (i = 0; i < size; ++i) {
sum += arr[i];
}
avg = sum / size;
return avg;
}
double balance[5] = {1000, 2, 7, 17, 50};
double avg = getAverage(balance, 5 );
printf( "Average value is: %f ", avg );
答案 0 :(得分:1)
在内部没有static
或_Thread_local
的函数中定义的对象不会自动初始化,并且具有不确定的值。为了确保初始化数组mrr
,请用int mrr[2][3] = { 0 };
定义它,它将初始化为全零。
第二个问题中的代码不完整,但是,大概是在调用函数中定义了数组,并且未初始化,因此其值是不确定的。
答案 1 :(得分:0)
默认情况下,在函数内部定义的数组(即本地数组)的[值]是不确定的。另一方面,全局变量(即静态变量)默认情况下初始化为0。请参阅以下相关文章:initial value of int array in C
要解决您的问题,只需使用
之类的手动手动初始化数组即可。for (int r=0;r<2;r++)
{
for (int c=0; c<3; c++) {
mrr[r][c] = 0;
printf("[%d],[%d]:%d\n",r,c,mrr[r][c]);
}
}
答案 2 :(得分:0)
您的关于未初始化变量的问题已被注释和其他答案很好地涵盖了;这个答案是您的第二个问题,关于getAverage()
的意外输出。
您将balance
定义为double
的数组,但是getAverage()
期望的是int
的数组。当我改变时:
double getAverage(int arr[], int size) { ... }
收件人:
double getAverage(double arr[], int size) { ... }
我得到了预期的结果:215.2。原始代码中的隐式类型转换[1]导致了意外行为。
此外,我不知道您使用的是什么编译器,但是当我编译原始代码[2]时,gcc
发出以下警告:
warning: incompatible pointer types passing 'double [5]' to parameter of type 'int *'
...这是麻烦正在酝酿中的致命一击。如果您的编译器没有生成此警告,或者您取消了警告,或者如果警告已记录到文件或您未查看的内容中,则建议再次使它们可见。注意编译器警告为我节省了无数小时的痛苦。
[1]“类型转换”可能不是这里的最好用语。即使存在一些陷阱,类型转换通常也是良性的;这里发生的是,构成double
值的字节被读为int
,并且这两种数据类型的字节结构非常不同;这就是为什么原始代码的输出看起来好像正在处理如此疯狂的数字:例如,当以int
读取时,用于将“ 17”表示为双精度的字节变得非常不同。更糟糕的是,逐步检查构成double
值数组的字节,就好像它是int
值数组一样,它甚至可能根本不在适当元素边界处查看数组元素。简而言之,类型差异会造成严重破坏。
[2]“原始代码”是指您的代码具有足够的开销代码来进行编译,例如include
编译指示和main()
主体;我总体上同意关于提供完整的最小示例的其他评论。
答案 3 :(得分:0)
此补充答案是针对OP对我先前的回答的评论。防御者问:
“我还有一些问题。如果期望一个int类型的数组,并且我发送了为什么会在360度范围内更改结果的信息,我发送了两次。我仍然没有得到答案。”
使用short int
和int
之间的类型冲突来说明这一点会更容易,但是同样的想法也适用于int
与double
。
看看这段代码:
#include <stdlib.h>
#include <stdio.h>
void functionA(short int[], int size);
int main(void) {
printf("sizeof short int : %lu\n", sizeof(short int));
printf("sizeof int : %lu\n", sizeof(int));
printf("\n\n");
printf("==== sending short int to functionA() ====\n");
short int shortdata[4] = {10, 20, 50, 100};
functionA(shortdata, 4);
printf("==== sending int to functionA() ====\n");
int intdata[4] = {10, 20, 50, 100};
functionA(intdata, 4);
}
void functionA(short int arr[], int size) {
int i;
char* ptr;
for (i = 0; i < size; ++i) {
ptr = &arr[i];
printf("bytes of 'arr[%d]' : %x %x\n", i, *ptr, *(ptr+1));
printf("value of 'arr[%d]' : %d\n", i, arr[i]);
printf("\n");
}
}
产生以下输出:
sizeof short int : 2
sizeof int : 4
==== sending short int to functionA() ====
bytes of 'arr[0]' : a 0
value of 'arr[0]' : 10
bytes of 'arr[1]' : 14 0
value of 'arr[1]' : 20
bytes of 'arr[2]' : 32 0
value of 'arr[2]' : 50
bytes of 'arr[3]' : 64 0
value of 'arr[3]' : 100
==== sending int to functionA() ====
bytes of 'arr[0]' : a 0
value of 'arr[0]' : 10
bytes of 'arr[1]' : 0 0
value of 'arr[1]' : 0
bytes of 'arr[2]' : 14 0
value of 'arr[2]' : 20
bytes of 'arr[3]' : 0 0
value of 'arr[3]' : 0
输出的前两行表明,在我的机器上,short int
占用2个字节的内存,而int
占用4个字节。
functionA()
期望一个short int
数组,当我发送一个short int[]
时,我们看到了预期的输出。组成数组第一个元素的字节是0x0a 0x00
,十进制为“ 10”;组成数组第二个元素的字节是0x14 0x00
,十进制为“ 20”;等等。
但是,当我向functionA()
发送int[]
时,每个元素发送4个字节,因此,当它遍历数组时,无法正确看到元素。它对第一个元素还可以,但这仅是因为它很小。当寻找第二个元素时,实际上是在寻找第一个元素的最后两个字节,因此它会看到0x00 0x00
或“ 0”;当它寻找第三个元素时,它正在寻找第二个元素的前两个字节,并且看到0x14 0x00
或“ 20”;等等。
另一种显示方式是shortdata
的字节是这样的:
0a 00 14 00 32 00 64 00
和intdata
的字节是这样的:
0a 00 00 00 14 00 00 00 32 00 00 00 64 00 00 00
因为functionA()
期望short int[]
,所以它以这样的方式对待intdata
-每个元素两个字节–并视为其元素:
arr[0] : 0a 00
arr[1] : 00 00
arr[2] : 14 00
arr[3] : 00 00
这与您的代码类似。您的getAverage()
期望有一个int[]
,因此,当您向其发送double[]
时,它并没有按照您的预期方式看到字节。
(int
和double
之间的冲突比short int
和int
之间的冲突更为激烈;这是因为除了大小不同之外(在大多数现代机器上,int
是4个字节,double
是8个字节),浮点数存储为指数和尾数-因此字节值的含义完全不同。)
我希望这种解释会有所帮助,并鼓励您尝试上面的代码,并了解C内存的内部结构,因为它与分配和处理变量有关。作为新的C程序员,您将深入了解可以继续使用C进行编程的基础知识。