Do we need to initialize the pointers inside struct - c

We have pointers inside a struct, do we need to initialize the pointers inside the struct?
I have tried the code below, include this sentence below or not, the code all run well.
(Could some experts give help here? and I read some code, and found seems sometimes initialized, sometimes not, so confused and search/ask here.)
The answer in this link seems not mentioned initialize this pointer inside struct. initializing-a-member-of-a-structure-with-pointers-c
#include "stdio.h"
#include "stdlib.h"
struct part{
int num;
char *name;
};
int main()
{
struct part *p = (struct part*)malloc(sizeof(struct part));
//Include this or not, this code all run well
p->name = (char*)malloc(sizeof(char));
p->num = 1;
p->name = "ss";
printf("%d, %s\n", p->num, p->name);
return 0;
}

No, you should not do that, you are creating a memory leak, because you allocate memory and then forget the pointer value and don't free it.
To remove the memory leak:
p->name = malloc(1); //sizeof char is 1 by definition, and cast not needed
free(p->name);
p->name = "ss";
However, if you look at that, it should be clear that allocating 1 byte of memory, then immediately freeing it, is pointless.
Perhaps you want a copy of the string?
const char *initdata = "ss";
p->name = malloc(strlen(initdata)+1);
strcpy(p->name, initdata);
// Remember to free this at some point
Alternatively, you could use initialize with the string literal, but then you should have const char pointer because string literals are read-only:
struct part{
int num;
const char *name;
};

Related

Copy a string to a *struct member

I've looked through topics of similar kind, but didn't find a solution for my problem. I've got a struct like
typedef struct {
int number;
char *string;
} mystruct;
//Then define a pointer to the struct:
mystruct *data;
// Allocate memory:
data = malloc(sizeof(mystruct));
//Assign some number, let's say 5:
(*data).number = 5;
//So far ok, works (checked: 5 can be retrieved from the struct somewhere else) but:
strcpy((*data).string = "Hello!");
//This line fails with segmentation fault.
I don't understand why? Can somebody please explain what I'm doing wrong?
As mentioned in the comments, the problem with your attempted strcpy call is that your destination (the string member of your data) isn't a pointer to valid memory. (I am assuming that your invalid syntax, strcpy((*data).string = "Hello!") is a typo, and that your real code has something like strcpy((*data).string, "Hello!") – otherwise, it won't even compile, so you won't get a segmentation fault.)
There are several approaches to fix this, depending on what you actually want to happen. First, as also mentioned in the comments, you can just copy the pointer to the destination, like this1:
data->string = "Hello!";
However, this may not be what you want, because, if the source is not actually a literal, but a modifiable string, then, after that assignment, any changes to the source will also apply to your copy.
If you want a copy of the source data, you will need to allocate sufficient space for it, then call strcpy; like this:
#include <stdlib.h> // For malloc
const char* src = "Hello!";
data->string = malloc(strlen(src) + 1); // Add 1 for the required nul-terminator
strcpy(data->string, src);
However, the strdup function2 does the job of the above malloc and strcpy calls in one fell swoop:
data->string = strdup("Hello!");
In each of the above two cases, be sure to call free(data->string) when you're finished.
1 Note that you can use the "member access through pointer" (->) operator, rather than dereferencing and then using the . operator: data->number = 5 is equivalent to your (*data).number = 5.
2 Some compilers/platforms may not support the strdup function, but it is part of the ISO C Standard from C23
As other users mentioned, you need to allocate space for the string.
I would use a flexible array member and have only one allocation for the struct and string.
typedef struct {
int number;
char string[];
} mystruct;
mystruct *create(const char *str)
{
mystruct *ms = NULL;
if(str)
{
ms = malloc(sizeof(*ms) + strlen(str) + 1);
if(ms)
{
strcpy(ms -> string, str);
ms -> number = 0;
}
}
return ms;
}
int main(void)
{
mystruct *ms = create("Hello");
if(ms)
{
printf("ms -> string = `%s`\n", ms -> string);
}
free(ms);
}
I am not sure to understand this line
strcpy((*data).string = "Hello!");
Do you mean
strcpy((*data).string, "Hello!");
I believe the issue is that your struct contain a pointer char * string that doesn't point to a valid allocated memory.
You can try multiple solutions
Have struct with predefined size
typedef struct {
int number;
char string[100];
} mystruct;
You can allocate memory for the string during the initialization
data = malloc(sizeof(mystruct));
data->string = malloc(sizeof(char) *100));

