简体   繁体   中英

Wrong values inside of array

I am a new C-Language learner and faced 2 problems. (Written in the same page because I think it's the same root cause for both)

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]);
}

I read that in case we don't provide a value to a newly created array it gets a default value of 0 inside all of its cells. But when I print the result it showed:

[0],[0]:0
[0],[1]:4201072
[0],[2]:6422224
[1],[0]:6422280
[1],[1]:6422476
[1],[2]:1977208000

Second, the following code returns a totally unexpected value (The Average) of 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 );

Objects defined inside functions without static or _Thread_local are not automatically initialized and have indeterminate values. To ensure the array mrr is initialized, define it with int mrr[2][3] = { 0 }; , which will initialize it to all zeros.

The code in the second question is incomplete, but, presumably, the array is defined in the calling function and is not initialized, so its values are indeterminate.

By default, [the values of] an array defined inside a function (ie a local array) is indeterminate. Global (ie static) variables, on the other hand, are initialized to 0 by default. See this related post: initial value of int array in C

To address your issue, simply initialize your array manually, with something like

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]);
    }
}

Your question about uninitialized variables is well-covered by the comments and other answers; this answer is for your second question, about the unexpected output from getAverage() .

You define balance as an array of double , but getAverage() is expecting an array of int . When I change:

double getAverage(int arr[], int size) { ... }

to:

double getAverage(double arr[], int size) { ... }

I get the expected result: 215.2. The implicit type-conversion [1] in your original code is causing the unexpected behavior.

Also, I don't know what compiler you are using, but when I compiled your original code [2], gcc threw this warning:

warning: incompatible pointer types passing 'double [5]' to parameter of type 'int *'

... which is a dead give-away that trouble is brewing. If your compiler doesn't generate this warning, or if you have warnings suppressed, or if they are logged to a file or something that you aren't looking at, I recommend making them visible again; paying attention to compiler warnings has saved me untold hours of grief.

[1] "type conversion" isn't maybe the best term here; type conversion is generally benign, even though there are some gotchas; what's happening here is that the bytes that make up the double value are being read as an int , and the byte structure of those two data types is very different; that's why the output of your original code makes it seem like it's dealing with such crazy-large numbers : eg, the bytes used to represent "17" as a double when read as an int become a very, very different number. Worse, stepping through the bytes that make up an array of double values as if it were an array of int values, it probably isn't even looking at the array elements at the proper element boundaries. In short, the type disparity is causing havoc.

[2] By "original code" I mean your code with enough overhead code to make it compile, like include pragmas and a main() body; I agree in general with the other comments about providing a complete, minimal example.

This supplemental answer is in response to the OP's comment on my earlier answer. Defender asks:

"I have some questions left. If it's expecting an array of type int and i sent double why this would change the result in 360 degrees. I still didn't get an answer to that."

It'll be easier to illustrate this with a type clash between short int and int , but the same idea applies to int vs. double .

Take a look at this code:

#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");
   }
}

which produces this output:

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

The first two lines of output show that on my machine, short int takes 2 bytes of memory and int takes 4 bytes.

functionA() is expecting a short int array, and when I send it a short int[] , we see the expected output. The bytes that make up the first element of the array are 0x0a 0x00 , which in decimal is "10"; the bytes that make up the second element of the array are 0x14 0x00 , which in decimal is "20"; and so on.

But when I send functionA() an int[] , I'm sending 4 bytes per element, so when it iterates through the array, it doesn't see the elements correctly. It does okay with the first element, but only because it's a small number; when it looks for the second element, it is actually looking at the last two bytes of the first element, so it sees 0x00 0x00 , or "0"; when it looks for the third element it is looking at the first two bytes of the second element, and sees 0x14 0x00 , or "20"; and so on.

Another way to show it is that the bytes of shortdata are this:

0a 00 14 00 32 00 64 00

and the bytes of intdata are this:

0a 00 00 00 14 00 00 00 32 00 00 00 64 00 00 00

Because functionA() is expecting a short int[] , it treats intdata that way -- two bytes per element -- and sees as its elements:

arr[0] : 0a 00
arr[1] : 00 00
arr[2] : 14 00
arr[3] : 00 00

It's a similar story with your code. Your getAverage() is expecting a int[] , so when you send it a double[] , it is not seeing the bytes the way you intend.

(The clash between int and double is even more drastic than between short int and int ; this is because in addition to being different sizes (on most modern machines, int is 4 bytes and double is 8 bytes), floating-point numbers are stored as an exponent and a mantissa -- so the byte values have an entirely different meaning.)

I hope this explanation helps, and I encourage you to experiment with the code above, and read about the internals of C memory as it pertains to allocating and handling variables. As a new C programmer, you will gain insight in to fundamentals that will help you for as long as you continue programming in C.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM