0

i am writing a file copy program,in which i faced difficulty regarding realloc(). Please look at the following snippet (which i write to understand the working of realloc()):-

int main(){
    char *p =(char *) malloc ( 10 ),*t;
    p = "this is";
    if (strlen (p)==7)
    {
        t = realloc ( p,14);
        if ( t==NULL)
        {
            printf ("no no\n");
        }
    }
    printf("%p\n%p\n%d",p,t,strlen(p));
    free (p);
    free (t);
    return 1;
}

output

no no      //because realloc () is unable to reallocate  the memory
00450357   //address of p
00000000   //address of t

so why realloc() is unable to reallocate the memory and assign it (its address) to t?

EDIT i am using Code Blocks in windows.

OldSchool
  • 2,123
  • 4
  • 23
  • 45
  • 2
    Because you've clobbered the address returned by malloc with the string assignment. If you'd used a strcpy, then the realloc would have worked but you would get double free on the free(p) because it has already been freed during the realloc. – cup Mar 29 '14 at 09:37

3 Answers3

7

You have overwritten the value returned by malloc by address of a static string. Then realloc receives the address of the static string as parameter to reallocate.

char *p =(char *) malloc ( 10 ),*t;
p = "this is";
t = realloc ( p,14);

What you probably wanted is:

char *p =(char *) malloc ( 10 ),*t;
strcpy(p, "this is");
t = realloc ( p,14);
Marian
  • 7,402
  • 2
  • 22
  • 34
  • Is it overwritten due to its (string literals)type of const char * – OldSchool Mar 29 '14 at 09:45
  • The statement `p = "this is";` means that there is somewhere in the memory (and surely not on the heap) the string "this is" and its address is assigned to `p`. The string is created by compiler in compile time and it is usually located in a part of memory reserved to constants grabbed from the program code. – Marian Mar 29 '14 at 09:49
  • if we use integer array then case would be diffrent?isnt it? – OldSchool Mar 29 '14 at 09:52
  • Not sure to understand the point about integer array. The point is that you have to call `realloc` with a pointer obtained from `malloc`. In your case you have obtained a pointer from malloc, but then got another pointer (and assigned it to `p`) and called `realloc` with this different pointer. – Marian Mar 29 '14 at 09:59
  • as i have written free() (at the end of program)for both p and t.is it okay if i write it only for t? – OldSchool Mar 29 '14 at 10:10
  • Not really. `realloc` is freeing `p` but only in case it is called. In your example you shall free `t` in the branch calling `realloc` and `p` in the branch not calling it. – Marian Mar 29 '14 at 10:14
  • It is hard to say it simpler. Your program has two branches. In one branch you allocate `p`, then reallocate it to `t`. In this branch only `t` has to be freed. In another branch (if the string size isn't equal to 7) you do not reallocate anything to `t` and you need to free `p`. – Marian Mar 29 '14 at 10:21
2

After allocating to p you are doing

p = "this is";

which overrides the value returned by malloc(). And as memory pointed by p is not free-able the realloc() fails.

To copy the string do

strcpy(p, "this is");

although check p has enough memory allocated, otherwise use

strncpy(p, "this is", length_of_p);
Rohan
  • 52,392
  • 12
  • 90
  • 87
  • but if we have integer type pointer to store pointer returned by malloc and we use a loop to store value at that address as *p++=2.then it is also reallocatable so why here it is not? – OldSchool Mar 29 '14 at 09:51
1

The man page of realloc states that unless the first argument of realloc is NULL, it must have been returned by an earlier call to malloc, calloc, or realloc.

t = realloc (p, 14);

The above statement passes p to realloc, which points to the string literal "this is", which has static storage duration and is read-only though not const qualified. As such, your program invokes undefined behaviour. (It crashed on my machine due to segfault.)

Also, you lose handle on the dynamically allocated memory when you reassign p the address of the first element of the string literal, causing memory leak.

char *p =(char *) malloc ( 10 ),*t;
p = "this is";

What you actually need to do is copy the contents of the string literal to dynamically allocated buffer using strcpy.

// include the required headers

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

// explicitly state void in the parameter list of main
int main(void) {
    // do not cast the result of malloc
    char *p = malloc(10 * sizeof *p);
    char *t;
    if(p == NULL) {
        printf("malloc failed\n");
        return 1;
    }
    // beware of buffer overrun by strcpy
    // consider using the safer strncpy if it suits
    p = strcpy(p, "this is");
    if(strlen(p) == 7) {
        // save the result of realloc in t
        // in case, realloc fails to allocate
        t = realloc(p, 14);
        if(t == NULL) {
            printf("realloc failed\n");
            // handle it
            // p points to old buffer
        }
        else {
            t = NULL;
            // p points to new buffer
        }
    }

    // after your done with p, free it
    free(p);

    return 0;
}
ajay
  • 9,402
  • 8
  • 44
  • 71
  • if i write t=realloc ( p,14 ) is this means that p will be freed and t points to the same starting address but its range increases? – OldSchool Mar 29 '14 at 10:27
  • 1
    @Bayant_singh No. If `realloc` is successful, it returns the same value as that of `p`. Here, we store the result of `realloc` in `t` because if `realloc` fails, then it leaves `p` unchanged and returns `NULL`. Therefore, doing `p = realloc(p, 14);` would lose the handle on older buffer causing memory leak, in case `realloc` fails. – ajay Mar 29 '14 at 10:32
  • 1
    @Bayant_singh Also, note that if `realloc` can extend the older buffer, then it will. If it cannot, then it will allocate new buffer, copy the old buffer to the new one, and then free the old buffer. Therefore, the return value of `realloc` may or may not be same in case of successful call. Please read the man page for details http://man7.org/linux/man-pages/man3/malloc.3.html – ajay Mar 29 '14 at 10:35
  • but how can i copy old buffer to new one? – OldSchool Mar 29 '14 at 10:39
  • @Bayant_singh `realloc` does it for you. That's what it is used for. When `realloc` allocates memory, it keeps the old data. – ajay Mar 29 '14 at 10:41
  • in short if i write t=realloc (p,14) t may or may not point to same starting address as that of p due to reason mentioned by you. – OldSchool Mar 29 '14 at 10:42