Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

malloc 2

Status
Not open for further replies.

Rmcta

Technical User
Nov 1, 2002
478
0
0
US
I am trying to understand how to use malloc, calloc and realloc.
I am getting the following error for below code: error C2440: '=' : cannot convert from 'void *' to 'char *'
Conversion from 'void*' to pointer to non-'void' requires an explicit cast

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

main()
{
char mychar[]= "This is a test";

char *p;

p=malloc(sizeof(mychar)+ 20);

if(p== NULL)

printf("Error: memory allocation did not work!");



printf("%d", sizeof(mychar));

return 0;

}

What is wrong?
 
look at the prototype for malloc:

Code:
void *malloc(size_t size);

malloc returns a void*, and you are assigning it to a char*. Many compilers won't care about this, but apparently yours does.

>> Conversion from 'void*' to pointer to non-'void' requires an explicit cast

This means that you need to explicitly cast the return value of malloc to a char* like:

Code:
p = (char *) malloc(sizeof(mychar)+20);
 
Thank you! You are 100% correct.

So I wrote the following code to practice but I have a 2 questions. Looking at the output:
1) why does p[2] hold -33686019 in the first group
2) why after I clear the memory (see second group) p3 and p4 still hold their value?

#include <stdio.h>
#include <stdlib.h> /* required for the malloc and free functions */


int main()
{
int *p;
int i;

p=(int *)calloc(3, sizeof(int)); /*I had to add (int *) for my compiler */

if (p==NULL)
{printf("Did not work!");
return 1;}

else

p[0] = 11;
p[1] = 12;
p[2] = 13;

/* now i realize i need more space */

p = (int *)realloc(p, sizeof(int) *2); /*had to cast using (int *) */

p[3] = 14;
p[4] = 15;


for(i=0 ; i<5 ; i++)
printf("p[%d] holds %d\n", i, p);

realloc(p,0); /* same as free(p); */
printf("\n\n");

for(i=0 ; i<5 ; i++)
printf("p[%d] holds %d\n", i, p);


return 0;

}

HERE IS MY OUTPUT:

p[0] holds 11
p[1] holds 12
p[2] holds -33686019
p[3] holds 14
p[4] holds 15


p[0] holds -572662307
p[1] holds -572662307
p[2] holds -572662307
p[3] holds 14
p[4] holds 15


 
Code:
   p = (int *)realloc(p, sizeof(int) *2); /*had to cast using (int *) */
doesn't allocate space for 2 additional integers, it allocates space for exactly 2 integers, so p now points to space that is 2 integers in size. Essentially what you have done with this realloc statement is free 1 integer size of memory (p[2]) making the value at that location indeterminate or in this case -33686019.

Next, you initialize the memory at p[3] and p[4] to the values 14 and 15, this is not memory that you have allocated, so the results are indeterminate, it appears that it has worked, but this is a buffer overflow (you have accessed memory outside of the bounds of your buffer) and can cause all kinds of problems that can be difficult to track down.

Finally, you free the memory with the realloc(p,0) statement. What you are doing is freeing the memory you have allocated, corresponding to p[0] and p[1]. This results in all values p[0]..p[4] being indeterminate, hence the seemingly illogical output. That's what happens when you begin overflowing buffers and accessing memory you don't have allocated, you end up with indeterminate results, program/system crashes etc.

This is a classic example of buffer overflow.

Hope that makes sense. Good luck.
 
> Conversion from 'void*' to pointer to non-'void' requires an explicit cast
Yeah, it means you're compiling your C program with a C++ compiler.

> p = (int *)realloc(p, sizeof(int) *2);
You should always use a temp pointer when calling realloc
Code:
void *temp = realloc(p, sizeof(int) *2); 
if ( temp == NULL ) {
  // no new memory, but at least you've still got your
  // original memory pointed to by p
} else {
  p = temp;
}

--
 
Thank you Salem.

This part of the code then is ok:
include <stdio.h>
#include <stdlib.h> /* required for the malloc and free functions */


int main()
{
int *p;
int i;

p=(int *)calloc(3, sizeof(int)); /*I had to add (int *) for my compiler */

if (p==NULL)
{printf("Did not work!");
return 1;}

else

p[0] = 11;
p[1] = 12;
p[2] = 13;

now...I decide I need to store 2 more int 14 and 15 so I know I need to use realloc.

I create a new pointer called temp.

Can you tell me what exactly I am doing with the following code:

void *temp = realloc(p, sizeof(int) *2);


 
>> Can you tell me what exactly I am doing with the following code:

>> void *temp = realloc(p, sizeof(int) *2);

What you are doing (as Salem wisely suggested) is using a temporary pointer instead of p to attempt the memory reallocation. The reason for doing this is that if the realloc fails and returns NULL, if you don't use the temp pointer, you have lost the value of your pointer p and can no longer access or free the memory that was created with your calloc statement.

What may add to your confusion is that temp is declared as a void pointer (void *temp) rather than a int pointer (int *temp). It could just as easily have been:

Code:
int *temp = (int *) realloc(p, sizeof(int) *2);

One other thing about what you are doing: you started out by allocating space for 3 integers and then decided you needed space for 2 more, your realloc statement shouldn't be
Code:
void *temp = realloc(p, sizeof(int) *2);
This leaves you with space for only 2 integers, not 5. Your realloc statement should be:
Code:
void *temp = realloc(p, sizeof(int) *5);
Which gives you the space for 5 integers, the original 3 plus 2 more.
 
Thank you itsgsd for your great explanation.

After I issue:
void *temp = realloc(p, sizeof(int) *5);

are pointer p and temp pointing to the same location?
is it the same to say:
p[1], p[2], p[3], p[4], p[5] or
temp[1], temp[2], temp[4], temp[5] ?



 
> are pointer p and temp pointing to the same location?
temp may be
- NULL (realloc failed)
- the same as p (the block changed size without moving)
- different from p (the block is now in a different place)
Study the code I posted last time.

Figure out why there is a
temp == NULL comparison
and a
p = temp assignment

> temp[1], temp[2], temp[4], temp[5] ?
No you can't do that - temp is a void pointer, which means you cannot dereference it.

--
 
Would this be correct then?

void *temp = (int *)realloc(p, sizeof(int) *5);
if (temp ==NULL)
{printf("Reallocation did not work!");
return 1;}

else
p = (int *)temp;

p[3] = 144;
p[4] = 15;

 
> Would this be correct then?
Yes.

Except for the unnecessary casts of the return result of realloc, caused by compiling a C program with a C++ compiler (as discussed).

--
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top