when to carefully use free() to free up malloc() used memory? - c

I read from many question here in SO and some other articles regarding free() function in c that frees the memory of unused variables. In my case, I have the following code block.
char *injectStrAt(char *str, char *strToIn, int pos)
{
char *strC = malloc(strlen(str) + strlen(strToIn) + 1);
strncpy(strC, str, pos);
strC[pos] = '\0';
strcat(strC, strToIn);
strcat(strC, str + pos);
return strC;
}
The above function I use to inject a string block in to an array. I am using malloc to create a new char*. In the above case do I need to do free(strC) ? advice pls.

strC is the return value of this function, so you don't call free(strC) inside the function itself. You need to free it outside the function, the time when this string is not used anymore.

Since your function is returning strC, one presumes it must remain valid after the return of this function, thus this function must not free() that buffer. Once it's freed, the buffer is no longer valid so must not be used.
Your caller is responsible for freeing it in this case.

No you shouldn't free strC inside this function because it is the return value of this function. If you do so the statement:
return strC;
will return some unexpected or garbage value.
char* stringA = injectStrAt(str, strToIn, pos);
printf("StringA: %s"); // unexpected value.
So when should you free up the memory? Well, you should do it after the value of strC is returned from the function injectStrAt() to stringA, in this particular case. Although generally memory is freed when the string or the variable to which the memory was allocated is no longer required.
char* stringA = injectStrAt(str, strToIn, pos);
/... use the string
free(stringA);

Related

Error :"pointer being realloc'd was not allocated" on macOS but works on Windows when trying to realloc twice

