Freeing memory after calling strtok() causes an error - c

Could you please help me? My code does tokenizing, so I created code like this:
I allocate some memory,
I strcpy(malloced_memory, argv)
I execute strtok(mallocted_memory, ".")
Try free(mallocted_memory).
filename = malloc(strlen(argv));
strcpy(filename, argv);
strk_ptr = malloc(sizeof(filename));
strk_ptr = strtok(filename,".");//
i++;
sprintf(in->file_name,"%s",strk_ptr);
while(strk_ptr = strtok(NULL,"."))//
{
i++;
sprintf(in->file_name,"%s.%s",in->file_name,strk_ptr);
sprintf(in->file_ext ,"%s",strk_ptr);
}
free(strk_ptr);
free(filename);
That code has the problem that I can't free(filename). If I try free(filename), then program get SIGTRAP. But program is working.
I want fix that problem. What should I do?

This line:
filename = malloc(sizeof(argv));
should be this:
filename = malloc(strlen(argv) + 1); /* +1 for the '\0' at the end */
if (filename == NULL) { /* take some action */ }
And this line:
strk_ptr = malloc(sizeof(filename));
is only creating a memory leak since it is followed by:
strk_ptr = strtok(filename,".");
And you should check the return value:
strk_ptr = strtok(filename,".");
if (strk_ptr == NULL) { /* take some action */ }
BTW, the strtok() function returns a pointer to a token inside the string passed in the initial call to it (filename in your example). It does not allocate memory, so its return value should NOT be freed (which your program avoids, but it's a common mistake). While I'm grousing about strtok(), I'll mention that you can't (directly or indirectly) pass it a literal string to tokenize, since it modifies the string and literal strings are readonly. That is, doing: strtok("sample.txt", ".") is a no-go.
And finally, this kind of implicit condition is not great form:
while (strk_ptr = strtok(NULL,".")) { ... }
Better is:
while ((strk_ptr = strtok(NULL,".")) != NULL) { ... }

You don't need to allocate memory when using strtok()
There is no problem in freeing filename as it is correctly allocated by malloc(), however there are many other problems and memory leaks.
Basically you first allocate memory for str_ptr:
strk_ptr = malloc(sizeof(filename));
Here malloc() return a pointer which is stored in strk_ptr.
And then you call strtok() which also return a pointer, inside filename:
strk_ptr = strtok(filename,".");
So you lost the original pointer returned by malloc() and now strk_ptr points somewhere in filename. When you call free(str_ptr) you are freeing a memory inside filename. The subsequent call to free(filename) report the error. The solution is simply that don't need to allocate memory for strk_ptr.
I wrote a working minimal code to show you how to correctly use strtok. Please remember that, when asking a question, posting a minimal working code is alway better.
int main(int argc, char **argv) {
char *strk_ptr;
char *filename = malloc(strlen(argv[0]) + 1);
strcpy(filename, argv[0]);
printf("filename = %s, size = %zu\n", filename, sizeof(filename));
// Do not malloc this
//strk_ptr = malloc(strlen(filename) + 1);
strk_ptr = strtok(filename,".");//
printf("%s\n", strk_ptr);
while( (strk_ptr = strtok(NULL,".")) )
{
printf("%s\n", strk_ptr);
}
free(filename);
return 0;
}
First of all argv is a char** so if you want to copy the content of the first argument passed as input you have to use argv[0], which is always the executable file name.
then, sizeof(filename) returns the size of the pointer not the size of the content as filename is not an array. you have to use strlen(filename) + 1.
strtok return a pointer inside the object (filename) which is already allocated so you don't need to allocate memory for strk_ptr.
When using strtok in a loop consider to take the following approach:
for (strk_ptr = strtok(filename, "."); strk_ptr; strk_ptr = strtok(NULL, "."))
{
printf("%s\n", strk_ptr);
}

filename = malloc(strlen(argv));
strk_ptr = malloc(sizeof(filename));
strk_ptr gets some memory, which you then go leave dangling by pointing strk_ptr to filenames memory, you then end up double freeing filename.
So don't malloc strk_ptr. Just leave it as char* then only free filename at the end

strk_ptr = malloc(sizeof(filename));
strk_ptr = strtok(filename,".");//
...
free(strk_ptr);
Doesn't work. At first, strk_ptr points to the malloc'd memory but then the pointer is immediately overwritten with some other value, so basically you lose the pointer to the malloc'd memory and hence cannot free that memory any more.
Edit:
Seeing malloc(sizeof(filename)), I should add that you do not have to allocate memory for the pointer variable itself. The declaration char* strk_ptr; makes the compiler implicitly allocate memory for that pointer (i.e. 4 or 8 bytes). So you can just use the pointer directly like any other variable, and you won't have to free that variable's memory.
char* strk_ptr;
strk_ptr = strtok(filename,".");
Or, if that wasn't your intention then note that sizeof(filename) does not return the length of the string, but just the size of the pointer variable filename, i.e. usually 4 or 8, independent of what string filename points to. See also http://www.gnu.org/software/libc/manual/html_node/String-Length.html:
char string[32] = "hello, world";
char *ptr = string;
sizeof (string)
⇒ 32
sizeof (ptr)
⇒ 4 /* (on a machine with 4 byte pointers) */

Related

What is the difference between char *var= NULL; and char var[LENGTH + 1];?

I am creating a function to load a Hash Table and I'm getting a segmentation fault if my code looks like this
bool load(const char *dictionary)
{
// initialize vars
char *line = NULL;
size_t len = 0;
unsigned int hashed;
//open file and check it
FILE *fp = fopen(dictionary, "r");
if (fp == NULL)
{
return false;
}
while (fscanf(fp, "%s", line) != EOF)
{
//create node
node *data = malloc(sizeof(node));
//clear memory if things go south
if (data == NULL)
{
fclose(fp);
unload();
return false;
}
//put data in node
//data->word = *line;
strcpy(data->word, line);
hashed = hash(line);
hashed = hashed % N;
data->next = table[hashed];
table[hashed] = data;
dictionary_size++;
}
fclose(fp);
return true;
}
However If I replace
char *line = NULL; by char line[LENGTH + 1]; (where length is 45)
It works. What is going on aren't they "equivalent"?
When you do fscanf(fp, "%s", line) it'll try to read data into the memory pointed to by line - but char *line = NULL; does not allocate any memory.
When you do char line[LENGTH + 1]; you allocate an array of LENGTH + 1 chars.
Note that if a word in the file is longer than LENGTH your program will write out of bounds. Always use bounds checking operations.
Example:
while (fscanf(fp, "%*s", LENGTH, line) != EOF)
They are not equivalent.
In the first case char *line = NULL; you have a pointer-to-char which is initialised to NULL. When you call fscanf() it tries to write data to it and this will cause it to dereference the NULL pointer. Hence segfault.
One option to fix that would have been to allocate (malloc() and friends) the required memory first, check the pointer is not NULL (allocation failed) before using it. Then you would need to free() the resources once you no longer need the data.
In the second case char line[LENGTH +1] you have an array-of-char of size LENGTH + 1. This memory has been allocated for you on the stack (the compiler ensures this happens automatically for arrays), and the memory is only 'valid' for use during the lifetime of the function: once you return you must no longer use it. Now, when you pass the pointer to fscanf() (to the first element of the array in this case), fscanf() has a memory buffer to write to. As long as the buffer is large enough to hold the data being written this works correctly.
char *line = NULL;
Says "I want a variable named 'line' that can point to characters, but is not currently pointing to anything." The compiler will allocate memory that can hold a memory address, and will fill it with zero (or some other internal representation of "points to nothing").
char line[10];
Says "allocate memory for 10 characters, and I would like to use the name 'line' for the address of the first one". It does not allocate space to hold the memory address, because that's a constant, but it does allocate space for the characters (and does not initialize them).
Declaring a pointer as NULL doesn't allocate memory for the array. When you access the pointer, then what gets executed is reading / writing to a null pointer, which is not what you want. How fscanf works is it writes out to the buffer you sent, hence meaning that the buffer must be allocated before hand. If you want to use a pointer, then you ought to do:
char* line = malloc(LEN + 1);
When declaring as an array, then the compiler allocates memory for it, not you. This is better, in case you forget to free the memory, which the compiler won't do. Note that if you do use an array (which is a local variable in this case), it cannot be used by functions higher up on the call stack, because as I stated above, the memory gets freed upon return from the function.

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.

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;
}