How do I make a pointer inside a struct point to the same string pointed by another pointer?

I have the following code:
struct el{
char *line;
struct el *next;
};
struct el *abc, def;
char *p1;
char buffer[100];
abc = &def;
gets(buffer);
p1 = malloc(strlen(buffer) + 1 );
strcpy( p1, buffer);
How can I make line point to the same string pointed by p1 without allocating the same string twice? Is it enough to write:
abc->line = p1;
Or do I also need to free the area pointed by p1?
I sense something smelly... Namely, that all your variables seem to be local variables (on the stack) that cease to exist when your function returns.
So would your function end with
return abc;
then you loose everything because you said abc= &def; and def is also a local variable. So yes, you can simply do abc->line= p1; but after the return you have lost abc (which points to def which was a stack variable that then no longer exists) and hence you have also lost abc->line and so you have a memory leak.
So you should expand the code you show us for us to be able to say "Yes you can do that".
The following is an example of a function that is wrong:
struct el{
char *line;
struct el *next;
};
struct el *example(void)
{
struct el *abc, def; // def is a local variable
char *p1;
char buffer[100];
abc = &def;
gets(buffer);
p1 = malloc( strlen(buffer) + 1 );
strcpy( p1, buffer);
abc->line= p1;
return abc; // def won't exist anymore after the function returns
}
To fix this error, you should also do abc= malloc(sizeof(struct el)); or pass a pointer variable to the function, for example:
void example2(struct el *abc)
{
char *p1;
// ...
abc->line= p1;
}
and call as for example:
int main(void)
{
struct el pqr = {0};
example2(&pqr);
// ...
}
How can I make line point to the same string pointed by p1 without allocating the same string twice? Is it enough to write:
abc->line = p1;
Yes, you can do that. abc->line will be pointing to the same memory address as p1.
Or do I also need to free the area pointed by 'p1'?
No, you don't need to free both. You should either use:
free(abc->line);
or:
free(p1);
You only need one of them, as both pointers are pointing to the same memory address, when you free one you free both.
Note that by freeing abc->line, p1 will become a dangling pointer, it will be pointing no nothing meaningful.
Recommended read regarding gets.
How can I make line point to the same string pointed by p1 without allocating the same string twice? Is it enough to write abc->line = p1?
Yes. abc->line = p1; is correct.
Or do I also need to free the area pointed by p1?
No, not at all. In opposite, If you would do so, line would point to nowhere.
Note that abc->line = p1; only assigned the value of the memory address of the chunk allocated by malloc() from p1 to the structure member line. They both are references to the **same ** memory allocated by malloc().
Never ever use gets(). Reason why is here. It is also removed from the C standard since C11.
First, using gets() is not recommended. A good replacement is fgets().
How can I make 'line' point to the same string pointed by 'p1' without allocating >the same string twice?
Two pointers can both point to the same buffer simply by setting them to point to the address of the buffer. Dynamic memory allocation is not necessary.
Given your code:
//the following are created in file global scope
struct el{
char *line;
struct el *next;
};
struct el *abc, def;
char *p1;
char buffer[100];
//The following is performed in local scope within a function, using global variables created above.
p1 = &buffer[0];//assign address of buffer to pointer p1
//same for char *line:
abc->line = &buffer[0];//assign address of buffer to member *line
//both will now accept input using fgets()
fgets(p1, sizeof(buffer), stdin);
fgets(abc->line, sizeof(buffer), stdin);

munmap_chunk(): invalid pointer, when to use free()

I'm curious as to why free(myWord->w) would be an invalid pointer? I allocate memory to it, so shouldn't I free it as well? or does freeing a struct also free all of its fields?
New to C so any insight on the world of pointers is much appreciated!
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct word {
char *w;
} WORD;
void setWord(char **f);
int main() {
WORD *myWord = malloc(sizeof(WORD));
myWord->w = malloc(6);
strcpy(myWord->w, "hello"); // set to "hello"
setWord(&(myWord->w)); // set to "bagel"
free(myWord->w); /* munmap_chunk(): invalid pointer. Aborted (core dumped) */
free(myWord);
return 0;
}
void setWord(char **F) {
*F = "bagel";
}
*F = "bagel"; is not how you assign a string. Instead the code overwrite the value of the pointer myWord->w so when you call free, it's no longer the correct pointer value.
To see that the pointer change, try this:
printf("%p\n", (void*)myWord->w);
setWord(&(myWord->w)); // set to "bagel"
printf("%p\n", (void*)myWord->w);
Consequently, the free call will fail as the pointer-value isn't the one you got from the malloc.
So instead of *F = "bagel"; use
strcpy(*F, "bagel"); // NOT: *F = "bagel"
Further you don't need to pass the address of w. Simply do:
void setWord(char *F) {
strcpy(F, "bagel");
}
and call it like:
setWord(myWord->w);
And...
I allocate memory to it, so shouldn't I free it as well? or does freeing a struct also free all of its fields?
Yes, you must free it.
No, free of a struct does not free members automatically. You must do that.

C sprintf overwrite?

