0

My Query is on Dynamic memory allocation in c Programming.

I have an array for which memory is allocated dynamically, Now i got a question from one of my friend that there are 3 conditons need to be checked befor re-allocating memory to an existing array. I tried doing R&D but i am not getting appropriate answer.

Can you please help me in this. Below is the Code which i have used for allocating memory.

#include <stdio.h>
#include <stdlib.h>
int main(){
int n,i,*ptr,sum=0;
printf("Enter number of elements: ");
scanf("%d",&n);
ptr=(int*)malloc(n*sizeof(int));  //memory allocated using malloc
if(ptr==NULL)                     
{
    printf("Error! memory not allocated.");
    exit(0);
}
printf("Enter elements of array: ");
for(i=0;i<n;++i)
{
    scanf("%d",ptr+i);
    sum+=*(ptr+i);
}
printf("Sum=%d",sum);
free(ptr);
return 0;
}

Now, I want to ask user to extend memory or not, if YES then I want to re-allocate memory.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 1
    Note: Please [do not cast](http://stackoverflow.com/q/605845/2173917) the return value of `malloc()`. – Sourav Ghosh Dec 22 '14 at 06:48
  • 1
    Your friend told you that there are 3 things that need to be checked, but wouldn't tell you what they are? – Michael Burr Dec 22 '14 at 07:22
  • 1
    Was this code supposed to contain `realloc` somewhere, because so far it vaguely resembles an unfinished homework assignment. – WhozCraig Dec 22 '14 at 07:33
  • In your `for` loop you should use `i++` instead of `++i`. Otherwise you will only read in n-1 numbers, namely from 1 to n (instead of 0 to n). – Philipp Murry Dec 22 '14 at 08:17

4 Answers4

1
  1. Check if the value returned from realloc() was acceptable. Only checking for NULL is not sufficient. malloc() and fiends may successfully return NULL when the size requested is 0.

    int AmountRequested = ...;
    void * newptr = realloc(oldptr,  AmountRequested);
    if (newptr == NULL && AmountRequested > 0) {
      ; // OOM occurred, Handle error
    } else {
      newptr = oldptr; // good to go
    }
    
  2. Is the amount requested in range of 0 to SIZE_MAX? Often signed types like int are use, when size_t is best - and that is an unsigned type. Code must also insure that if it is starting from N elements and sizeof(*ptr) that the computation AmountRequested = N * sizeof(*ptr) does not exceed SIZE_MAX.

    if (N > SIZE_MAX/sizeof(*ptr)) {
      ; //Handle too big 
    }
    AmountRequested = N * sizeof(*ptr);
    // This test needed if AmountRequested is `int`, `long`, etc.
    if (AmountRequested < 0 || AmountRequested > SIZE_MAX) {
      ;  // Handle bad request size
    }
    
  3. The value of void *oldptr must be initialized or set to some valid pointer. Even NULL is OK.

    void *oldptr1;
    ... = realloc(oldptr1, newsize); // bad
    
    void *oldptr2 = NULL;
    ... = realloc(oldptr2, newsize); // OK
    
    void *oldptr3 = malloc(oldsize);
    ... = realloc(oldptr3, newsize); // OK
    

  1. Odd ball issue: If using a relic machine or maybe some new esoteric one, there is an odd situation where the number of elements and the size of the elements were both in the range of 0 to SIZE_MAX range, but there product was not. The solution was to not use realloc(), malloc(), but only calloc(). Of course the makes doing a realloc() a problem. Have not seen this issue this millennium.

    BigStructure * ptr = calloc(n, sizeof *ptr);
    
alk
  • 69,737
  • 10
  • 105
  • 255
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

The three things you want to check in order to reallocate memory for a pointer are:

  1. whether the prior allocation limit is reached;
  2. the new allocation size is greater than current; and
  3. that the call to realloc returns a valid pointer.

The last being the most informative. realloc returns a pointer to the newly allocated memory if successful, or NULL on failure. This has critical consequences for your existing data. If you attempt to realloc using the existing pointer and it fails, your pointer is set to NULL and your existing data is lost. That is why it is recommended to assign the return from realloc to a temporary pointer and test that a valid pointer is returned before assigning the return of realloc to your existing pointer.

The general approach to reallocation is to allocate a reasonable amount of memory to begin with. As memory is used, check whether the memory limit is reached. When reached realloc two times the current amount of memory to a temporary pointer and check whether a valid pointer is retured. If so, assign the new pointer to your existing pointer and update the variable you are using to track the current allocation size. (repeat as necessary)

The following incorporates each of the above. Look it over and let me know if you have questions:

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

#define MAXS 5

int main() {

    int *myarray = NULL;        /* initialize all variables */
    int *tmp = NULL;
    int asize = MAXS;
    int i = 0;

    printf ("\n Filling myarray with 30 elements (allocated 5)\n\n");

    myarray = calloc (MAXS, sizeof *myarray);   /* allocate 5 ints  */
    if (!myarray)
    {
        printf (" error: allocation failed.\n");
        exit (EXIT_FAILURE);
    }

    for (i = 0; i < 30; i++)                    /* fill w/30 ints   */
    {
        if (i == asize)                         /* test if at limit */
        {                                       /* if so realloc    */
            if ((tmp = realloc (myarray, 2 * asize * sizeof *myarray)))
            {
                myarray = tmp;                  /* if OK, reassign  */
                asize = 2 * asize;              /* update asize     */
                printf ("  => reallocated myarray, size : %d\n", asize);
            }
            else                                /* realloc failed   */
            {
                printf (" error: realloc failed.\n");
                break;
            }
        }
        myarray[i] = i;                         /* assign element   */

        printf ("  filled myarray[%2d] : %d\n", i, myarray[i]);
    }

    if (myarray) free (myarray);                /* free memory      */

    printf ("\n");

    return 0;
}

output:

$ ./bin/reallocint

 Filling myarray with 30 elements (allocated 5)

  filled myarray[ 0] : 0
  filled myarray[ 1] : 1
  filled myarray[ 2] : 2
  filled myarray[ 3] : 3
  filled myarray[ 4] : 4
  => reallocated myarray, size : 10
  filled myarray[ 5] : 5
  filled myarray[ 6] : 6
  filled myarray[ 7] : 7
  filled myarray[ 8] : 8
  filled myarray[ 9] : 9
  => reallocated myarray, size : 20
  filled myarray[10] : 10
  filled myarray[11] : 11
  filled myarray[12] : 12
  filled myarray[13] : 13
  filled myarray[14] : 14
  filled myarray[15] : 15
  filled myarray[16] : 16
  filled myarray[17] : 17
  filled myarray[18] : 18
  filled myarray[19] : 19
  => reallocated myarray, size : 40
  filled myarray[20] : 20
  filled myarray[21] : 21
  filled myarray[22] : 22
  filled myarray[23] : 23
  filled myarray[24] : 24
  filled myarray[25] : 25
  filled myarray[26] : 26
  filled myarray[27] : 27
  filled myarray[28] : 28
  filled myarray[29] : 29
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

realloc() might fail so it is better to use some temp pointer to store the return value and check whether realloc() passed or failed and later assign that pointer back to your original pointer.Also note that there is no need to cast malloc() or realloc()

I am assuming you will add the check to take input from the user whether to extend the memory or not and if memory needs to extended then by what amount.

printf("Enter 1 to extend else 0\n");
scanf("%d",&option);
if(option == 1)
{
   printf("Enter the amount\n");
   scanf("%d",&m);
   int *temp = NULL;

   temp = realloc(ptr,(m+n)*sizeof(int)); /* m is the size by which your array needs to be        extended */

   if(temp != NULL)
   ptr = temp;
}
Gopi
  • 19,784
  • 4
  • 24
  • 36
0

check the condition that is return value of realloc is not null.

if ( temp!=NULL );

Then while reallocating the memory check the new size higher than the old one. if it is a smaller one then the data of the array will be loss.

If you want to get the confirmation from the user. Enter 1 for realloction. Then check with that.

 scanf(%d",&input);
 if ( input == 1 ) //reallocation.
Karthikeyan.R.S
  • 3,991
  • 1
  • 19
  • 31