Freeing memory in the caller that is reallocated by the callee?

Here is my situation:
main allocates memory based on string and calls function by passing an address. The function then appropriately resizes the passed memory to accommodate more data. After which when I try to release the memory I get heap error.
Here is the code:
typedef char * string;
typedef string * stringRef;
/**************************
main
**************************/
int main()
{
string input = "Mary had";
string decoded_output = (string)calloc(strlen(input), sizeof(char));
sprintf(decoded_output, "%s", input);
gen_binary_string(input, &decoded_output);
free(decoded_output); /*this causes issue*/
return 0;
}
void gen_binary_string(string input,stringRef output)
{
int i=0, t=0;
size_t max_chars = strlen(input);
/*
the array has to hold total_chars * 8bits/char.
e.g. if input is Mary => array size 4*8=32 + 1 (+1 for \0)
*/
string binary_string = (string)calloc((BINARY_MAX*max_chars) + 1, sizeof(char));
int offset = 0;
/* for each character in input string */
while (*(input+i))
{
/* do some binary stuff... */
}
/* null terminator */
binary_string[BINARY_MAX*max_chars] = '\0';
int newLen = strlen(binary_string);
string new_output = (string) realloc((*output), newLen);
if (new_output == NULL)
{
printf("FATAL: error in realloc!\n");
free(binary_string);
return;
}
strcpy(new_output, binary_string);
(*output) = new_output;
free(binary_string);
}
You may be misunderstanding the purpose of realloc. Calling realloc will not necessarily return a newly allocated object. If possible, it will return the same object, extended to hold more bytes. Also, it automatically copies the object's contents. Theferore: (1) you should not copy and (2) you should not free the old buffer.
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... (snip) Unless ptr is NULL, it must have been returned by an
earlier call to malloc(), calloc() or realloc(). If the area
pointed to was moved, a free(ptr) is done.
After a better reading of your code, I don't understand why you're using realloc at all here, as you're not using the old contents of output. You'd get the same behaviour (and the same error) if you replaced realloc with malloc. I think your real problem is that you're not allocating enough bytes: you should have strlen(binary_string) + 1 to accommodate the '\0' at the end of the string.
A better option would be to pass in a char** from the caller, let the callee allocate the char* and then pass back the pointer at the end of the function.
This prevents the need for two allocations and one free (always a bad sign).

