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....
Related
I have a const char* string, I want to copy that string character by character to dynamic `char*.
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr)+1);
while(*constStr){
*str = *constStr;
constStr++;
str++;
}
printf("%s", str);
free(str);
The problem is that previous code just copies each character of constStr to only the first index of the str. I don't know why?
As others have pointed out, you are incrementing str pointer in each iteration, so you always end up printing the end of the string.
You can instead iterate over each character without incrementing the pointer. The following code worked for me:
const char *constStr = "Hello world";
int len = strlen(constStr);
char *str = (char *) malloc(len + 1);
int i;
for (i = 0; i <= len; ++i) {
str[i] = constStr[i];
}
printf("%s", str);
free(str);
Yes you didn't null terminate the string. That was the primary problem. To be more clear, it is not that you didn't nul terminate the string which is the problem but rather your use of them where a pointer to a nul terminated char array is expected is the problem. But even if you did there was significant amount of problems in the code.
You allocated the memory and the casted the return value of malloc which is unnecessary. void* to char* conversion is implicitly done.
malloc might not be able to service the request, it might return a null pointer. It is important to
check for this to prevent later attempts to dereference the null pointer.
Then you started copying - you copied everything except the NUL terminating character. And then you passed it to printf's %s format specifier which expects a pointer to a null terminated char array. This is undefined behavior.
The one position, in the str is uninitialized - beware that accessing uninitialized value may lead to undefined behavior.
Also there is another problem, From standard §7.22.3.3
The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.
Yes so is is the case here? No. when you called free(str) str is not pointing to the dynamically allocated memory returned by the malloc. This is again undefined behavior.
The solution always is to keep a pointer which stores the address of the allocated chunk. The other answers already showed them (without repeating them - both of them provides a good solution).
You can use strdup or strcpy also - even if you don't need them now - get accustomed with them. It helps to know those. And yes strdup is not part of standard, it is a POSIX standard thing.
Example:
const char *constStr = "Hello world";
char *str = malloc(strlen(constStr)+1);
if( !str ){
perror("malloc");
exit(EXIT_FAILURE);
}
char *sstr = str;
while(*constStr){
*str = *constStr;
constStr++;
str++;
}
*str = 0;
printf("%s", sstr);
free(sstr);
Here's the "classical" string copy solution:
const char *constStr = "Hello world";
char *str = malloc(strlen(constStr) + 1), *p = str;
/* Do not forget to check if str!=NULL !*/
while((*p++ = *constStr++));
puts(str);
The problem is that previous code just copies each character of
constStr to only the first index of the str. I don't know why?
Use index variable.
Don't forget terminating '\0' because you have a good chance of segmentation fault.
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;
}
So I am dynamically creating an array of strings. I am then assigning each element in that array a pointer returned by calling strtok. At the end of my process when I need to redo everything I have been trying to free the pointers in the elements of said array, but I keep getting an error stating
*** glibc detected *** ./prgm: munmap_chunk(): invalid pointer: 0x00007fff600d98
Also, would it make sense to free inputStr at the end of the loop?
Where is my logical "not really logical at all" thinking wrong..
e.g code
char** argvNew = (char**)calloc(33,sizeof(char*));
char inputStr[128];
do{
scanf("%127[^\n]%*c", inputStr);
token = strtok(inputStr, delim);
/* Add tokens to array*/
varNum= 0;
for(i = 0; token != NULL; i++){
varNum++;
argvNew[i] = token;
token = strtok(NULL, delim);
}
argvNew[i] = NULL;
//Free argvNew
for(i = 0; i < varNum;i++){
printf("Deleting %i, %s\n",i,argvNew[i]);
free(argvNew[i]);
}
while(1);
No, you should not free it. It's returning a pointer to a character in inputStr (or NULL when it reaches the end). It's not allocating any new memory, so there's nothing to free.
If inputStr is dynamically allocated, you should free it when you're done with it.
No, since it's not allocating new memory.
Quoting the ref of strtok():
Return Value
If a token is found, a pointer to the beginning of the token. Otherwise, a null pointer. A null pointer is always
returned when the end of the string (i.e., a null character) is
reached in the string being scanned.
The example of the ref, doesn't free what strtok() returns, which confirms:
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
You see the returned pointer of strtok() will be used just to access the memory already created by your program (regardless of whether this was created dynamically or not; here it is created statically). It won't be assigned newly created memory, thus you shouldn't free it.
In general, this is what you should have in mind:
Call free() as many times as you call malloc().
You only allocated the argvNew array. And that's the only thing you should be deallocating.
You did not allocate what the pointers in argvNew are pointing to, so you are not going to free() them.
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) */
Have a
typedef struct person {
char name[20]
char surname[20]
} person_t;
I need to create a string like XXXXXX:YYYYYY with the function like
char* personToString(person_t *p). I tried to make it:
char* personToString(person_t* p) {
int n1,n2;
n1=strlen(p->name);
n2=strlen(p->surname);
char *p = (char*) malloc((n1+n2+2)*sizeof(char));
strcat(p,puser->name);
strcat(p,":");
strcat(p,puser->surname);
return p;
}
This give me a reasonable output but I have some errors testing with valgrind! I also think that there is a way more classy to write the function!
When you malloc memory for p the memory will hold garbage values. Strcat will append a string after the null character, but in an uninitialized string will hold random values.
Replace the first strcat with strcpy.
You need to
strcpy(p,puser->name);
not
strcat(p,puser->name);
malloc does not initialize the buffer to zero, so strcat is searching for a null byte in p first and probably not finding one, reading past the end of the buffer and thus crashing.
Instead of one strcpy plus two strcat you can also write one call to sprintf:
sprintf(p, "%s:%s", puser->name, puser->surname);
First you should call string copy, then strcat:
strcat(p,puser->name);
should be:
strcpy(p,puser->name);
because memory allocated with malloc function keeps values garbage, by doing strcat for first you are concatenating after garbage -- it also brings Undefined behaviour in your code.
You can use void* calloc (size_t num, size_t size); instead of malloc(), calloc function initialized allocated memory with 0 (then strcat() no problem).
Also dynamically allocated memory you should deallocate memory block using void free (void* ptr);) explicitly.
This looks good to me,
char* personToString( struct person_t *p )
{
int len = strlen(p->name) + strlen(p->surname) + 2; // holds ':' + NULL
char *str = malloc( len ); // Never cast malloc's return value in C
// Check str for NULL
if( str == NULL )
{
// we are out of memory
// handle errors
return NULL;
}
snprintf( str, len, "%s:%s", p->name, p->surname);
return str;
}
NOTE:
Never cast malloc's return value in C.
Use snprintf when multiple strcat is needed, its elegant.
free the return value str here in caller.
Fixed struct and char variables.