invalid realloc/realloc returns NULL

In one function I used malloc :

void name1(struct stos* s)
{
   s = malloc (4 * sizeof (int));
}

And everything is ok. But later I used realloc

void name2(struct stos* s)
{
   s->size = 2*(s->size);
   s = realloc (s, (s->size + 1) * sizeof (int));
}

and I get invalid free/delete/realloc in valgrind and realloc returns NULL.

Declaration of Structure and rest of program is:

struct stos
{
   int top;
   int size;
   int stk[];
};

void name1(struct stos* s);
void name2(struct stos* s);    

int main()
{
   struct stos stosik;
   struct stos* s;
   s = &stosik;

   name1(s);

   //some operations on the array and int top here

   name2(s);
}

What did I do wrong here? I looked for what might have gone wrong for quite long, read quite a few articles about pointers, malloc/realloc etc. but with no result. I would be really grateful, if someone could help me.

Answers


The problem is slightly subtle and caused by a combination of two things. Let's start here:

struct stos stosik;
struct stos* s;
s = &stosik;

name1(s);

First, you make s point to an a valid chunk of memory that is allocated on the stack (stosik) and then you call name1 passing into s. Let's look at what name1 looks like:

void name1(struct stos* s)
{
    s = malloc (4 * sizeof (int));
}

Hmm, we can see that name1 takes in a pointer to a struct stos called s; inside that function, we are allocating some memory and making s point to it. This is a problem.

First of all, note that s already points to a valid chunk of memory. So using a malloc here is suspicious. It will cause a subtle bug that will actually hide the real bug in your program, which is bad. So, let's remove stosik completely:

int main()
    {
    struct stos* s = NULL;

    name1(s);

    if(s == NULL)
        return -1;

Now, if you run this program, you will see that after you call name1 the variable s still points to NULL. What's happening here?

Well, we are changing the function's LOCAL copy of s (i.e. the s that exists only inside name1)... but the s in main isn't changed! Remember, that we are passing a pointer into name1 but we are passing it by value.

To do what you seem to be trying to do you can do you would have to either pass a pointer to s into name1 (that is, to pass a double pointer) or you should return the result of the malloc from name1 as a return value. Let's look at each of these options:

Passing s in via a double pointer
void name1(struct stos **s)
    {
    /* sanity check */
    if(s == NULL)
        return; 

    /* now, allocate enough space for four integers and make 
     * whatever s points to, point to that newly allocated
     * space.
     */
    *s = malloc(4 * sizeof(int));
}

And calling it from main requires us to use the "address-of" operator:

struct stos *s = NULL;

/* we need to pass a pointer to s into name1, so get one. */
name1(&s);

/* malloc can fail; check the result! */
if(s == NULL) 
    return -1;
Returning a pointer to the allocated memory from name1
struct stos *name1()
{
    return malloc(4 * sizeof(int));
}

Calling this from main is slightly easier:

struct stos *s = name1();

/* malloc can fail; check the result! */
if(s == NULL)
    return -1;

Changing your code to what I show you here will fix this issue (but there may be others) but let me touch briefly upon something else:

The other bug

The crash you encounterd crops up partially because of the problem we just covered; another issue is that inside name2 you are calling realloc. The pointer you pass into realloc however, is not a pointer that you got back from malloc or realloc, which is what realloc expects. It points to stosik instead. So that code causes undefined behavior and after that anything can happen.

If you're lucky (it seems you were), it will just crash right then and there and if you're not... well, who knows what will happen?


  1. if you want to dynamically allocate s in name1 you need it to be declared as name1(struct stos** s) and pass pointer to the pointer where the allocated memory should appear.

  2. Your main allocates stosik staticaly, meaning you don't need to do any further dynamic allocation. Then when you try doing name1(statically allocated mem) it does … um, something. I don't know what, but certainly not what you expect.


Need Your Help

AS3 - Using Matrix3D objects for reordering display

actionscript-3 animation 3d z-order

I'm working with about 20 objects that are moving around in 3D space. Adobe recommends "Using Matrix3D objects for reordering display":

Collection change security with yield return statements

c# .net yield-return

Using yield return Statements I always wonder wheter to implement a version count: