Miguel Humberto
Miguel Humberto

Reputation: 21

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

  }
}

Upvotes: 0

Views: 120

Answers (2)

H.S.
H.S.

Reputation: 12669

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.

Upvotes: 4

Shubham
Shubham

Reputation: 1153

Rather than using more & more pointers, I'd like to do it in this way:-

#include <stdio.h>
#include <stdlib.h>
//#define gd 2
#define ROW 2
#define COLUMN 2

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

int main(){
    int **arr = NULL;
    get_mem(&arr);
    printf("Enter 4 int values: ");
    get_data(arr);
    free(*arr);
    return 0;
}

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

    for(i = 0; i < COLUMN; i++)
    {
        (*arr)[i] = ( int * )malloc( COLUMN * sizeof(int) );
    }
    printf("Okay!\n");
}

void get_data(int **arr)
{
    int c, f;
    for(c = 0; c < ROW; c++)
    {
        for(f = 0; f < COLUMN; f++)
        {
            scanf("%2d", &arr[c][f]);   //*(*arr+c)+f)
        }
    }
    for(c = 0; c < ROW; c++)
    {
        for(f = 0; f < COLUMN; f++)
        {
            printf("%d ", arr[c][f]);   //*(*arr+c)+f)
        }
        putchar('\n');
    }
}

I don't know what that gd is but it was making code ambiguous so I removed that and replaced it with ROW & COLUMN everywhere in the program(where it was necessary).

After allocating space to int **arr via get_mem() function, at least ask the user to input values and use proper spacing & indenting.

There's no need of fflush or fpurge, so I removed them. Now, here if you're accessing array this way you need to be very careful of using parenthesis at proper places. You should use *(*(arr+c)+f) instead of *(*arr+c)+f)(It was an error.) this. But I chose to access the elements or store values as we do in 2D arrays. That's easier.

If you want to access this array using pointers only, instead of arr[c][f] you can do it in this way:-

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

&

printf("%d ", *(*(arr+c)+f));

Note: Also, you should check for any error while allocating memory.

Hope, it helps.

Upvotes: 2

Related Questions