I'm trying to implement a function that concatenate two strings, but I keep getting the same error.
"pointer being realloc'd was not allocated"
When I compiled the same code on a windows machine it worked, is it something that I'm missing?
The code below is basically what I'm trying to do.
main:
int main() {
int length = 4096;
char *string = malloc(length * sizeof(char));
createString(string, length);
realloc(string, 30);
return 0;
}
createString:
void createString(char * string, int length) {
char *copyAdress = string;
char *temp ="";
int counter2 = 0;
fflush(stdin);
fgets(string, length,stdin);
while(*string != EOF && *string != *temp ) {
string++;
counter++;
}
string = copyAdress;
realloc(string, (counter)*sizeof(char));
}
Thanks!
Edit:
I want createString to change the size of string to the length of the string that I get with fgets, while having the same address as the string that I sent in, so I can allocate more memory to it later when I want to add another string to it.
There are several issues:
realloc(string, (counter)*sizeof(char)); is wrong, you need string = realloc(string, (counter)*sizeof(char)); because realloc may return a different address.
Calling createString(string, length); won't modify string
If you want a more accurate answer you need to tell us what exactly createString is supposed to do. In your code there is no attempt to concatenate two strings.
Let's work through this in order of execution.
fflush(stdin); is undefined behaviour. If you really need to clear everything in the stdin you have to find another way (a loop for example). There are compilers/systems with a defined implementation but I would not count on it.
string++; is superflous as you overwrite string after the loop.
realloc(string, (counter)*sizeof(char));
should be
char *temp = realloc(string, (counter)*sizeof(char));
if (temp != NULL)
string = temp;
This way you get the pointer where your new string is located, but I suggest you read the refecerence for realloc. In essence you do not know if it has been moved and the old address might be invalid from that point on. So dereferencing it is also undefined behaviour.
After this you would have to return the new address of string or pass the address of the pointer to your function.
The same problem repeats with the second realloc. You only got to know your first call was wrong, because the second call noticed that you do not have valid data in what you thought would be your string.
In regards to your comment: It is not possible to use realloc and to be sure that the reallocated memory is in the same place as before.
If you realloc some memory, the pointer pointing to the original memory becomes invalid (unless realloc failed and returned NULL). So calling realloc twice on the same pointer should indeed not work (if it didn't return NULL the first time).
See the answers from others about what you do wrong. However, the eror message means that on MacOS, the realloc in createString deallocated the orignal string and allocated a new one, and now your realloc in main tries to realloc a pointer that is no longer valid (allocated). On Windows, the memory was not deallocated in createString and so the second call of realloc (in main) is given a valid pointer.

Allocating memory for strings dynamically

char* test() {
char* returnValue = "test";
return returnValue;
}
char* test=test();
printf("%s",test);
is it safe to use? is it the same, as
char* test {
char* returnValue=strdup("test");
return returnValue;
}
char* test=test();
printf("%s",test);
if yes, then should I free it later on? they are both seem to work correctly.
is it the same
No, it isn't.
char * test1() {
char * returnValue = "test";
return returnValue;
}
The above code returns the fixed address to the constant literal "test". This will be the same address each time the function is called.
It is not a dynamical allocation of memory.
Doing
printf("%d\n", test1() == test1());
will print
1
meaning "true", the two addresses returned are the same.
On "constness"
To better reflect the constness of the result of test1() it should better be defined as follows:
const char * test1() {
const char * returnValue = "test";
return returnValue;
}
char * test2 {
char * returnValue = strdup("test");
return returnValue;
}
The above code returns the address to a freshly allocated area of memory having been copied "test" into. This will be a different*1 address each time the function is called.
*1: "different" at least, as long as the result of any previous call to test2() had not been free() ed already
This is a dynamical allocation of memory. It therefore requires a call to free() passing in the address returned by strdup() (which internally calls malloc()) to deallocated the memory, if not needed any more.
Doing
printf("%d\n", test2() == test2()); /* leaks memory: 2 times 4+1 char */
will print
0
meaning "false", the two addresses returned are different.
For completeness: To avoid the leak as per the above snippet do
char * p, * q;
printf("%d\n", (p = test2()) == (q = test2()));
free(p);
free(q);
is it saft to use
Formally the code of both snippets is correct.
Which one to use and if the use if "safe" completely depends on the use case, on the the context.
char* test() {
char* returnValue = "test";
return returnValue;
}
is it safe to use?
Yes, as long as you are not trying to modify the returnValue which is a string literal. The string literals have static storage duration, so they are alive throughout the lifetime of the program but attempt to modify the content of string literal is undefined behavior.
is it the same, as
char* test {
char* returnValue=strdup("test");
return returnValue;
}
Answer is - No
strdup()
Returns a pointer to a null-terminated byte string, which is a duplicate of the string pointed to by str1. The returned pointer must be passed to free to avoid a memory leak.
The strdup() uses malloc() to obtain memory for the new string, here the new string is "test". It stays allocated until it is explicitly deallocated or until the program ends. So, it should be freed using free() once you are done with it. Also, you can modify the content of string returned by strdup() but make sure to not to access beyond the allocated memory chunk.
is it safe to use?
Yes, unless you try to change the string. There is no allocation in fact, so each time your function will return exactly the same pointer to the same location in memory.
is it the same, as
No, the strdup() makes an allocation and returns new allocated memory.
if yes, then should I free it later on?
It is no, but still you need to free the memory after strdup() later on.
they are both seem to work correctly
For printf() it is fine, unless you try to change those strings... You will not be able to change the char* returnValue = "test" string, but you will be able to change the string after strdup()
In both cases, "test" is allocated in the Stack as a read-only portion of memory (const char).
In the first block, you return a pointer to "test". As said before, this will be always the same value across calls to the function. Due to its read-only property, trying to free or modify it, will raise an execution error (munmap_chunk(): invalid pointer when trying to free, Segmentation fault when trying to modify).
In the second block, you return a pointer to a dynamically allocated portion of memory in the Heap. It's your responsibility to free this portion of memory using free() or equivalent. You are free to modify this variable, or even reallocate this portion of memory.
You can always do your own tests:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* test1() {
char* returnValue = "test";
return returnValue;
}
char* test2() {
char* returnValue = strdup("test");
return returnValue;
}
int main(void)
{
char* vtest1 = test1();
printf("%s => %p\n", vtest1, &vtest1);
char* vtest2 = test2();
printf("%s => %p\n", vtest2, &vtest2);
printf("Freeing 2nd test...\n");
free(vtest2);
printf("Trying to modify 1st test...\n");
vtest1[0] = 'p';
printf("Freeing 1st test...\n");
free(vtest1);
return 0;
}

how to free the dynamically allocated memory for a local variable?

Sample program:
#include <stdio.h>
#include <malloc.h>
void f(int n) {
char *val = (char *) malloc(12*sizeof(char));
val = "feels....";
printf("%s", val);
// free val; // if enable, compile time error: expected ';' before 'val' free val;
}
int main()
{
f(1);
return 0;
}
Is it required to free the memory which is dynamically allocated ? if yes, how to.
Yes, you need to free the memory. But when you allocate memory for a string, the way to populate the string is not to assign a string to it as that replaces the memory you've allocated. Instead you're meant to use the function strcpy like this...
char *val = malloc(12*sizeof(char));
strcpy(val,"feels....");
printf("%s", val);
free(val);
Instead of this:
char *val = (char *) malloc(12*sizeof(char));
val = "feels...."; // val points now to the string literal ""feels...."
// discarding the value returned by malloc
...
free(val); // attempt to free the string literal which will
// result in undefined behaviour (most likely a crash)
you probably want this:
char *val = malloc(12*sizeof(char)); // in C you don't cast the return value of malloc
strcpy(val, "feels...."); // the string "feels...." will be copied into
// the allocated buffer
...
free(val); // free memory returned previously by malloc
The compilation problem is because free is a function, you need to put its argument in parentheses.
free(val);
The other problem is a memory leak.
Strings in C are really just pointers to (hopefully) blocks of memory containing char data. The end of the string is denoted by a char with value 0. The thing to remember is that your variable is simply a pointer like any other pointer. So...
char *val = (char *) malloc(12*sizeof(char));
The above line dynamically allocates a block of memory and assigns a pointer to it to val.
val = "feels....";
The above line assigns a pointer to a string literal to val overwriting the previous pointer that was in val. It has not touched, in any way, the block of memory that was malloced in the first line. Furthermore, you have lost any reference you had to the malloced block so it has leaked. There's no way to free it.
String literals are usually created at compile time and the memory they occupy will be part of the program. This means they haven't come from the heap (where malloc gets its memory from. This means, in turn, when you try to free a string literal, bad things happen. On modern architectures, the program text is protected from writes at the OS level so trying to free part of it will almost certainly crash your program.
As long as you do not want to change the content of the string, you do not need to malloc space to it. You can omit the malloc line (and the corresponding free) and your program will still work.
f you do want to change the string, the easiest way to get a mutable copy of a string literal is to use strdup:
char *val = strdup("feels....");
// Do stuff with the string
free(val); // strdup strings need to be freed
strdup is a Posix function but not a C standard function so your platform might not have it. It's pretty simple to implement your own, though.
char* myStrDup(const char* thingToDup)
{
char* ret = malloc(strlen(thingToDup) + 1); // strlen returns the length without the terminating nul. Hence add 1 to it to allocate
strcpy(ret, thingToDup); // Copies the entire string including the terminating nul.
return ret;
}

Trouble with returning a string from function

I am having trouble with the basic principles of strings in C.
I have a function:
char *editStr(char *str) {
char new[strlen(str)];
... do some editing ...
return new;
}
How would I return the array of characters called "new". As I understand, the return value of the function is a char*, which means that it is asking for a pointer to the first character of a string.
Right now, I guess the problem is that I am returning a character of arrays. I tried to return a pointer to the first character in "new", but that doesn't seem to work, either.
I tried "return *new[0]".
My string knowledge is bad.
There are various problems here but the array/pointer issue with return new; isn't one of them.
First, you want:
char new[strlen(str) + 1];
So that you have enough room for the null terminator.
Your new is allocated on the stack so returning it will only cause grief and confusion; you'll want to:
char *new = malloc(strlen(str) + 1);
instead so that the memory is still valid when the function returns.
As far as your real question goes, an array in C is the address of the first element so your return new; is fine (subject to the stack versus heap issue noted above). C arrays decay to pointers at the drop of a hat so you don't need to worry about returning an array when the function is declared to return a pointer.
You're returning a pointer to something you've created on the stack. You can't do that.
You need to malloc() memory from the heap and return that (and then free() it later)
char *editStr(char *str) {
char *newArray = malloc(strlen(str) +1);
... do some editing ...
return newArray;
}
EDIT: Because I forgot to add 1 for the string terminator. You could also use strdup() if you wanted to start with a copy of the original string.
Here's what I see:
The word "new" is a C++ keyword. Don't use it to name a variable
If you want to edit the string, edit str directly.
If you need to make a copy, use malloc(strlen(str)) to allocate the extra memory.
This article describes the issue you are having an how to deal with it.
The best way to return a pointer to an array in C is like this:
char *getArr()
{
char *retbuf = malloc(25);
if(retbuf == NULL)
return NULL;
return retbuf;
}
new variable is stack allocated and you cannot return the reference of a stack variable.
char *editStr(char *str) {
char new[strlen(str)];
... do some editing ...
return new;
} // At this point, Unwinding of stack begins.
// new is on stack and the memory allocated to it is deallocated.
// So, the returned reference is only pointing to garbage.
Instead, you should use malloc and free it once it is done.
char *new = malloc( strlen(str) + 1 ) ; // +1 for the the termination character
When you create a normal C array, it will only exist inside the scope you created it in (in this case, the function editStr()) and will be destroyed as soon as you return from that function. Therefore, if you were returning the array pointer, it would become useless, and if you tried to use it, your program would most likely crash.
Instead, you should dynamically allocate arrays using malloc(). It is fairly easy to use:
char *a = (char*) malloc(sizeof(char) * 5);
This would create an array of 5 chars that you could use, and even pass between functions. However, they do not get destructed automatically when they fall out of scope, so you need to destruct them manually using free(a) when you are done with the pointers, or else you will end up with a memory leak.
See also:
malloc on Wikipedia
malloc in the C++ Reference
malloc manpage
If you are working in a single-threaded environment and the value is used immediately, you can make the internal buffer static and it will be available even after you exit the function:
char *editStr(char *str) {
static char new[strlen(str)];
... do some editing ...
return new;
}
You can also use the plain old sprintf style: pass a pointer to a buffer to the function and fill it inside.
int editStr(char *str, char *new, int new_size) {
... do some editing ...
return 0; //can return error
}

Confusion between passing and modifying char pointers in C (reference vs. value)

I was wondering if you could help me out with a C string problem I don't quite understand. I have a function to which I send 3 char pointers. Within this function, the char pointers are shifted and modified correctly. However, when I return to the main function from which they are called, said functions are not changed. Am I passing by value be mistake? Here is an example of my code:
int main(void)
{
LPSTR path = (char*)malloc(strlen(START_PATH));
strcpy( path, START_PATH );
char* newstr = (char*)malloc(PATH_SIZE);
TrimVal(path, "*.*", newstr);
//Do Stuff
return 0;
}
void TrimVal(char* modify, char* string, char* newstr)
{
newstr[0] = '\0';
modify = strncat(newstr, modify, (strlen(modify) - strlen(string)));
return;
}
NOTE: Assume PATH_SIZE is a size value, and START_PATH is a char array
In doing this
modify = strncat(newstr, modify, (strlen(modify) - strlen(string)));
You are modifying the pointer, not what the pointer points to.
When you pass in path to TrimVal. It will pass in the memory location of path e.g. 0x12345
When you do the modify = you are saying, change the local variable modify to be a new memory location, e.g. 0x54321
When you return to main, it only has a pointer to 0x12345, and when it looks there, nothing has changed.
You can easily fix your problem by doing
{
...
TrimVal(&path, "*.*", newstr);
...
}
void TrimVal(char** modify, char* string, char* newstr)
{
newstr[0] = '\0';
*modify = strncat(newstr, *modify, (strlen(*modify) - strlen(string)));
return;
}
void TrimVal(char* modify, char* string, char* newstr)
Changing the values of modify, string, or newstr inside the TrimVal() function has no effect on the variables at the calling function.
Changing the contents of modify, string, or newstr inside the TrimVal() function will be reflected on the variables at the calling function.
So
void TrimVal(char* modify, char* string, char* newstr)
{
newstr[0] = '\0'; /* will be reflected in the calling function */
modify = "a new string"; /* won't be reflected */
}
I think your function, with a little clearing of code, could do what you want.
Oh ... and you have a memory leak with the path variable: you malloc some space for it and immediately afterwards lose the address of that space by assigning a different value to the path variable.
A couple of points in addition to the many other good ones raised in this thread:
LPSTR path = (char*)malloc(strlen(START_PATH));
If this is C, you should not cast the return value of malloc. (See C FAQ 7.7b.
More importantly, strlen does not include the terminating \0 in its calculation. So, the memory path points to is one character short of the required amount of memory to hold START_PATH plus the \0. Therefore:
strcpy(path, START_PATH);
invokes undefined behavior by writing one past the memory pointed to by path.
If you expect your char* variable to be modified in the function and you want to pass by reference, you need to pass it as char* . Remember, you are passing the pointer by reference, so there needs to be an extra layer of indirection (passing char does pass something by reference - a single character!)
I see a problem with the first two statements. You are declaring path as a pointer char and allocating memory for it that is stored in this address holder. In your next statement, you are changing the value in path, pointing it to the start of your char array, START_PATH. The memory you allocated is now lost.
Also, strncat does not call malloc to concatenate. It is expected that you are passing in a buffer large enough to hold the concat, and this is a potential security risk (buffer overrun).
Just one comment about your style of casting the return type of the malloc call. When casting this can hide errors.
This would be a much better style.
Include the stdlib.h and try and make the call to malloc as type independent.
char *ptr_char = NULL;
ptr_char = malloc(sizeof(*ptr_char));
Hope this helps,
C doesn't really have a pass-by-reference. What you are doing here is passing pointers by value. A string in C is represented by a pointer to char. So in the function TrimVal you can modify the contents of the string (that is, the pointed-to data), but not the pointer itself.
strncat modifies the contents of the first parameter and returns the same value.
If you want to change the value of path within TrimVal, you should pass a pointer to a pointer, like so:
...
TrimVal(path, "*.*", newstr);
...
void TrimVal(char** modify, char* string, char* newstr)
{
newstr[0] = '\0';
*modify = strncat(newstr, *modify, (strlen(*modify) - strlen(string)));
return;
}

Resources