Can someone explain me why this doesn't work? It appears that the program stops at sprintf(t->tuple[0], "abc"); and I don't know why. Really need help.
int testRemoveMeio(){
int result, i;
struct list_t *list = list_create();
char *tdata[3] = {" ", "2014", "Fixe!"};
struct tuple_t *t = tuple_create2(3, tdata);
struct tuple_t *tdups[4];
struct entry_t *entries[4];
sprintf(t->tuple[0], "abc");
tdups[0] = tuple_dup(t);
entries[0] = entry_create(tdups[0]);
list_add(list, entries[0]);
//extra code similar to above
return 0;
}
Edit:
struct tuple_t {
int tuple_dimension;
char **tuple;
};
struct tuple_t *tuple_create2(int tuple_dim, char **tuple){
struct tuple_t *t = (struct tuple_t *) malloc(sizeof(struct tuple_t));
if(t == NULL)
return NULL;
t->tuple_dimension = tuple_dim;
t->tuple = tuple;
return t;
}
Edited to add another example from the comments:
#include <stdio.h>
#include <string.h>
int main(void)
{
char * s = "ABC";
printf("%s\n",s);
sprintf(s,"DEF");
printf("%s\n",s);
return 0;
}
I pasted the code from your comment into the question. Both that and your original code are failing for the same reason, I think: you're modifying string literals.
It's sad but true that in C, string literals like "hello world" are illegal to modify, yet are assignable to char* without const and without a cast. This makes it easy to screw up, because modifying such a string is undefined behavior, because it may reside in read-only memory in your program.
To fix it, try this:
char tdata[3][6] = {" ", "2014", "Fixe!"};
Or in your second example:
char s[] = "ABC";
This way you are allocating an actual character array with writable storage. But please, always use snprintf() and never sprintf() because the latter is prone to buffer overruns which can crash your program or worse.
You second example is wrong. You should use snprintf(3) (there is no reason to use sprintf in 2014; it is old and dangerous, since it may give a buffer overflow) on some array of char like this:
#include <stdio.h>
int main(void) {
char buf[64];
snprintf(buf, sizeof(buf), "here %s", "ABC");
printf("%s\n",buf);
return 0;
}
You could have used some dynamically allocated memory zone (but then, you should know its size), e.g.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t siz=32;
char* ptr = malloc(siz);
if (!ptr) { perror("malloc"); exit(EXIT_FAILURE); };
snprintf(ptr, siz, "here %s and two is %d", "ABC", 2);
printf("%s\n", ptr);
free (ptr);
return 0;
}
You might use asprintf(3) if your system gives it (e.g. on Linux) like
#define _GNU_SOURCE
#include <stdio.h>
int main (void) {
char* ptrzone = NULL;
asprintf(&ptrzone, "and here %s and one is %d", "ABC", 1);
printf("%s\n", ptrzone);
free (ptrzone), ptrzone = NULL;
}
In serious programs, you often should use the result of snprintf.
Read the documentation of all the functions you are using, so also: perror(3), exit(3), malloc(3), free(3)
You absolutely should read more about C dynamic memory allocation
You should compile with all warnings and debug info (gcc -Wall -g) and learn to use the debugger (gdb) and the memory leak detector valgrind
Some important information is missing as the definition to struct tuple_t and the definition of function tuple_create2. If the error occurs on sprintf(t->tuple[0], "abc") then either t->tuple and/or t->tuple[0] is not correctly initialized/allocated. This former should be an array of at least 1 for the example (but more probably 3 if we look at tdata) strings and the latter to a string buffer (array of char). Check you or provide us the tuple_create2 function.
The way you use sprintf to copy a string is dangerous. On your example this works but if the string to copy contains the '%' character, bad things can happen (% is the character used to specify a format in printf/scanf family of functions. If you want to stay with sprinf use sprintf(t->tuple[0], "%s", "abc") but the simpler is strcpy(t->tuple[0], "abc")
Since you have now added the definition of tuple_create2, I try to answer.
In C, it is up to you to manage the memory. What do you expect from tuple_create2 ?. Your code allocates the space for the "header" (i.e. a struct tuple containing the dimension and an array of strings) and fills it with tuple. The result is a new object which points to the same memory for the data (i.e. the array of strings). This is OK except if you want to modify this array (which seems to be the case). There are 2 things: the array itself (each entry is a pointer to an array of chars - do you want to modify the pointers ?) and the strings (the content of the array of chars). There are several possibilities for this but this depends on you. For instance the function could allocate its own array of pointers and initialize with the existing data:
struct tuple_t *tuple_create2(int tuple_dim, char **tuple){
struct tuple_t *t = (struct tuple_t *) malloc(sizeof(struct tuple_t));
if(t == NULL)
return NULL;
t->tuple_dimension = tuple_dim;
t->tuple = (char **) malloc(sizeof(char *) * tuple_dim);
for(i = 0; i < tuple_dim; i++) // could be replaced by a memcpy
t->tuple[0] = tuple[0];
return t;
}
Then you have to be aware that we copied only pointers. So when you want to modify an element either you simply copy the pointer :
t->tuple[0] = "abc";
or you allocate a new string if you thing it can be modified and you don't want this. I give you an example with "abc" but this is not relevant because "abc" is a constant string which will not be modified. Anyway here is the code (note the use of stdrup which duplicates the string doing a malloc)
t->tuple[0] = strdup("abc");

Why this program is crashing did i wrongly allocated memory

This program is crashing. Please tell me what's wrong with it. When I use an array instead of a pointer like Name[12] in the structure it doesn't crash. I guess there is some problem in dynamic memory allocation. Help please.
#include <stdio.h>
struct struct_tag
{
int number;
char *Name;
} struct_name;
main()
{
struct_name.number = 34;
char *Name = (char *) malloc(sizeof(char));
strcpy(struct_name.Name,"A");
printf("%d", struct_name.number);
}
You're allocating a single character:
char *Name = (char *) malloc(sizeof(char));
And then never using that memory for anything. You meant to allocate memory for struct_name.Name, undoubtedly. But even if you had done so, you're then filling it with two characters ('a' and '\0'):
strcpy(struct_name.Name,"A");
which will cause an entirely different bug.
You want to say:
struct_name.Name = malloc( 2 );
Since (a) you shouldn't cast the result of malloc() and (b) sizeof(char) is always 1 and (c) you need room for the 0 at the end of your string.
For errors:
You are allocating memeory for *Name however you are not allocating
memory for struct_name.Name. So first thing is you need to allocate memory for struct_name.Name
As you already know that you'll be storing "A" in
struct_name.Name you should allocate memory for 2 char.("A" is string i.e 'A' and '\0')
For warnings:
If you want to use strcpy function include string.h in your code.
Also if you are using malloc include stdlib.h in your code.
Try this fixed code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct struct_tag
{
int number;
char *Name;
}struct_name;
int main()
{
struct_name.number = 34;
struct_name.Name = malloc(sizeof(char)*2); // As you will store "A"
strcpy(struct_name.Name,"A");
printf("%d \t", struct_name.number);
printf("%s \n", struct_name.Name);
return 0;
}
first look code carefully.
char *Name = (char *) malloc(sizeof(char));
strcpy(struct_name.Name,"A");
Hare for what you allocated memory (char *Name) and in which you copied string(struct_name.Name)?
here you not allocate memory for struct_name.Name. Also you have allocate memory for one character and you tried to copy two characters.('A' and '\0').
It should be
struct_name.Name = malloc(2);

Resources