Search code examples
arrayscdynamic-memory-allocationrealloc

Dynamically expandable array in c


I wanted to expand an array dynamically as the user enters the values using below code.

#include<stdio.h>
#include<stdlib.h>

int main(){
    int *number=(int *)malloc(sizeof(int)),i=0,*new_ptr;
    printf("Enter a number to store it or -1 to finish the storage\n");
    scanf("%d",number);
    while(*(number+i)!=-1){
        printf("Enter a number to store it or -1 to finish the storage:\n");
        number=(int *)realloc(number,sizeof(number)+sizeof(int));
        i++;
        scanf("%d",number+i);
    };
    for(int j=0;j<i;j++){
        printf("%d ",number[j]);
    };
    return 0;
}

it gives this output

Enter a number to store it or -1 to finish the storage
1
Enter a number to store it or -1 to finish the storage:
2
Enter a number to store it or -1 to finish the storage:
3
Enter a number to store it or -1 to finish the storage:
4
Enter a number to store it or -1 to finish the storage:
5
Enter a number to store it or -1 to finish the storage:
6
Enter a number to store it or -1 to finish the storage:
7
Enter a number to store it or -1 to finish the storage:
8
Enter a number to store it or -1 to finish the storage:
9
Enter a number to store it or -1 to finish the storage:
0
Enter a number to store it or -1 to finish the storage:
-1
1 2 3 4 5 6 7 8 540155953 540287027

the junk file values happens only when the number of user input is greater than 8. Why it happens and how to fix it?


Solution

  • There were a few small issues with the original code. Junk values got printed because the original code invoked undefined behavior. Specifically, realloc() was not allocating enough space in the old logic. realloc() needs to know new total space.

    Original code was always realloc()ing sizeof(number)+sizeof(int)... which translates to sizeof(int *) + sizeof(int).

    That combo results in a constant which does not grow. This may at least partly explain why you could get OK performance until the array actually needed more space than sizeof(int *) + sizeof(int). The new code fixes that by updating the allocation size logic.

    Other adds/updates:

    • we check return of scanf() (best practice)
    • we check return of realloc() before applying it to our number pointer so we don't lose the number pointer reference.
    • we do not cast realloc() return to (int *), it is not required
    • Other improvements documented in comments.
    • This code is a conglomerate and manifestation of several great points made by the community, as well as some uniquely my own. Please enjoy:
        #include <stdio.h>
        #include <stdlib.h>
    
        int main()
        {
            int *number=malloc(sizeof(int)), *temp, i=0,j, sres,scap;
          
            if(!number)
            {
                /* malloc() problem.  Alert user and exit. */
                printf("Coule not allocate memory!\n");
                return 0;
            }
    
            /* The do / while() loop design eliminates redundancy of the 
            ** scanf() prompt and fetch.  We prompt user and scan() 
            ** in a single code block. */
            do {
                printf("Enter a number to store it or -1 to finish the storage:\n");
                /* Use a separate, new variable to capture the scanf() input */
                sres = scanf("%d", &scap); /* Added: always check the return of scanf()*/
                if(sres!=1)
                {
                    /* scanf() problem.  Alert user and exit. */
                    printf("scanf() error!\n");
                    return 0;
                }
                /* New logic/sequence.  If the captured value is not -1, store and continue*/
                if(scap != -1)
                {
                    number[i++] = scap;  /* Store input to array */
                    /* Updated allocation size logic: (i+1) means current count + next input: */
                    temp = realloc(number, (i+1)*sizeof(number)); 
                    if(temp)
                    {
                        /* Preserve number pointer.  Only assign new 
                        ** memory if allocation was successful*/
                        number = temp; 
                    }
                    else
                    {
                        /* realloc() problem.  Alert user and exit. */
                        printf("Coule not allocate memory for next input!\n");
                        return 0;
                    }
                }
            }while(scap != -1);  /* Condition modified to adapt to new logic*/
    
            for(j=0;j<i;j++)
            {
                printf("%d ",number[j]);
            }
    
            return 0;
        }
    
    
    Output:
    
    
    Enter a number to store it or -1 to finish the storage:
    1
    Enter a number to store it or -1 to finish the storage:
    2
    Enter a number to store it or -1 to finish the storage:
    3
    Enter a number to store it or -1 to finish the storage:
    4
    Enter a number to store it or -1 to finish the storage:
    5
    Enter a number to store it or -1 to finish the storage:
    6
    Enter a number to store it or -1 to finish the storage:
    7
    Enter a number to store it or -1 to finish the storage:
    6
    Enter a number to store it or -1 to finish the storage:
    5
    Enter a number to store it or -1 to finish the storage:
    4
    Enter a number to store it or -1 to finish the storage:
    3
    Enter a number to store it or -1 to finish the storage:
    2
    Enter a number to store it or -1 to finish the storage:
    1
    Enter a number to store it or -1 to finish the storage:
    -1
    1 2 3 4 5 6 7 6 5 4 3 2 1