So I have this code in which allocation is happening in one function and deallocation is being done in the calling function. Getting Segmentation fault or Abort message while trying to free the memory either by ptr or *ptr. Kindly have a look:
#include <stdio.h>
int main()
{
char *ptr;
fun(&ptr);
printf("ptr = %p\n",ptr);
printf("&ptr = %p\n",&ptr);
printf("String ptr = %s\n",ptr);
free (ptr);
return 0;
}
void fun(char **str)
{
*str = malloc(10);
*str = "HELLO";
printf("str = %p\n",str);
printf("&str = %p\n",&str);
printf("String str = %s\n",*str);
}
Following is the output:
str = 0x7ffe63247858
&str = 0x7ffe63247838
String str = HELLO
ptr = 0x400764
&ptr = 0x7ffe63247858
String ptr = HELLO
*** Error in `/home/a.out': munmap_chunk(): invalid pointer: 0x0000000000400764 ***
Aborted
Question :
Why can't we free ptr ? And if we can, what is the best way to do it ?
you're overwriting the pointer value in the line after, making *str point to a literal.
So you have a memory leak and undefined behaviour by trying to free a literal.
You probably mean
strcpy(*str,"hello");
Note that those 2 lines could be changed into a working single line like this:
*str = strdup("HELLO");
which has the advantage of allocating the exact number of bytes for the string instead of guessing.
When you do *str = "HELLO"; it does not have the effect you expect. Instead of assigning value to the allocated memory, you are re-assigning the pointer to point to the string literal and thus later you try to deallocate it (thus the error). Instead of this you should use strcpy like strcpy(*str, "HELLO").
To answer the question of how to do this without explicit string copying, instead of
char *p = "hello";
do
char p[] = "hello";
The first points p to a non-modifiable portion of memory. The second allocates an array large enough to hold the literal and copies the literal into it.
you are changing memory address pointed str pointer after malloc in fun. you should do strcpy instead of direct assignment :
#include <stdio.h>
int main()
{
char *ptr;
fun(&ptr);
printf("ptr = %p\n",ptr);
printf("&ptr = %p\n",&ptr);
printf("String ptr = %s\n",ptr);
free (ptr);
return 0;
}
void fun(char **str)
{
*str = malloc(10);
strcpy(*str,"HELLO");//*str = "HELLO";
printf("str = %p\n",str);
printf("&str = %p\n",&str);
printf("String str = %s\n",*str);
}
Related
I am attempting to create a structure (2nd) in a structure (1st) with dynamic memory allocation. For the sequence of steps below (case 1), where I call malloc for a pointer to the 2nd structure before calling realloc for the 1st structure, I see garbage when printing the value of the member (str[0].a1) in the first structure. If I place the same realloc code before malloc (case 2), there are no issues.
#include<stdio.h>
#include<stdlib.h>
typedef struct string2_t {
int a2;
} string2;
typedef struct string1_t {
int a1;
string2 * b;
} string1;
string1 * str = NULL;
int size = 0;
string1 test(int val){
// case 2
//str = (string1 *) realloc(str, size*sizeof(string1));
string1 S;
S.a1 = val;
size += 1;
S.b = (string2 *) malloc(2*sizeof(string2));
S.b[0].a2 = 11;
S.b[1].a2 = 12;
// case1
str = (string1 *) realloc(str, size*sizeof(string1));
return S;
}
int main() {
size += 1;
str = (string1 *) malloc(size*sizeof(string1));
str[0] = test(10);
printf("value of a:%d\n",str[0].a1);
str[1] = test(20);
printf("value of a:%d\n",str[0].a1);
return(0);
}
I can see that memory location changes for case 1, but I don't quite understand why doesn't pointer point to the right contents (str[0].a1 shows junk). I haven't returned the address of 1st structure before realloc, so I feel it should have worked. Could someone explain why it's pointing to garbage?
As has been stated by several in the comments, lines like this cause undefined behavior:
str[0] = test(10);
The test() function reallocates str, and this is not sequenced with retrieving the address of str[0] as the location to store the result. It's very likely to be compiled as if it had been written
string1 *temp = str;
temp[0] = test(10);
temp caches the old address of str from before the realloc(), and this is invalid after the function returns.
Change your code to:
string1 temp = test(10);
str[0] = temp;
Better design would be to reorganize the code so that all maintenance of the str array is done in one place. test() should be a black box that just allocates the string1 object, while main() allocates and reallocates str when assigning to it.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void set(char* str){
str = malloc(10);
strcpy(str, "dog");
printf("\nstr = %s", str);
}
int main(){
char* s;
set(s);
printf("\n%s", s);
return 0;
}
Here's what I want to print out:
str = dog
dog
Here's what actuall gets printed out:
str = dog
(null)
Why is this? What I think I'm doing is passing an uninitalized pointer that then gets assigned a block of memory in set(), which then gets "dog" written into. What's actually going on?
There is no pass-by-reference in C. But pointers and indirection gives a facility to mimic that indirectly.
In your case, what is sent from main() to set() is the address in variable 's'. It
will have that value till malloc() statement executes. After that, str will have whatever address is returned by malloc().
When the same thing is expected in main, what should have been passed is the address
of 's' rather than what address it holds (like some of the examples above).
C is a pass-by-value language. There is no way to pass something by reference except explicitly. For your case that means expecting a pointer-to-a-pointer:
void set(char **str)
{
*str = malloc(10);
strcpy(*str, "dog");
printf("str = %s\n", *str);
}
And calling with the address of the pointer you want to 'fill in':
int main(void)
{
char *s;
set(&s);
printf("%s\n", s);
return 0;
}
Why isn't this function(char*) pass by ref?
C doesn’t have pass-by-reference. Everything is pass-by-value – it’s just that some values are also pointers to other values. Your uninitialized variable s is read when you call set(s) (which is undefined behaviour) in order to provide a value for its parameter str, then str = malloc(10) throws that value away to assign a new value to the local str.
You can pass a pointer to the pointer:
void set(char** str){
*str = malloc(10);
strcpy(*str, "dog");
printf("\nstr = %s", *str);
}
int main(){
char* s;
set(&s);
printf("\n%s", s);
return 0;
}
or return a pointer:
char* set(void) {
char* str = malloc(10);
strcpy(str, "dog");
printf("\nstr = %s", str);
return str;
}
int main(){
char* s = set();
printf("\n%s", s);
return 0;
}
You are passing an unasigned pointer to your set function, here a copy of the pointer is made and you use malloc on that copy. The original pointer in main is never updated with the new memory address.
To achieve what you want could be done this way:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void set(char** str){
*str = malloc(10);
strcpy(*str, "dog");
printf("\nstr = %s", *str);
}
int main(){
char* s;
set(&s);
printf("\n%s", s);
return 0;
}
I used a pointer to a pointer in set, and pass the memory address of the pointer s to it.
I'm fairly new to C and I'm a little confused as to the correct way to initialise struct variables which are pointers, within a function. Is this style sufficient, or do I need to allocate memory before I assign s->str?
Thank you kindly for your replies, apologies if the question is unclear as I am very new to this language.
typedef struct Mystruct{
const char* str1;
const char* str2;
}mystruct;
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = (mystruct*)(malloc(sizeof(mystruct)));
s->str1 = str1;
s->str2 = str2;
return s;
}
your function is legal and doesn't do anything bad. Nevertheless, you should document it to mention that the strings are not copied, only the pointers are.
So if the passed data has a shorter life than the structure itself, you may meet undefined behaviour. Example:
mystruct*func()
{
char a[]="foo";
char b[]="bar";
return mystruct_new(a,b);
}
mystruct*func2()
{
char *a="foo";
char *b="bar";
return mystruct_new(a,b);
}
int main()
{
mystruct *s = func();
printf(s->a); // wrong, memory could be trashed
mystruct *s2 = func2();
printf(s2->a); // correct
mystruct *s3 = mystruct_new("foo","bar");
printf(s3->a); // also correct, string literals have global scope
}
the above code is undefined behaviour for the first print because s->a points to some memory that is no longer allocated (local to func).
The second print is OK because s2->a points to a string literal which has infinite life span.
So maybe your function is more useful like this:
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct));
s->str1 = strdup(str1);
s->str2 = strdup(str2);
return s;
}
now the memory is allocated for the strings. Don't forget to free it when discarding the structure, better done in another utility function.
If the strings being passed in to str and str2 will always be string constants than yes you can get away with doing it this way. My guess however is that this is not the case. So you would be better off making a copy of each string with strdup and assigning those to the struct members:
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct));
s->str1 = strdup(str1);
s->str2 = strdup(str2);
return s;
}
Just make sure to free each of those fields before freeing the struct.
Think of it this way: when you allocate memory for the struct, you get the pointer member variables for free. So in essence, when you do this:
mystruct *s = malloc(sizeof(mystruct)); //don't cast result of malloc.
Then you can treat s->str1 in the exact same way as you would any regular char* variable, say
char *str1 = NULL;
If you want it to point to something, then you have to allocate memory for the pointers. Consider this:
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct);
char* someString = getMyString(); //gets some arbitrary string
char* str1 = NULL;//just for demonstration
int length = strlen(someString) + 1;
//for struct members
s->str1 = malloc(sizeof(char) * length);
strcpy(s->str1, someString);
//For regular pointers
str1 = malloc(sizeof(char) * length);
strcpy(str1, someString);
return s;
}
Also note that if you just assign to a pointer by using the = operator instead of allocating memory, then it will only copy the address to the original value. This may or may not be what you want depending on the context. Generally, if you know the memory location will stay in scope and you don't need (or don't mind) to change the original string, then it is preferred to simply assign it. Otherwise, it is advisable to make a copy.
//Makes a copy of the string
s->str1 = malloc(sizeof(char) * length);
strcpy(s->str1, someString);
//copies the address of the original value only!
s->str1 = someString;
Use strncpy() instead of strcpy(). The latter is subject to buffer overruns.
For example in this code snippet given by another user, use the strncpy() in place of strcpy()
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct);
char* someString = getMyString(); //gets some arbitrary string
char* str1 = NULL;//just for demonstration
int length = strlen(someString) + 1;
//for struct members
s->str1 = malloc(sizeof(char) * length);
strcpy(s->str1, someString);
//For regular pointers
str1 = malloc(sizeof(char) * length);
strcpy(str1, someString); // replace with strncpy(str1, someString, bufsize); where bufsize is the maximum number of characters in your string + 1 for the terminator '\0'.
return s;
}
i have this code in C:
char* func(char* str, int a) {
str = malloc(a * sizeof(char));
return str;
}
int main() {
char* s1 = NULL;
s1 = func(s1,4);
s1 = "123";
free(s1);
s1 = func(s1, 5);
s1 = "1234";
free(s1);
...
}
i keep getting run time error(as if it were an infinte loop)
is this using of s1 in main() legal?
would it produce memory leakage?
s1 = "123"; here you make s1 to point to a string literal and you should never call free for a string literal. My guess is that you meant to copy these characters to the memory allocated for s1. If that is the case, make use of strcpy. For instance:
char* func(char* str, int a) {
str = malloc(a * sizeof(char));
return str;
}
int main() {
char* s1 = NULL;
s1 = func(s1,4);
strcpy(s1, "123");
free(s1);
s1 = func(s1, 5);
strcpy(s1, "1234");
free(s1);
...
}
As for your second question - you have a memory leak in your code but precisely because of the reason I already mentioned - s1 = "123"; does not copy the bytes but points s1 at the literal. The code I suggest should be safe of memory leaks.
You are freeing a string literal, and you loose the address s1 points to when you do s1 = "123"; and now you can never free it.
is this using of s1 in main() legal? would it produce memory leakage? \
it will compile but it is not an issue of ilegal use but incorrect use, and yes it is an evident memory leak.
Bear with me. I have not coded in c in 8 years and am totally baffled why my string manipulation is not working. I am writing a program that loops forever. In the loop I initialize two char pointers each is passed to a function that add text to the char pointer (array). When the functions are done I print the char pointer and free the two char pointers. However the program dies after 7 iterations with the following error message
* glibc detected * ./test: double free or corruption (fasttop): 0x0804a168 ***
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include string.h
#include stdio.h
#include stdlib.h
#include errno.h
#include time.h
char *SEPERATOR = "|";
void getEvent (char* results);
void getTimeStamp(char* timeStamp, int timeStampSize);
void stringAppend(char* str1, char* str2);
int main (int argc, char *argv[])
{
int i = 0;
while(1)
{
i++;
printf("%i", i);
char* events= realloc(NULL, 1);
events[0] = '\0';
getEvent(events);
char* timestamp= realloc(NULL, 20);
timestamp[0] = '\0';
getTimeStamp(timestamp, 20);
printf("%s", events);
printf("timestamp: %s\n", timestamp);
free(events);
free(timestamp);
}
}
void getEvent (char* results)
{
stringAppend(results, "a111111111111");
stringAppend(results, "b2222222222222");
}
void getTimeStamp(char* timeStamp, int timeStampSize)
{
struct tm *ptr;
time_t lt;
lt = time(NULL);
ptr = localtime(<);
int r = strftime(timeStamp, timeStampSize, "%Y-%m-%d %H:%M:%S", ptr);
}
void stringAppend(char* str1, char* str2)
{
int arrayLength = strlen(str1) + strlen(str2) + strlen(SEPERATOR) + 1;
printf("--%i--",arrayLength);
str1 = realloc(str1, arrayLength);
if (str1 != NULL)
{
strcat(str1, SEPERATOR);
strcat(str1, str2);
}
else
{
printf("UNABLE TO ALLOCATE MEMORY\n");
}
}
You are reallocating str1 but not passing the value out of your function, so the potentially changed pointer is leaked, and the old value, which has been freed by realloc, is freed again by you. This causes the "double free" warning.
The problem is that while stringAppend reallocates the pointers, only stringAppend is aware of this fact. You need to modify stringAppend to take pointer-to-pointers (char **) so that the original pointers are updated.
This line in stringAppend:
str1 = realloc(str1, arrayLength);
changes the value of a local variable in stringAppend. This local variable named str1 now points to either the reallocated memory or NULL.
Meanwhile local variables in getEvent keep the values they had before, which now usually point to freed memory.
All the comments where very helpfull. Of course it makes total sense why the error was happening. I ended up solving it by making the following changes.
For both the getEvent and stringAppend I return the char pointer.
e.g.
char* stringAppend(char* str1, char* str2)
{
int arrayLength = strlen(str1) + strlen(str2) + strlen(SEPERATOR) + 1;
printf("--%i--",arrayLength);
str1 = realloc(str1, arrayLength);
if (str1 != NULL)
{
strcat(str1, SEPERATOR);
strcat(str1, str2);
}
else
{
printf("UNABLE TO ALLOCATE MEMORY\n");
}
return str1;
}
This isn't an answer to your question (and you don't need one, since the error has been pointed out), but I do have some other comments about your code:
char* events= realloc(NULL, 1);
events[0] = '\0';
You don't test that realloc successfully allocated memory.
char* timestamp= realloc(NULL, 20);
timestamp[0] = '\0';
Same problem here. In this case, you don't need realloc at all. Since this is a fixed-size buffer, you could use just:
char timestamp[20] = "";
And don't do this:
str1 = realloc(str1, arrayLength);
because if realloc fails, you'll orphan the memory that str1 was pointing to before. Instead:
char* temp = realloc(str1, arrayLength);
if (temp != NULL)
{
str1 = temp;
...
}
Note that since you're modifying stringAppend to return the new string, you should do similar checks in the calling functions.
Also, "separator" is spelled with two As, not with two Es.