I'm new to C and haven't really grasped when C decides to free an object and when it decides to keep an object.
heap_t is pointer to a struct heap.
heap_t create_heap(){
heap_t h_t = (heap_t)malloc(sizeof(heap));
h_t->it = 0;
h_t->len = 10;
h_t->arr = (token_t)calloc(10, sizeof(token));
//call below a couple of times to fill up arr
app_heap(h_t, ENUM, "enum", 1);
return h_t;
}
putting h_t through
int app_heap(heap_t h, enum symbol s, char* word, int line){
int it = h->it;
int len = h->len;
if (it + 1 < len ){
token temp;
h->arr[it] = temp;
h->arr[it].sym = s;
h->arr[it].word = word;
h->arr[it].line = line;
h->it = it + 1;
printf(h->arr[it].word);
return 1;
} else {
h->len = len*2;
h->arr = realloc(h->arr, len*2);
return app_heap(h, s, word, line);
}
}
Why does my h_t->arr fill up with junk and eventually I get a segmentation fault? How do I fix this? Any C coding tips/styles to avoid stuff like this?
First, to answer your question about the crash, I think the reason you are getting segmentation fault is that you fail to multiply len by sizeof(token) in the call to realloc. You end up writing past the end of the block that has been allocated, eventually triggering a segfault.
As far as "deciding to free an object and when [...] to keep an object" goes, C does not decide any of it for you: it simply does it when you tell it to by calling free, without asking you any further questions. This "obedience" ends up costing you sometimes, because you can accidentally free something you still need. It is a good idea to NULL out the pointer, to improve your chance of catching the issue faster (unfortunately, this is not enough to eliminate the problem altogether, because of shared pointers).
free(h->arr);
h -> arr = NULL; // Doing this is a good practice
To summarize, managing memory in C is a tedious task that requires a lot of thinking and discipline. You need to check the result of every allocation call to see if it has failed, and perform many auxiliary tasks when it does.
C does not "decide" anything, if you have allocated something yourself with an explicit call to e.g. malloc(), it will stay allocated until you free() it (or until the program terminates, typically).
I think this:
token temp;
h->arr[it] = temp;
h->arr[it].sym = s;
/* more accesses */
is very weird, the first two lines don't do anything sensible.
As pointed out by dasblinkenlight, you're failing to scale the re-allocation into bytes, which will cause dramatic shrinkage of the array when it tries to grow, and corrupt it totally.
You shouldn't cast the return values of malloc() and realloc(), in C.
Remember that realloc() might fail, in which case you will lose your pointer if you overwrite it like you do.
Lots of repetition in your code, i.e. realloc(h->arr, len*2) instead of realloc(h->arr, h->len * sizeof *h->arr) and so on.
Note how the last bullet point also fixes the realloc() scaling bug mentioned above.
You're not reallocating to the proper size, the realloc statement needs to be:
realloc(h->arr, sizeof(token) * len*2);
^^^^^^^^^^^^
(Or perhaps better realloc(h->arr, sizeof *h->arr * h->h_len);)
In C, you are responsible to free the memory you allocate. You have to free() the memory you've malloc/calloc/realloc'ed when it's suitable to do so. The C runtime never frees anything, except when the program has terminated(some more esoteric systems might not release the memory even then).
Also, try to be consistent, the general form for allocating is always T *foo = malloc(sizeof *foo), and dont duplicate stuff.
e.g.
h_t->arr = (token_t)calloc(10, sizeof(token));
^^^^^^^^ ^^ ^^^^^^^^^^^^^
Don't cast the return value of malloc in C. It's unncessesary and might hide a serious compiler warning and bug if you forget to include stdlib.h
the cast is token_t but the sizeof applies to token, why are they different, and are they the same type as *h_t->arr ?
You already have the magic 10 value, use h_t->len
If you ever change the type of h_t->arr, you have to remember to change the sizeof(..)
So make this
h_t->arr = calloc(h_t->len, sizeof *h_t->arr);
Two main problems in creating dangling pointers in C are the not assigning
NULL to a pointer after freeing its allocated memory, and shared pointers.
There is a solution to the first problem, of automatically nulling out the pointer.
void SaferFree(void *AFree[])
{
free(AFree[0]);
AFree[0] = NULL;
}
The caller, instead calling
free(p);
will call
SaferFree(&p);
In respect to the second and harder to be siolved issue:
The rule of three says:
If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them.
Sharing a pointer in C is simply copying it (copy assignment). It means that using the rule of three (or the general rule of 0)
when programming in C obliges the programmer to supply a way to construct and especially destruct such an assignment, which is possible, but not an
easy task especially when C does not supply a descructor that is implicitly activated as in C++.
Related
When I have a pointer which should repeatedly be used as argument to realloc and to save it's return value, I understand that realloc won't touch the old object if no allocation could take place, returning NULL. Should I still be worried about the old object in a construction like:
int *p = (int *)malloc(sizeof(int *));
if (p = (int *)realloc(p, 2 * sizeof(int *)))
etc...
Now if realloc succeeds, I need to free(p) when I'm done with it.
When realloc fails, I have assigned it's return NULL to p and free(p) doesn't do anything (as it is a free(NULL)). At the same time (according to the standard) the old object is not deallocated.
So should I have a copy of p (e.g. int *last_p = p;) for keeping track of the old object, so that I can free(last_p) when realloc fails?
So should I have a copy of p (e.g. int *last_p = p;) for keeping track of the old object, so that I can free(last_p) when realloc fails?
Basically: yes, of course.
It is generally not suggested to use the pattern you showed:
p = (int *)realloc(p, ...)
This is considered bad practice for the reason you found out.
Use this instead:
void *new = realloc(p, ...);
if (new != NULL)
p = new;
else
...
It is also considered bad practice to cast the return value of malloc, realloc etc. in C. That is not required.
Should you save a temporary pointer?
It can be a good thing in certain situations, as have been pointed out in previous answers. Provided that you have a plan for how to continue execution after the failure.
The most important thing is not how you handle the error. The important thing is that you do something and not just assume there's no error. Exiting is a perfectly valid way of handling an error.
Don't do it, unless you plan a sensible recovery
However, do note that in most situations, a failure from realloc is pretty hard to recover from. Often is exiting the only sensible option. If you cannot acquire enough memory for your task, what are you going to do? I have encountered a situation where recovering was sensible only once. I had an algorithm for a problem, and I realized that I could make significant improvement to performance if I allocated a few gigabytes of ram. It worked fine with just a few kilobytes, but it got noticeably faster with the extra ram usage. So that code was basically like this:
int *huge_buffer = malloc(1000*1000*1000*sizeof *hugebuffer);
if(!huge_buffer)
slow_version();
else
fast_version();
In those cases, just do this:
p = realloc(p, 2 * sizeof *p)
if(!p) {
fprintf(stderr, "Error allocating memory");
exit(EXIT_FAILURE);
}
Do note both changes to the call. I removed casting and changed the sizeof. Read more about that here: Do I cast the result of malloc?
Or even better, if you don't care in general. Write a wrapper.
void *my_realloc(void *p, size_t size) {
void *tmp = realloc(p, size);
if(tmp) return tmp;
fprintf(stderr, "Error reallocating\n");
free(p);
exit(EXIT_FAILURE);
return NULL; // Will never be executed, but to avoid warnings
}
Note that this might contradict what I'm writing below, where I'm writing that it's not always necessary to free before exiting. The reason is that since proper error handling is so easy to do when I have abstracted it all out to a single function, I might as well do it right. It only took one extra line in this case. For the whole program.
Related: What REALLY happens when you don't free after malloc?
About backwards compatibility in general
Some would say that it's good practice to free before exiting, just because it d actually does matter in certain circumstances. My opinion is that these circumstances are quite specialized, like when coding embedded systems with an OS that does not free memory automatically when they terminate. If you're coding in such an environment, you should know that. And if you're coding for an OS that does this for you, then why not utilize it to keep down code complexity?
In general, I think some C coders focuses too much on backwards compatibility with ancient computers from the 1970th that you only encounter on museums today. In most cases, it's pretty fair to assume ascii, two complement, char size of 8 bits and such things.
A comparison would be to still code web pages so that they are possible to view in Netscape Navigator, Mosaic and Lynx. Only spend time on that if there really is a need.
Even if you skip backwards compatibility, use some guards
However, whenever you make assumptions it can be a good thing to include some meta code that makes the compilation fail with wrong target. For instance with this, if your program relies on 8 bit chars:
_Static_assert(CHAR_BITS == 8, "Char bits");
That will make your program crash upon compilation. If you're doing cross compiling, this might possibly be more complicated. I don't know how to do it properly then.
So should I have a copy of p (e.g. int *last_p = p;) for keeping track of the old object, so that I can free(last_p) when realloc fails?
Yes, exactly. Usually I see the new pointer is assigned:
void *pnew = realloc(p, 2 * sizeof(int *)))
if (pnew == NULL) {
free(p);
/* handle error */
return ... ;
}
p = pnew;
I ran into a rather weird problem,
I have the following code:
typedef struct{
char *a;
char *b;
char *c;
}Str;
typedef struct{
int size;
str array[]; //flexible array.
}strArr;
The purpose here is to allocate a,b, and c for the new element from the realloc.
StrArr *arr;
int arrSize;
arrSize = 1;
arr = malloc(sizeof(strArr)+sizeof(int)*arrSize);
arr->size++;
arr = realloc(arr, sizeof(strArr)+sizeof(int)*arr->size);
arr->array[arr->size-1].a = malloc(sizeof(char)*75);
arr->size++;
card = realloc(arr, sizeof(strArr)+sizeof(int)*arr->size);
The question is: whenever arr is realloc'd to be one bigger, do you have to allocate memory for the strings of the new element? This code will fail if it is run because it gives me glibc detected at the second realloc. What am I doing wrong? If i take off the malloc statement in the middle it runs. Also, if i try a strcpy into arr->array[arr->size-1].a, it would segfault.
Any help would be appreciated.
Thank you.
There are numerous issues with this code, enough to suggest that whatever you're experiencing can't be reproduced. Nonetheless, there are sufficient problems to cause instability (i.e. segmentation violations). I'm going to assume you meant to use a lowercase s in str rather than an uppercase S in Str; it only makes sense that way. Similarly for the lowercase s (which should be) in strArray.
At which point have you assigned arr->size a value in order for arr->size++; to be useful? That itself is a mistake, but that's interlaced into another mistake:
arr = realloc(arr, sizeof(strArr)+sizeof(int)*arr->size);
That turns out to be a major issue as you continue to use the uninitialised variable in critical pieces of logic, again and again, nonetheless, once that issue is resolved, the next mistake here is:
Anything that resembles the pattern X = realloc(X, Y); is suspicious. It's the Xes. Those should be different. You're not supposed to just replace the values like that. I mean, it'll work, kind of... but it's not much more effort to do it properly, and unless done properly, this won't be valgrind-friendly. That should be a big deal to you, because valgrind is a tool that helps us identify memory leaks!
You should store this into a temporary variable:
void *temp = realloc(X, Y);
... and then you can handle errors, perhaps by cleaning up and exiting properly:
if (temp == NULL) {
perror("realloc");
/* free(X); // what would valgrind cease complaining about? */
exit(EXIT_FAILURE);
}
... and replacing X with temp:
X = temp;
sizeof(int) should not be assumed to be the same size as sizeof str (whatever str is). Given the type of arr->array, I would expect sizeof str or, better yet, here's a nice pattern to keep in mind:
// X = realloc(Y, Z); or ...
void *temp = realloc(arr, sizeof *arr + arr->size * sizeof arr->array[0]);
// XXX: handle errors
The question is: whenever arr is realloc'd to be one bigger, do you have to allocate memory for the strings of the new element?
The strings themselves should be in a separate storage location to the list nodes. What is this? Strings and list nodes, in the same array?!
I suppose it might make sense if by strings you mean fixed-width, null padded fields. Fixing the width of the field makes expressing the array in a one-dimensional space much easier.
Otherwise, you should keep your strings allocated separately from your list nodes... in a manner with which the down-stream programmer has complete control over, if I may add, is kinda nice, though you lose that the moment you use realloc, malloc, etc (and thus the moment you use VLAs, hmmmm!)...
What am I doing wrong?
I think I've picked apart your code sufficing to say:
Initialise all of your variables before you use them. In this case, there are some variables pointed at by arr which are used without first being initialised.
Don't assume sizeof(int) and sizeof (/*any pointer type*/) have the same width. There are very real systems where this won't be true.
Remember to use that X = realloc(Y, Z); pattern, followed by error handling, followed by Y = X;.
I'm still not sure whether forcing down-stream programmers to rely upon malloc/realloc/etc and free is necessary, or even beneficial, here.
Also, if i try a strcpy into arr->array[arr->size-1].a, it would segfault.
Yes, well... there's that phantom arr->size-related issue again!
when I create a pointer to certain struct, do I have to set it to NULL, then alloc it then use it? and why?
No, you don't have to set it to NULL, but some consider it good practice as it gives a new pointer a value that makes it explicit it's not pointing at anything (yet).
If you are creating a pointer and then immediately assigning another value to it, then there's really not much value in setting it to NULL.
It is a good idea to set a pointer to NULL after you free the memory it was pointing to, though.
No, there is no requirement (as far as the language is concerned) to initialize a pointer variable to anything when declaring it. Thus
T* ptr;
is a valid declaration that introduces a variable named ptr with an indeterminate value. You can even use the variable in certain ways without first allocating anything or setting it to any specific value:
func(&ptr);
According to the C standard, not initializing an automatic storage variable leaves its value indeterminate.
You are definitely encouraged to set pointers to NULL whenever the alternative is your pointer having an indeterminate value. Usage of pointers with an indeterminate value is undefined behavior, a concept that you might not grasp properly if you're used to C programming and come from higher level languages.
Undefined behavior means that anything could happen, and this is a part of the C standard since the philosophy of C is letting the programmer have the burden to control things, instead of protecting him from his mistakes.
You want to avoid undefined behaviors in code: it is very hard to debug stuff when any behavior can occurr. It is not caught by a compiler, and your tests may always pass, leaving the bug unnoticed until it is very expensive to correct it.
If you do something like this:
char *p;
if(!p) puts("Pointer is NULL");
You don't actually know whether that if control will be true or false. This is extremely dangerous in large programs where you may declare your variable and then use it somewhere very far in space and time.
Same concept when you reference freed memory.
free(p);
printf("%s\n", p);
p = q;
You don't actually know what you're going to get with the last two statements. You can't test it properly, you cannot be sure of your outcome. Your code may seem to work because freed memory is recycled even if it may have been altered... you could even overwrite memory, or corrupt other variables that share the same memory. So you still have a bug that sooner or later will manifest itself and could be very hard to debug it.
If you set the pointer to NULL, you protect yourself from these dangerous situations: during your tests, your program will have a deterministic, predictable behavior that will fail fast and cheaply. You get a segfault, you catch the bug, you fix the bug. Clean and simple:
#include <stdio.h>
#include <stdlib.h>
int main(){
char* q;
if(!q) puts("This may or may not happen, who knows");
q = malloc(10);
free(q);
printf("%s\n", q); // this is probably don't going to crash, but you still have a bug
char* p = NULL;
if(!p) puts("This is always going to happen");
p = malloc(10);
free(p);
p = NULL;
printf("%s\n", p); // this is always going to crash
return 0;
}
So, when you initialize a pointer, especially in large programs, you want them to be explicitely initliazed or set to NULL. You don't want them to get an indeterminate value, never. I should say unless you know what you are doing, but I prefer never instead.
No, don't forget that initialization has to be to a null pointer at all. A very convenient idiom in modern C is to declare variables at their first use
T * ptr = malloc(sizeof *ptr);
This avoids you a lot of hussle of remembering the type and whether or not a variable is already initialized. Only if you don't know where (or even if) it is later initialized, then you definitively should initialize it to a null pointer.
So as a rule of thumb, always initialize variables to the appropriate value. The "proper 0 for the type" is always a good choice if you don't have a better one at hand. For all types, C is made like that, such that it works.
Not initializing a variable is premature optimization in most cases. Only go through your variables when you see that there is a real performance bottleneck, there. In particular if there is an assignment inside the same function before a use of the initial value, andy modern compiler will optimize you the initialization out. Think correctness of your program first.
You dont have to unless you dont want it to dangle a while. You know you should after freeing(defensive style).
You do not have to initialize to NULL. If you intend to allocate it immediately, you can skip it.
At can be useful for error handling like in the following example. In this case breaking to the end after p allocation would leave q uninitialized.
int func(void)
{
char *p;
char *q;
p = malloc(100);
if (!p)
goto end;
q = malloc(100);
if (!q)
goto end;
/* Do something */
end:
free(p);
free(q);
return 0;
}
Also, and this is my personal taste, allocate structs always with calloc. Strings may be allocated uninitialized with malloc
I am new in C, trying to figure out about memory allocation in C that I kinda confused
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int a;
} struct1_t;
int main()
{
funct1(); //init pointer
return 1;
}
int funct2(struct1_t *ptr2struct)
{
printf("print a is %d\n",ptr2struct->a);
//free(ptr2struct);
printf("value of ptr in funct2 is %p\n", ptr2struct);
return 1; //success
}
int funct1(){
struct1_t *ptr2struct = NULL;
ptr2struct = malloc(sizeof(*ptr2struct));
ptr2struct->a = 5;
printf("value of ptr before used is %p", ptr2struct);
if (funct2(ptr2struct) == 0) {
goto error;
}
free(ptr2struct);
printf("value of ptr in funct1 after freed is is %p\n", ptr2struct);
return 1;
error:
if(ptr2struct) free(ptr2struct);
return 0;
}
I have funct 1 that calls funct 2, and after using the allocated pointer in funct1, I try to free the pointer. And I create a case where if the return value in funct2 is not 1, then try again to free the pointer.
My question is below
which practice is better, if I should free the memory in funct2 (after I pass it) or in funct1 (after I finish getting the return value of funct1)
The second thing is whether this is correct to make a goto error, and error:
if(ptr2struct) free(ptr2struct);
My third question is , how do I check if the allocated value is already freed or not? because after getting the return value, I free the pointer, but if I print it, it shows the same location with the allocated one (so not a null pointer).
Calling free() on a pointer doesn't change it, only marks memory as free. Your pointer will still point to the same location which will contain the same value, but that value can now get overwritten at any time, so you should never use a pointer after it is freed. To ensure that, it is a good idea to always set the pointer to NULL after free'ing it.
1) Should I free it in the calling function or in the called function?
I try to do the free-ing in the same function that does the malloc-ing. This keeps the memory-management concerns in one place and also gives better separation of concerns, since the called function in this case can also work with pointers that have not been malloc-ed or use the same pointer twice (if you want to do that).
2) Is it correct to do a "goto error"?
Yes! By jumping to a single place at the end of the function you avoid having to duplicate the resource-releasing code. This is a common pattern and isn't that bad since the "goto" is just serving as a kind of "return" statement and isn't doing any of its really tricky and evil stuff it is more known for.
//in the middle of the function, whenever you would have a return statement
// instead do
return_value = something;
goto DONE;
//...
DONE:
//resorce management code all in one spot
free(stuff);
return return_value;
C++, on the other hand, has a neat way to do this kind of resource management. Since destructors are deterministically called right before a function exits they can be used to neatly package this king of resource management. They call this technique RAII
Another way other languages have to deal with this is finally blocks.
3) Can I see if a pointer has already been freed?
Sadly, you can't. What some people do is setting the pointer variable value to NULL after freeing it. It doesn't hurt (since its old value shouldn't be used after being freed anyway) and it has the nice property that freeing a null pointer is specified to be a no-op.
However, doing so is not foolproof. Be careful about having other variables aliasing the same pointer since they will still contain the old value, that is now a dangerous dangling pointer.
My question is below
which practice is better, if I should free the memory in funct2 (after I pass it) or in funct1 (after I finish getting the return value of funct1)
This is an "ownership" question. Who owns the allocated memory. Typically, this has to be decided based on the design of your program. For example, the only purpose of func1() could be to only allocate memory. That is, in your implementation, func1() is the function for memory allocation and then the "calling" function uses the memory. In that case, the ownership to free the memory is with the caller of func1 and NOT with func1().
The second thing is whether this is correct to make a goto error, and error:
The use of "goto" is generally frowned about. It causes mess in the code that could just be easily avoided. However, I say "generally". There are cases where goto can be quiet handy and useful. For example, in big systems, configuration of the system is a big step. Now, imagine you call a single Config() function for the system which allocates memory for its different data structures at different points in the function like
config()
{
...some config code...
if ( a specific feature is enabled)
{
f1 = allocateMemory();
level = 1;
}
....some more code....
if ( another feature is enabled)
{
f2 = allocateMemory();
level = 2;
}
....some more codee....
if ( another feature is enabled)
{
f3 = allocateMemor();
level =3;
}
/*some error happens */
goto level_3;
level_3:
free(f3);
level_2:
free(f2);
level_1:
free(f1);
}
In this case, you can use goto and elegantly free only that much memory that was allocated till the point the configuration failed.
However, suffice to say in your example goto is easily avoidable and should be avoided.
My third question is , how do I check if the allocated value is already freed or not? because after getting the return value, I free the pointer, but if I print it, it shows the same location with the allocated one (so not a null pointer).
Easy. Set the freed memory as NULL. The other advantage, apart from the one mentioned by MK, is that passing NULL pointer to free will cause a NOP i.e. no operation is performed. This will also help you avoid any double delete problems.
What i am about to share are my own development practices in C. They are by NO mean the ONLY way to organize yourself. I am just outlining a way not the way.
Okay, so, in many ways "C" is a loose language, so a lot of discipline and strictness comes from oneself as a developer. I've been developing in "C" for more than 20 years professionally, I've only very rarely have I had to fix any production-grade software that I have developed. While quite a bit of the success may be attributed to experience, a fair chunk of it is rooted in consistent practice.
I follow a set of development practices, which are quite extensive, and deal with everything as trivial as tabs to naming conventions and what not. I will limit my self to what I do about dealing with structures in general and there memory management in particular.
If I have a structure that's used throughout the software, I write create/destroy; init/done type functions for it:
struct foo * init_foo();
void done_foo(struct foo *);
and allocate and de-allocate the structure in these functions.
If I manipulate a structure elements directly all over the program then don't typedef it. I take the pain of using the struct keyword in each declaration so that I know it's a structure. This is sufficient where the pain threshold is NOT so much that I would get annoyed by it. :-)
If I find that the structure is acting VERY much like an object then I choose to manipulate the structure elements STRICTLY through an opaque API; then I define its interface through set/get type functions for each element, I create a 'forward declaration' in the header file used by every other part of the program, create a an opaque typedef to the pointer of the structure, and only declare the actual structure in the structure API implementation file.
foo.h:
struct foo;
typedef struct foo foo_t;
void set_e1(foo_t f, int e1);
int get_ei(foo_t f);
int set_buf(foo_t f, const char *buf);
char * get_buf_byref(foo_t f)
char * get_buf_byval(foo_t f, char *dest, size_t *dlen);
foo.c:
#include <foo.h>
struct foo {
int e1;
char *buf;
...
};
void set_e1(foo_t f, int e1) {
f->e1 = e1;
}
int get_ei(foo_t f) { return f->e1; }
void set_buf(foo_t f, const char *buf) {
if ( f->buf ) free ( f->buf );
f->buf = strdup(buf);
}
char *get_buf_byref(foo_t f) { return f->buf; }
char *get_buf_byval(foo_t f, char **dest, size_t *dlen) {
*dlen = snprintf(*dest, (*dlen) - 1, "%s", f->buf); /* copy at most dlen-1 bytes */
return *dest;
}
If the related structures are very complicated you may even want to implement function pointers right into a base structure and then provide actual manipulators in particular extensions of that structure.
You will see a strong similarity between the approach i've outlined above and object oriented programming. It is meant to be that ...
If you keep your interfaces clean like this, whether or not you have to set instance variables to NULL all over the place won't matter. The code will, hopefully, yield itself to a tighter structure where silly mistakes are less likely.
Hope this helps.
I know this is answered but, I wanted to give my input. As far as I understand, when you call a function with parameters such as here (the pointer), the parameters are pushed to the stack(FILO).
Therefore the pointer passed to the function will be automagically popped off the stack but not freeing the pointer in funct1(). Therefore you would need to free the pointer in funct1() Correct me if I am wrong.
I have a function which is called multiple times during the program's execution. In said function, I have a dynamic character pointer which I resize numerous times.
My question is: do I need to free this pointer before the end of the function?
void functionName()
{
char *variable = (char *) malloc(0);
//variable is resized with realloc x number of times
//should free be called here?
return;
}
I should also note that I have tried to free the pointer, however, gdb gives me warnings when I do so.
Yes, you have to free it or you'll leak the memory. Your code should look something like this:
void function(void)
{
char *variable = (char *)malloc(0);
variable = realloc(variable, 10);
// do something with new memory
variable = realloc(variable, 20);
// do something with more new memory
free(variable); // clean up
}
Calling malloc(0) is a little weird, I think.
A few points to make:
I can't see how you use realloc() in your code, but if you're using it like this, it's wrong:
variable = realloc(variable, amount);
When it's unable to allocate more memory, realloc() returns NULL but leaves the original pointer unaltered. In the above line, this means that variable is NULL and we've lost access to the memory it pointed to, but that memory hasn't been freed. The correct idiom is this:
void *tmp = realloc(variable, amount);
if(tmp)
{
// success! variable invalid, tmp has new allocated data
variable = tmp;
}
else
{
// failure! variable valid, but same size as before, handle error
}
The reason you should use the second one is because, with realloc(), failure is bad, but is quite recoverable in many situations, unlike malloc() where failure usually means "stop everything and die."
This is a more contentious issue, but it is questionable whether or not you should cast the return value of malloc() and realloc() like you do. Consider:
// functionally identical in C
char *a = malloc(10);
char *b = (char *)malloc(10);
In C++, the cast must be made, because in C++ void * cannot be implicitly converted to another pointer type. (I think this is a language mistake, but it's not my place to judge.) If your code is C++, you should be using new and delete anyway. If your code is C but needs to compile with C++ compilers (for some inane reason), you have no choice but to cast. If you don't need to compile C code with C++ compilers (which is similar to having to run Ruby code in a Python interpreter), continue to the points below, which are why I think you shouldn't cast.
In C89, if a function is used without being declared, it will be implicitly declared as returning an int. If, say, we forgot to #include <stdlib.h> and we called malloc(), the version without a cast would cause a compiler error (implicit casts from int to char * aren't allowed), while the version with the cast would (wrongly) tell the compiler "I know this sounds crazy, but cast it anyway." Most compilers will give you a warning for implicit (or incompatable) declarations of built-in functions like malloc(), but the cast does make it harder to find.
Say you have some data:
float *array = (float *)malloc(10 * sizeof(float));
Later, you discover that you need more precision on your data, and have to make this a double array. In the above line, you need to change no more than 3 different places:
double *array = (double *)malloc(10 * sizeof(double));
If, on the other hand, you had written:
float *array = malloc(10 * sizeof *array);
You would only need to change float to double in 1 place. Furthermore, always using sizeof *obj instead of sizeof(type) and never using casts means that a later call to realloc() can work without any changes, while using casts and explicit type names would require finding anywhere you called realloc and change the casts and sizeofs. Also, if you forget, and do this:
double *array = (float *)malloc(10 * sizeof(float));
On most platforms, array will now only be an array of 5 elements, assuming the alignment isn't off and the compiler doesn't complain that you're assigning a float * to a double *. Some consider the warning the compiler issues to be helpful, as it points out potentially incorrect lines. However, if we avoid sizeof(type) and avoid casting, we can see that the lines won't be incorrect, so having the compiler draw attention to them is wasting time we could be using to program.
From the man pages:
If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
So, I believe the answer is "yes" :).
Yes you need to call free() once to release the block of memory. You do not need to call free for the subsequent reallocs() that you are doing, even if those return a different address/pointer. The memory manager knows that the old block is not needed any longer and will free() it.
You should be able to just call free(variable) at the end. If realloc ever has to move the data in order to resize it, it calls free internally, you do not need to worry about that.
Also, where you initialize variable, you could just set it to NULL instead of calling malloc; realloc will work just like malloc the first time.
Have a look at some of the answers I have given to a couple of questions in relation to memory management:
Why are memory leaks common?
What's the point in malloc(0)?
C String confusion?
Need help in solving segmentation fault.
C stdlib realloc issue?
C: Creating array of strings from delimited strings.
All of the above point out the obvious thing, for every malloc there is a free, if not you have a memory leak, so it is imperative that you free the memory when you are finished with your pointer variable that is mallocd.
Hope this helps,
Best regards,
Tom.
int main(int argc, char *argv[])
{
char *p = malloc(sizeof(argv[1]));
p = argv[1];
printf("%s\n", p);
free(p);
return 0;
}
iam getting the glibc error
hello
*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00007fff66be94c6 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7f38dca1db96]
./a.out[0x4005ed]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f38dc9c076d]