Search code examples
carraysfunctiondynamic-memory-allocation

Unexpected outputs, why?


This is simple, I am allocating a dynamic 2d array using functions. I limited the scanf() len and my problem is when input a value over the limit, something weird happen.

Example
Input: 111,222,333,444
Expected output: 11,22,33,44
Real output: 11,12,33,34

#include <stdio.h>
#include <stdlib.h>
#define gd 2

void get_mem(int ***arr);
void get_data(int **arr);

int main(){
    int **arr;
    arr = NULL;
    get_mem(&arr);
    get_data(arr);
    free(*arr);
    return 0;
}

void get_mem(int ***arr){
    int i;
    *arr =  (int**)malloc(gd*sizeof(int*));

for(i=0;i<5;i++){
    (*arr)[i] = (int*)malloc(gd*sizeof(int));
}
printf("oki\n");
}

void get_data(int **arr){
    int c,f;
    for(c=0;c<gd;c++){
        for(f=0;f<gd;f++){
            scanf("%2d",&*(*arr+c)+f);
            fpurge(stdin);
            fflush(stdin);          
        }
    }    
for(c=0;c<gd;c++){
    for(f=0;f<gd;f++){
        printf("%d ",*(*arr+c)+f);
        printf("\n");
    }

  }
}

Solution

  • The value of macro gd is 2. In get_mem(), allocating memory for 2 int *:

        *arr =  (int**)malloc(gd*sizeof(int*));
    

    and below it, accessing arr beyond it size:

    for(i=0;i<5;i++){    //allocating memory to 5 int pointers
              ^^
        (*arr)[i] = (int*)malloc(gd*sizeof(int));
    }
    

    Accessing an unallocated memory is undefined behaviour.

    Instead of using magic number 5 in the loop condition, you should check i with gd, like this

    for(i=0;i<gd;i++){
    

    In get_data(), the way you are accessing elements of arr for input is wrong

    scanf("%2d",&*(*arr+c)+f);
                ^^^^^^^^^^^^ 
    

    because

    &arr[c][f] --> &(*(arr[c] + f) --> &(*(*(arr + c) + f)) --> &*(*(arr + c) + f) --> (*(arr + c) + f)
    

    Note: The operator & is used to get the address and the operator * is used for dereferencing. These operators cancel the effect of each other when used one after another. Hence, &(*(arr + i)) is equivalent to arr + i.

    That means, &arr[c][f] is equivalent to (*(arr + c) + f) and you should use &arr[c][f] which is less error prone and more readable:

    for(f = 0; f < gd; f++) {
        scanf("%2d", &arr[c][f]);
    

    Same mistake you have made while printing the arr elements in second for loop:

    for(f=0;f<gd;f++){
        printf("%d ",*(*arr+c)+f);
                     ^^^^^^^^^^^
    

    It should be *(*(arr + c) + f). More readable form is arr[c][f]:

    for(f = 0; f < gd; f++){
        printf("%d ", arr[c][f]);
    

    You should not use fflush() for input stream. It's undefined behavior. From C Standards#7.21.5.2p2 -

    If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.

    Also, fpurge() is nonstandard and not portable. Moreover, you don't need to use either of them.