If you were to do something like:
char array[2][5] = {"cars", "tags"}
char array2[] = "computer";
There has been an implicit allocation of memory allocated equal to(for the first line):
sizeof(array); OR
sizeof(char*10);
Or however you want to do it.
Alternatively, one could do this:
char *ptr = "cars";
char *ptr2 = malloc(sizeof(*ptr2)*5);
*ptr2 = "cars";
I know that if you are using pointers to explicitely allocate memory using malloc then it is good practice to free that pointer using free(ptr);
However, when you define things as above, are the following calls necessary on the same grounds as the explicit allocation of memory?
free(ptr);
free(ptr2);
free(array);
free(array2);
-- As an aside, all of the above delcarations/initializations are implicitely NULL-terminated strings, right?
You only need to free memory allocated with malloc, the other cases you specified are pointers to string literals or automatic variables(usually allocated on the stack) attempting to free them is undefined behavior.
C style strings are NULL terminated.
Also, important to note that:
*ptr2 = "cars";
is not correct syntax.
You should only ever call free when passing something allocated with a call to malloc. Which means that you should only ever call free with ptr2.
Furthermore, your assignment *ptr2 = "cars" is a syntax error. You would need to use strcpy to fill ptr2. Like this:
char *ptr2 = malloc(sizeof(*ptr2)*5);
strcpy(ptr2, "cars");
C strings are null-terminated by convention, and string literals, i.e. "cars" are null-terminated.
However, when you define things as above, are the following calls necessary on the same grounds as the explicit allocation of memory?
No, its illegal to free memory which are not returned by malloc or calloc or realloc.
all of the above delcarations/initializations are implicitely NULL-terminated strings, right?
Yes, those strings are called string literals and will be NULL termintaed.
*ptr2 = "cars"; is not a valid statement. If you want to point ptr2 someplace else, you need to use:
ptr2 = "cars";
If you want to overwrite the memory ptr2 points to, use strcpy:
strcpy(ptr2, "cars");
Only ptr2 needs to be freed - it's the only one you allocated with malloc. Note that if you make the ptr2 = "cars" assignment mentioned above, you won't be able to free the original memory you allocated. That's a logical error known as a "memory leak".
You only have to free memory yo have allocated using malloc, when you declare a static array memory is freed automatically at the end of the code block.
Related
I was wondering if a malloc() call is tied to its initial variable that you assign malloc() to at all, when it comes to how the system frees the memory.
For example, can I do the following:
void * ptr1 = malloc(50);
void * ptr2 = ptr1;
ptr1 = malloc(25);
free(ptr2);
I was intending to free the memory that was initially assigned to ptr1, but later free it by another pointer.
Let's walk through this step-by-step (UNDEF means that we don't know what a value is; valid means a pointer is safe to use):
void *ptr1, *ptr2; /* ptr1=UNDEF (invalid), ptr2=UNDEF (invalid) */
ptr1 = malloc(50); /* ptr1=0xAAA (valid), ptr2=UNDEF (invalid) */
ptr2 = ptr1; /* ptr1=0xAAA (valid), ptr2=0xAAA (valid) */
ptr1 = malloc(25); /* ptr1=0xBBB (valid), ptr2=0xAAA (valid) */
free(ptr2); /* ptr1=0xBBB (valid), ptr2=UNDEF (invalid) */
free() doesn't know which if any variable the pointer it's passed is stored in; it isn't guaranteed to (but also isn't guaranteed not to) update or interact with the variables in any way. All that effectively changes from an application developer's perspective is whether it's safe to actually use that pointer, or any other references into the block of memory allocated during the malloc() call that returned it.
As mentioned by #M.M in comments, the C language specification is explicit that the value of a pointer to a deallocated object is undefined, and the compiler is permitted to modify it in any way; see Why does MISRA C state that a copy of pointers can cause a memory exception? for further discussion.
Short answer: Yes
Longer answer:
You are not calling free "on the variable", but on the value stored in the variable.
To better understand what is going on, it may be better to think of memory as a big array of bytes, and visualizing a pointer as a numeric index into that array. And on most architectures you are likely to encounter, this is actually what is going on behind the scenes.
When you do
void * ptr1 = malloc(50);
malloc is reserving a block of 50 bytes and returning a pointer to that block. That pointer is nothing more than a numeric index telling us where in memory the reserved block starts.
In theory we could (on some architectures) write
int ptr1 = (int)malloc(50);
The reasons we are not doing it, are:
sizeof(int) may not be large enough to hold a pointer
void * tells the compiler that the numeric value stored in ptr1 should be treated as a memory address.
If we continue looking at your code:
void * ptr2 = ptr1;
There is nothing magical happening here. The "numeric value" stored in ptr1 is copied into ptr2, just as if ptr1 and ptr2 were normal integer variables.
ptr1 = malloc(25);
Here you overwrite the content of ptr1 with a new "numeric value", but the old value
still exist as a copy in ptr2.
free(ptr2);
Here you call free with the value stored in ptr2. This is the value returned by malloc(50). free does not care which variable is holding that value/address. It only cares that the value/address points to the first byte of a block of memory that was reserved with malloc.
In theory, if you knew that malloc(50) returned the value 0xb00b1e5 you could do
free((void *) 0xb00b1e5);
But you can't safely predict what malloc is going to return, so don't do that.
So my understanding is that these two block of codes are valid and do the same thing.
1.)
char *ptr = malloc(5);
ptr = "hi";
2.)
char *ptr = "hi";
I would want to know the difference between the two like if there any advantages of one over the other.
The former is a bug, and that code should never have been written.
It overwrites the pointer returned by malloc() with the address of a string literal, dropping the original pointer and leaking memory.
You must use strcpy() or some other memory-copying method to initialize newly allocated heap memory with a string.
The second just assigns the (run-time constant) address of the string literal to the pointer ptr, no characters are copied anywhere.
The first bit is a possible memory leak, the second relies on the implicit const storage class being used, and assigns the memory address of an immutable string to a pointer.
Basically:
char *ptr = malloc(5);//allocates 5 * sizeof *ptr
//then assigns the address where this block starts to ptr
//this:
ptr = "hi";//assigns position of 'h','i', '\0' in read-only mem to ptr
Now, the address you've allocated, that ptr pointed to, still is allocated. The difference is that you have no "handle" on it anymore, because ptr's value changed. There's no pointer pointing to the dynamic memory you allocated using malloc, so it's getting rather tricky to manage the memory... You probably won't be able to free it, and calling free on ptr now will result in undefined behaviour.
If you write:
char *ptr = "hi";
Then you're actually writing:
const char *ptr = "hi";
Which means you can't change the string to which ptr points:
ptr[0] = 'H';//IMBOSSIBRU
Alternatives are:
char string[] = "Hi";//copies Hi\0 to string
//or
char *ptr = malloc(5);
strcpy(ptr, "hi");//requires string.h
The difference between the two snippets above is that the first creates a stack array, the second allocates a block of memory on the heap. Stack memory is easier to manage, faster and just better in almost every way, apart from it being less abundant, and not really usable as a return value...
There is a pool of string literals for every process. Whenever you create a string literal inside your code, the literal is saved in the pool and the string's address (i.e. an address pointing somewhere to the pool) is returned. Therefore, you are creating a memory leak in your first option, because you are overwriting the address you received with malloc.
In the first case
char *ptr = malloc(5);
ptr = "hi";
There is a memory leak and later you are pointing ptr to a string literal "hi" which does require any memory from the heap (that's why there is memory leak).
But if you are allocating the memory and if you are using
strcpy (ptr, "hi");
then if you wish you can modify it
strcpy (ptr, "hello")
with one condition that you allocate sufficient memory before.
But in your case you are assigning a pointer ptr with a string literal, here you will not be able to modify it
ptr = "hello" // not valid. This will give a segmentation fault error
In your second case there is no memory leak and you are making a pointer to point to a string literal and thus it's value cannot be modified as it will be stored in read only data segment.
If I have a variable, str that I would like to allocate memory to on the heap, I would use malloc() like:
char* str = (char*)malloc(sizeof("Hello"));
malloc() is returning a void* pointer, which is the memory location where my memory is.
So now, I can give it some data
str = "Hello";
So, the memory location is now full, with 6 bytes. Now, I want to increase its size, to contain the string "Hello World". So, I use realloc(). According to man, void* realloc(void *ptr, size_t size) will:
The realloc() function changes the size of the memory block pointed to by ptr to size bytes.
The contents will be unchanged in the range from the start of the region up to the minimum of
the old and new sizes. If the newsize is larger than the old size, the added memory will not
be initialized.
So I assumed that it will return a void* to the new, now bigger memory location, which I can now fill with my new string, so going on the same logic to malloc():
str = (char*)realloc(str, sizeof("Hello World"));
But, this is where the problem is. This will cause:
*** Error in `./a.out': realloc(): invalid pointer: 0x0000000000400664 ***
And in valgrind
Invalid free() / delete / delete[] / realloc()
This suggests that there is something wrong with the pointer, str. So I decided to remove:
str = "Hello";
And it compiles fine, with the following code:
char* str = (char*)malloc(sizeof("Hello"));
str = (char*)realloc(str, sizeof("Hello World"));
I am aware of the fact that pointer to realloc() must come from malloc(), but simply assigning data to it shouldn't cause realloc() to fail, which suggects that I am doing something completly wrong.
So, what am I doing wrong?
And here is the code that fails:
char* str = (char*)malloc(sizeof("Hello"));
str = "Hello";
str = (char*)realloc(str, sizeof("Hello World"));
// str = "Hello World"; - this is what I would to be able to do.
Note: This code is something I have stripped down from a much larger program, just
to demonstrate the problem I am having, so I have removed checks etc.
Also, I am very new to C, so hence the really simple problem (sorry?), but after hours of work and research, I still can't figure out what I am doing wrong - It seems to work fine for everyone else!.
In C you cannot copy around blocks of memory as you tried to do:
str = "Hello";
That is not a valid string copy; instead, it leaves your malloc'd memory unaccounted for ("leaked"), and changes the pointer 'str' to point to a hard-coded string.
Further, because str is now a pointer to a hard-coded, static string, you cannot realloc it. It was never malloc'd to begin with!
To fix this, you want to change: str = "Hello"; to this:
strcpy(str, "Hello");
str = "Hello";
is the problem. You allocated a buffer and made str point to it. You then need to copy into that buffer. Like this:
strcpy(str, "Hello");
But instead you changed the value of the pointer.
When you call realloc, you must pass to realloc, a pointer that was created by an earlier call to malloc, realloc or similar. But you did not do that. Because you modified str.
malloc() is returning a void* pointer, which is the memory location where my memory is.
So far so good
So now, I can give it some data
str = "Hello";
You are right on being able to give that memory some data, but you are wrong on a way of doing it: you cannot reassign the pointer to a string literal - this would create a memory leak. Instead, you should copy the data into the memory block, like this:
strcpy(str, "Hello");
If you do an assignment instead of a copy, the pointer no longer points to something returned by malloc, making it illegal to pass that pointer to realloc.
This instruction:
str = "Hello";
doesn't allocate any memory in the heap.
char* str = (char*)malloc(sizeof("Hello"));
You are allocating memory dynamically to the str. Good. You are cast-ing the return value of malloc(), Not good.
str = "Hello";
You are trying to put the address of the static string "Hello" in str. Why? This is actually overwriting the memory address allocated by malloc(). What str contains is not a dynamically allocated pointer right now. It's a static address, which is not eligible for realloc()/ free() . Also, you are taking yourself into a zone of memory leak. What I think is you need strcpy() instead.
if you want to avoid the reallocation of memory issue use the function strdup :
char *str = strdup("hello");
str = strdup("hello word");
strdup returns a pointer to the storage space containing the copied string. If it cannot reserve storage strdup returns NULL.
I think I have got my head mostly around the difference, but if I am correct, then this should be correct also:
1.)
char *string1 = (char*) malloc(runtime_determined_number);
2.)
char string2val[runtime_determined_number];
char *string2 = &string2val;
Here I would expect string1 and string2 to be the same, is this the case?
string1 and string2 are not pointed to the same memory area
string1 is a pointer pointing to a char array allocated dynamically with malloc
string2 is a pointer pointing to a char array allocated statically
They both point to uninitialized blocks of memory of the same length. So in that respect they are the same, yes.
Note that in case 1, you are responsible for freeing the memory once you're finished. And in case 2, you can't safely return the pointer from a function as the memory will go out of scope on exit.
Using malloc you are asking the OS for memory during runtime. If malloc succeeded you are able to work with the allocated memory. You must deallocate this memory later on!
In your second part you are creating a char-array and then assign its address to a pointer. In this case the memory is taken from the stack and will be freed automatically when the array goes out of scope.
Your char*s won't be the same as they will be pointing to different locations in memory. There is aminor chance they contain the same garbage as you have not initialized them...
They are similar in that they have the same type and have at least runtime_determined_number bytes allocated for them.
They are different in that:
the first version requires an explicit free() to avoid a memory leak;
the lifetime of the two objects may or may not be the same.
Note that the second version is only valid in C99, since it makes use of a variable-length array.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C Array Instantiation - Stack or Heap Allocation?
When dynamically allocating a struct containing a char pointer, what happens with the actual char pointer? Where is it stored?
And once the struct is freed, is the char pointer freed along with it?
For example consider the following struct:
struct mix
{
int a;
float b;
char *s;
};
typedef struct mix mix;
And then the following code that allocates memory for it:
int main()
{
mix *ptr = (mix*)malloc(sizeof(mix));
ptr->a = 3;
ptr->b = 4.5f;
ptr->s = "Hi, there, I'm just a really long string.";
free(ptr);
return 0;
}
Is *s allocated on the stack and then freed along with *ptr? I can imagine it is indeed allocated on the stack as it's not in any way dynamically allocated (unless malloc has some functionality I'm not aware of). And I guess 'going out of scope' for *s would be at the point of freeing *ptr. Or have I got it completely wrong? :)
Thanks very much!
The space for the char* member named s is allocated on the heap, along with the rest of the members of mix after the call to malloc() (whose return value you do not need to cast). The string literal to which s is assigned is not allocated on the heap or the stack, but is part of the actual binary and has static storage duration. So this:
ptr->s = "Hi, there, I'm just a really long string.";
assigns the address of the string literal to ptr->s. If you want ptr->s to point to something other than a string literal then you need to malloc() memory for it. And for every malloc() there must be a free() so ptr->s would need to be free()d before ptr is (if ptr->s is pointing to dynamically allocate memory only).
After the call to free(), dereferencing ptr is undefined behaviour.
When you dynamically allocate mix with malloc(), you are actually allocating a block of memory to store mix structure data members, i.e.
an int (a)
a float (b)
a pointer to a char (s)
And when you call free(), you just release that block.
So, you don't allocate the string, you just allocate the string pointer.
If you want to dynamically allocate the string, you must do it explicitly (with another call to malloc()), and to avoid memory leaks you should also free the string explicitly, using free().
When you malloc for ptr, memory is allocated for all members of the struct including the pointer s which is no different to memory allocated for any other member of the struct.
You are assigning a string literal to s, so it's fine which is usually stored in the read-only section. Otherwise, you'll need to malloc for the ptr->s as well and free. Since, it's a string literal, there's no need to free s here (doing so is UB).
mix* ptr is allocated on the stack. The contents that ptr point at, a variable of type mix, is allocated dynamically on the heap, including the pointer s.
Please note that s doesn't point at anything, the pointer doesn't do anything useful. You have to set it to point at something, which could be allocated anywhere. Whatever it points to is not freed when your struct is freed. In this case you set it to point at a constant string literal allocated in ROM, so you won't need to worry about that.
Is *s allocated on the stack
*s (that is, the result of dereferencing the pointer s) isn't allocated at all. Following the malloc, ptr->s is an uninitialized pointer. It doesn't point to anything, and the expression *(ptr->s) has undefined behavior until you do ptr->s = "Hi, etc".
Once you've initialized ptr->s to point to the string literal, *(ptr->s) is the first character of the string literal, so it probably exists in some data section of the executable. Nothing is dynamically allocated other than the sizeof(mix) bytes for the struct (probably 12 bytes on a 32bit implementation).
what happens with the actual char pointer? Where is it stored?
char* is also like other members, take some bytes(take 8 byte in 64 bit machine, similar to other pointer). In your case, you are allocating memory for that structure instance in heap. so the memory for this pointer also will be allocated in same heap block which is allocated for that structure instance.
Consider this code. This gives where the char* will be:
#include <stdio.h>
typedef struct
{
int a;
float b;
char *s;
}mix;
int main()
{
printf("\n%d ,float:%d, int:%d, char*:%d", sizeof(mix), sizeof(float), sizeof(int), sizeof(char*));
return 0;
}
so size of this structure is 16 bytes. consist of 4 byte integer, 4 byte float and 8 byte char*. (In 64 bit OS, char* will be 4 bytes if OS is 32 bit.)
And once the struct is freed, is the char pointer freed along with it?
Usually the block which is pointed by char* will not be freed(If it points to a block allocated by malloc()). only the structure block will be freed. we know free() needs valid address which is returned during allocation for peaceful de-allocation. If you free without freeing that char*, it will leads to memory leak.
But your case "Hi, there, I'm just a really long string.";
the above given string is string literal which is allocated in read-only section of your program.
use gcc -S Yourprogram.c
This will generate .s file. You can look at .read_only section for this string. so even you delete your structure instance, there will be no memory leak. Because you are just pointing a address which is read-only. You are not at-all allocating memory for this string.