数组内的值错误

时间:2019-06-25 19:33:59

标签: c arrays

我是一名新的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 );

4 个答案:

答案 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 intint之间的类型冲突来说明这一点会更容易,但是同样的想法也适用于intdouble

看看这段代码:

#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[]时,它并没有按照您的预期方式看到字节。

intdouble之间的冲突比short intint之间的冲突更为激烈;这是因为除了大小不同之外(在大多数现代机器上,int是4个字节,double是8个字节),浮点数存储为指数和尾数-因此字节值的含义完全不同。)

我希望这种解释会有所帮助,并鼓励您尝试上面的代码,并了解C内存的内部结构,因为它与分配和处理变量有关。作为新的C程序员,您将深入了解可以继续使用C进行编程的基础知识。