strdup() memory leak even after free()

I've never needed to use strdup(stringp) with strsep(&stringp_copy, token) together until recently and I think it was causing a memory leak.
(strdup() has always free'd just fine before.)
I fixed the leak, and I think I understand how, but I just can't figure out why I needed to.
Original code (summarized):
const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *line, *field_name;
int colon_position;
message_copy = strdup(message);
while(line = strsep(&message_copy, "\n")) {
printf(line);
char *colon = strchr(line, ':');
if (colon != NULL) {
colon_position = colon - line;
strncpy(field_name, line, colon_position);
printf("%s\n", field_name);
}
}
free(message_copy);
New code that doesn't leak:
const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *freeable_message_copy, *line, *field_name;
int colon_position;
freeable_message_copy = message_copy = strdup(message);
while(line = strsep(&message_copy, "\n")) {
printf(line);
char *colon = strchr(line, ':');
if (colon != NULL) {
colon_position = colon - line;
strncpy(field_name, line, colon_position);
printf("%s\n", field_name);
}
}
free(freeable_message_copy);
How is the message_copy pointer being overwritten in the first code? or is it?
The function strsep() takes a pointer to the original string (message_copy) and modifies it to return a new pointer to the 'next' token
const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *original_copy;
//here you have allocated new memory, a duplicate of message
message_copy = original_copy = strdup(message);
Print out the pointer here,
printf("copy %p, original %p\n", message_copy, original_copy);
Note that as you use strsep(), you are modifying the message_copy,
char* token;
//here you modify message_copy
while(token = strsep(&message_copy, "\n")) {
printf("%s\n", token);
}
This illustrates the changed message_copy, while original_copy is unchanged,
printf("copy %p, original %p\n", message_copy, original_copy);
Since message_copy does not point to the original strdup() result this would be wrong,
free(message_copy);
But keep around the original strdup() result, and this free works
//original_copy points to the results of strdup
free(original_copy);
Because strsep() modifies the message_copy argument, you were trying to free a pointer that was not returned by malloc() et al. This would generate complaints from some malloc() libraries, and from valgrind. It is also undefined behaviour, usually leading to crashes in short order (but crashes in code at an inconvenient location unrelated to the code that did the damage).
In fact, your loop iterates until message_copy is set to NULL, so you were freeing NULL, which is defined and safe behaviour, but it is also a no-op. It did not free the pointer allocated via strdup().
Summary:
Only free pointers returned by the memory allocators.
Do not free pointers into the middle or end of a block returned by the memory allocators.
Have a read of the strsep man page here.
In short the strsep function will modify the original character pointer that's passed into the function, overwriting each occurrance of the delimiter with a \0, and the original character pointer is then updated to point past the \0.
Your second version doesn't leak, as you created a temporary pointer to point to the start of the original char pointer returned from strdup(), so the memory was freed correctly, as you called free() with the original char pointer instead of the updated one that strsep() had modified.
From the man page,
...This token is terminated by overwriting the delimiter with a null byte ('\0') and *stringp is updated to point past the token....

Resources