How can I create structs in a function? I'm trying this way:
#include <string.h>
#include <stdio.h>
typedef struct { char name[10]; } Item;
typedef struct { Item *item; } MyStruct;
MyStruct make(char *name) {
MyStruct st;
Item item;
strcpy(item.name, name);
st.item = &item;
printf("name: %s\n", st.item->name);
return st;
}
int main() {
MyStruct s1, s2;
s1 = make("hi");
s2 = make("hey");
printf("\nname: %s\n", s1.item->name);
printf("name: %s\n", s2.item->name);
}
The output is:
name: hi
name: hey
name: hey
name: hey
The struct s1 is being overwritten when I create s2. It looks that the address of the struct st on the function make is the same every time the function is called. Is it correct? I would like to avoid using malloc if possible.
Edit: The result is different on macOS and Linux, the output above is from Linux, below is from macOS. Why is it different?
name: hi
name: hey
name: p
name: p
When you declare Item item; you're allocating that locally and it falls out of scope. The next function call coincidentally recycles that same memory position.
This is undefined behaviour as you need to dynamically allocate that if it's to persist outside that scope.
The MyStruct st; is destroyed as soon as the function returns, so that's undefined behavior, so you'll have to use malloc and return a pointer to MyStruct.
Actually, returning structs is perfectly fine, and the compiler will make sure that a copy of the original data is returned, so no data is lost. But the problem is, the copy is shallow, so, for example, pointers are copied literally (the very address the original pointer points to is copied, but not the data), which means that any pointer inside the newly copied struct is potentially invalid, because the memory location it used to point to may have been deallocated while destroying the stack frame on function return.
Your function uses a struct with a pointer inside, and this pointer points to a local variable. The latter is (as all local variables) destroyed on function exit, and while a copy of the original struct is returned, the pointer now points to a memory address that's (probably) no longer controlled by your program.
That's why your data gets overwritten on the second call. So, if you want to preserve Item item, you should allocate it, and not the return value of your function (although you can do this too, of course, but this won't solve the problem since item will be destroyed anyway), on the heap with malloc.
Your problem is misunderstanding pointers. Let's start with some very similar code that would work.
#include <string.h>
#include <stdio.h>
typedef struct { char name[10]; } Item;
typedef struct { Item item; } MyStruct; // <--- Removed the *
MyStruct make(char *name) {
MyStruct st;
Item item;
strncpy(item.name, name, 10); // <--- strncpy because name[] is a fixed length
st.item = item; // <-- Removed the &; *copies* item into st
printf("name: %s\n", st.item.name); // <-- . rather than ->
return st;
}
int main() {
MyStruct s1, s2;
s1 = make("hi");
s2 = make("hey");
printf("\nname: %s\n", s1.item.name); // <-- . rather than ->
printf("name: %s\n", s2.item.name); // <-- . rather than ->
}
In this code I got rid of the pointers and everything should work. Item is 10 chars, and MyStruct is also 10 chars long. When you return it, those 10 chars of memory are copied, just like an int.
But you didn't do this; you added pointers. Since item is a local variable, it's in the current stack frame, not the heap. The stack frame disappears at the end of the current scope. (But it doesn't really disappear. It's just undefined behavior to reference it out of scope, so it can return anything.)
Doing it without pointers means more copying (though actually not that much more copying; on a 64-bit system, a pointer is 8 bytes). It also means changes to one copy don't impact the others. That's either good or bad depending on your problem. Getting rid of pointers this way can actually be a very good design as long as the struct doesn't get too big. Once you add pointers, you're going to need to manage memory and decide about ownership and when to free the memory and all the other headaches. It depends on your problem which approach is best.
As a note, if you go this way, there's no reason to create an intermediate item (and it's inefficient to do so because it's making two copies of the string). Instead you'd just copy directly into st:
MyStruct make(char *name) {
MyStruct st;
strncpy(st.item.name, name, 10);
printf("name: %s\n", st.item.name);
return st;
}
Related
My data gets overwritten whenever I insert a new value ,If I omit my free() in the main program my program works fine.Why ?How to recify this issue.Is memory allocation of structure is correct?
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct List
{
char val[20] ;
};
struct Hashtable
{
struct List *start;
};
struct Hashtable ht[26];
void init();
void insert(struct List*);
void init()
{
register int j;
for (j=0;j<26;j++)
{
ht[j].start=NULL;
}
}
int main(void)
{
init();
int i=0;
for (int i=0;i<5;i++)
{
struct List *newnode=(struct List*)malloc(sizeof(struct List));
scanf("%s",newnode->val);
insert(newnode);
free(newnode);
newnode=NULL;
}
return 0;
}
void insert(struct List *node)
{
if ( ht[node->val[0]-97].start==NULL)
{
ht[node->val[0]-97].start=node;
return;
}
else
{
printf("The value is %s\n", ht[node->val[0]-97].start->val);
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------___________________________________________________________________________
When you assign pointers, you only copy the pointers themselves, not the memory they might point to.
When you call free using a pointer, all copies of that pointer become invalid and can no longer be used.
You either need to make a completely new copy in the insert function (including allocating a new List structure), or you should not call free.
My personal recommendation is that you don't allocate at all in the main function, and that the insert function takes the string to "insert" as an argument (instead of the List pointer it currently takes).
Perhaps something like this:
void insert(char *val)
{
// Get the hash-table index (note that it only works with ASCII encoding)
char hash = tolower(val[0]) - 'a';
// First check if it exists
if (ht[hash].start == NULL)
{
// No, then add it
// First allocate memory for the node
struct List *node = malloc(sizeof *node);
// Then copy the string
strcpy(node->val, val);
// And finally add it
ht[hash].start = node;
}
}
Then your loop in the main function could be like
for (unsigned i = 0; i < 5; ++i)
{
char val[20];
scanf("%19s", val);
insert(val);
}
Imagine memory is a row of lockers, each containig an 8 bit value, and numbered as 1, 2, 3... (Well, higher values usually, but you get it). A pointer is just the number of that locker, nothing more. What malloc does, is:
Find a spot with free memory
Mark that memory as used
Return the number of the first locker
When you free, you mark again that memory as free. There are many algorithms to do this, but it would be wise to search for a small free memory space whith its number as low as possible, since leaving empty spaces is a waste of memory.
When you assign a pointer, you do not assign the values it points to, but the locker number.
When you free, you give the algorithm the possibility to use that locker, and when you use malloc again, it probably finds the same locker as before, and then you modify its contents.
Remember that your hashtable still uses that locker number, and when it opens the locker, it will find out its contents are modified.
Solution below:
TL;DR:
Your hash table uses still the same memory, so don't free it, since it might be modified when found by malloc.
Free it from the hashtable once you are finished using that pointer, to avoid wasting memory
Note: If you just read the solution, understanding heap (above), will help you with a lot of headaches, plus it is nice to know what the computer is doing with your code.
This is my code:-
typedef struct Frame
{
char* name;
unsigned int duration;
char* path; // may need to scan (with fgets)
}frame_t;
typedef struct Link
{
frame_t* frame;
struct Link* next;
}link_t;
void addNewFrame(void)
{
link_t* newLink = (link_t**)malloc(sizeof(link_t*));
printf(" *** Creating new frame ***\n\n");
printf("Please insert frame path:\n");
// newLink->frame->name = (char*)malloc(sizeof(char) * MAX_LEN);
fgets(newLink->frame->name, MAX_LEN,stdin);
printf("%s", newLink->frame->name);
}
I just need to add a data to name variable in the "Frame" link list, please help me by reviewing this code.
You want to allocate the right types here:-
link_t* newLink = malloc(sizeof(link_t)); //Pointer to Link st
if(newLink){
newLink->frame = malloc(sizeof(frame_t)); //Pointer to frame member
if(newLink->frame){
newLink->frame->name = malloc(sizeof(char) * MAX_LEN); //Pointer to name member
if(newLink->frame->name){
//Rest of your code
}
}
}
EDIT:-
1. As pointed out in comments there's no need to cast the pointer returned by malloc()
2. Another very imp point you may want to check validity of the pointers before de-referencing them
First. You don't need to cast void * so (link_t **)malloc(... can be only malloc(....
Second. You allocated enough memory for a pointer not for a struct. I think you mean malloc(sizeof(link_t)) or even better malloc(sizeof(*newLink))
Third newLink->frame is a pointer so you need to allocate data for it too, newLink->frame = malloc(sizeof(frame_t))
Fourth newLink->frame->name is still a pointer so you need to allocate data for it too. newLink->frame->name = malloc(MAX_LEN)
The confusion that you are doing is pretty common. When you say type *something you are allocating a pointer to type in the stack. A pointer needs to point to somewhere else or NULL, or bad things happen. This applies to structures too. If your structure has a pointer member you need to point it to somewhere else. The somewhere else is where the real "type" object resides.
This also applies to arrays. If you say 'int foo[10]' you are allocating ten integers in the stack. If you say int *foo[10] you are allocating ten pointers in the stack. If you say int **foo you are allocating one pointer in the stack. Again all pointers need to be initialized, I mean, they need to point to some valid object, allocated somewhere else in the memory.
I hope this helps.
Some other points.
Always check pointer coming from malloc, if allocation failed you'll receive NULL. Dereferencing NULL will break your program.
Always initialize memory coming from malloc, fill it with zeros or something.
Don't use _t suffix, is POSIX reserved.
I didn't test any of this.
I have a struct called State:
typedef struct State{
char alphabets[2][6];
struct State *PREV; /*this points to the previous state it came from*/
struct State *NEXT; /*this points to the next state in the linked list*/
int cost; /*Number of moves done to get to this position*/
int zero_index;/*this holds the index to the empty postion*/
} State;
Here's my memAllocator() method:
memAllocator(){
struct State *p = (State*) malloc(sizeof(State));
if (p==NULL){
printf("Malloc for a new position failed");
exit(1);
}
return p;
}
Here's my main method.
main(){
State *start_state_pointer=memAllocator();
State start_state;
start_state.zero_index=15;
start_state.PREV = NULL;
start_state.alphabets[0][0]='C';
start_state.alphabets[0][1]='A';
start_state.alphabets[0][2]='N';
start_state.alphabets[0][3]='A';
start_state.alphabets[0][4]='M';
start_state.alphabets[0][5]='A';
start_state.alphabets[1][0]='P';
start_state.alphabets[1][1]='A';
start_state.alphabets[1][2]='N';
start_state.alphabets[1][3]='A';
start_state.alphabets[1][4]='L';
start_state.alphabets[1][5]='_';
start_state_pointer=&(start_state);
/*start_state=*start_state_pointer;*/
}
I think the statement start_state_pointer=&(start_state); is just assigning the pointer start_state_pointer to to the small amount of temporary space created during State start_state, rather than to the space I allocated.
But when I try the commented out statement start_state=*start_state_pointer to deference the pointer and allocate the space to start state. It gives me a segmentation fault.
I am just starting out in C. Can some one help me with this?
Your memAllocator and main functions don't have explicit return types. This style of code has been deprecated for over 10 years. Functions in C should always have a return type. For main, the return type should be int, and for your memAllocator function, it should be State *.
The second issue is that you allocate space for a State struct, but then fill a different State struct and overwrite the pointer to the previously allocated State struct using start_state_pointer = &(start_state);.
To use the memory that you just allocated, you want to use something like this:
State *start_state = memAllocator();
start_state->zero_index = 15;
start_state->PREV = NULL;
start_state->alphabets[0][0] = 'C';
// etc.
There is no need to create two State structs. When you use State start_start; in your original code, you are creating a struct with something called automatic storage. This means the space for this struct is allocated automatically and is deallocated automatically for you at the end of the scope it is declared in. If you take the address of this struct and pass it around other parts of your program, then you will be passing around a pointer to a deallocated struct, and this could be why your program is crashing.
I have a generic linked-list that holds data of type void* I am trying to populate my list with type struct employee, eventually I would like to destruct the object struct employee as well.
Consider this generic linked-list header file (i have tested it with type char*):
struct accListNode //the nodes of a linked-list for any data type
{
void *data; //generic pointer to any data type
struct accListNode *next; //the next node in the list
};
struct accList //a linked-list consisting of accListNodes
{
struct accListNode *head;
struct accListNode *tail;
int size;
};
void accList_allocate(struct accList *theList); //allocate the accList and set to NULL
void appendToEnd(void *data, struct accList *theList); //append data to the end of the accList
void removeData(void *data, struct accList *theList); //removes data from accList
--------------------------------------------------------------------------------------
Consider the employee structure
struct employee
{
char name[20];
float wageRate;
}
Now consider this sample testcase that will be called from main():
void test2()
{
struct accList secondList;
struct employee *emp = Malloc(sizeof(struct employee));
emp->name = "Dan";
emp->wageRate =.5;
struct employee *emp2 = Malloc(sizeof(struct employee));
emp2->name = "Stan";
emp2->wageRate = .3;
accList_allocate(&secondList);
appendToEnd(emp, &secondList);
appendToEnd(emp2, &secondList);
printf("Employee: %s\n", ((struct employee*)secondList.head->data)->name); //cast to type struct employee
printf("Employee2: %s\n", ((struct employee*)secondList.tail->data)->name);
}
Why does the answer that I posted below solve my problem? I believe it has something to do with pointers and memory allocation. The function Malloc() that i use is a custom malloc that checks for NULL being returned.
Here is a link to my entire generic linked list implementation: https://codereview.stackexchange.com/questions/13007/c-linked-list-implementation
The problem is this accList_allocate() and your use of it.
struct accList secondList;
accList_allocate(&secondList);
In the original test2() secondList is memory on the stack. &secondList is a pointer to that memory. When you call accList_allocate() a copy of the pointer is passed in pointing at the stack memory. Malloc() then returns a chunk of memory and assigns it to the copy of the pointer, not the original secondList.
Coming back out, secondList is still pointing at uninitialised memory on the stack so the call to appendToEnd() fails.
The same happens with the answer except secondList just happens to be free of junk. Possibly by chance, possibly by design of the compiler. Either way it is not something you should rely on.
Either:
struct accList *secondList = NULL;
accList_allocate(&secondList);
And change accList_allocate()
accList_allocate(struct accList **theList) {
*theList = Malloc(sizeof(struct accList));
(*theList)->head = NULL;
(*theList)->tail = NULL;
(*theList)->size = 0;
}
OR
struct accList secondList;
accList_initialise(secondList);
With accList_allocate() changed to accList_initialise() because it does not allocate
accList_initialise(struct accList *theList) {
theList->head = NULL;
theList->tail = NULL;
theList->size = 0;
}
I think that your problem is this:
You've allocated secondList on the stack in your original test2 function.
The stack memory is probably dirty, so secondList requires initialization
Your accList_allocate function takes a pointer to the list, but then overwrites it with the Malloc call. This means that the pointer you passed in is never initialized.
When test2 tries to run, it hits a bad pointer (because the memory isn't initialized).
The reason that it works when you allocate it in main is that your C compiler probably zeros the stack when the program starts. When main allocates a variable on the stack, that allocation is persistent (until the program ends), so secondList is actually, and accidentally, properly initialized when you allocate it in main.
Your current accList_allocate doesn't actually initialize the pointer that's been passed in, and the rest of your code will never see the pointer that it allocates with Malloc. To solve your problem, I would create a new function: accList_initialize whose only job is to initialize the list:
void accList_initialize(struct accList* theList)
{
// NO malloc
theList->head = NULL;
theList->tail = NULL;
theList->size = 0;
}
Use this, instead of accList_allocate in your original test2 function. If you really want to allocate the list on the heap, then you should do so (and not mix it with a struct allocated on the stack). Have accList_allocate return a pointer to the allocated structure:
struct accList* accList_allocate(void)
{
struct accList* theList = Malloc( sizeof(struct accList) );
accList_initialize(theList);
return theList;
}
Two things I see wrong here based on the original code, in the above question,
What you've seen is undefined behaviour and arose from that is the bus error message as you were assigning a string literal to the variable, when in fact you should have been using the strcpy function, you've edited your original code accordinly so.. something to keep in mind in the future :)
The usage of the word Malloc is going to cause confusion, especially in peer-review, the reviewers are going to have a brain fart and say "whoa, what's this, should that not be malloc?" and very likely raise it up. (Basically, do not call custom functions that have similar sounding names as the C standard library functions)
You're not checking for the NULL, what if your souped up version of Malloc failed then emp is going to be NULL! Always check it no matter how trivial or your thinking is "Ah sher the platform has heaps of memory on it, 4GB RAM no problem, will not bother to check for NULL"
Have a look at this question posted elsewhere to explain what is a bus error.
Edit: Using linked list structures, in how the parameters in the function is called is crucial to the understanding of it. Notice the usage of &, meaning take the address of the variable that points to the linked list structure, and passing it by reference, not passing by value which is a copy of the variable. This same rule applies to usage of pointers also in general :)
You've got the parameters slightly out of place in the first code in your question, if you were using double-pointers in the parameter list then yes, using &secondList would have worked.
It may depend on how your Employee structure is designed, but you should note that
strcpy(emp->name, "Dan");
and
emp->name = "Dan";
function differently. In particular, the latter is a likely source of bus errors because you generally cannot write to string literals in this way. Especially if your code has something like
name = "NONE"
or the like.
EDIT: Okay, so with the design of the employee struct, the problem is this:
You can't assign to arrays. The C Standard includes a list of modifiable lvalues and arrays are not one of them.
char name[20];
name = "JAMES" //illegal
strcpy is fine - it just goes to the memory address dereferenced by name[0] and copies "JAMES\0" into the memory there, one byte at a time.
Please bear with me, i m from other language and newbie to c and learning it from http://c.learncodethehardway.org/book/learn-c-the-hard-way.html
struct Person {
char *name;
int age;
int height;
int weight;
};
struct Person *Person_create(char *name, int age, int height, int weight)
{
struct Person *who = malloc(sizeof(struct Person));
assert(who != NULL);
who->name = strdup(name);
who->age = age;
who->height = height;
who->weight = weight;
return who;
}
I understand the second Person_create function returns a pointer of struct Person. I don't understand is(may be because i m from other language, erlang, ruby), why does it define it as
struct Person *Person_create(char *name, int age, int height, int weight)
not
struct Person Person_create(char *name, int age, int height, int weight)
and is there other way to define a function to return a structure?
sorry if this question is too basic.
It is defined so because it returns a pointer to a struct, not a struct. You assign the return value to a struct Person *, not to struct Person.
It is possible to return a full struct, like that:
struct Person Person_create(char *name, int age, int height, int weight)
{
struct Person who;
who.name = strdup(name);
who.age = age;
who.height = height;
who.weight = weight;
return who;
}
But it is not used very often.
The Person_create function returns a pointer to a struct Person so you have to define the return value to be a pointer (by adding the *). To understand the reason for returning a pointer to a struct and not the struct itself one must understand the way C handles memory.
When you call a function in C you add a record for it on the call stack. At the bottom of the call stack is the main function of the program you're running, at the top is the currently executing function. The records on the stack contain information such as the values of the parameters passed to the functions and all the local variables of the functions.
There is another type of memory your program has access to: heap memory. This is where you allocate space using malloc, and it is not connected to the call stack.
When you return from a function the call stack is popped and all the information associated with the function call are lost. If you want to return a struct you have two options: copy the data inside the struct before it is popped from the call stack, or keep the data in heap memory and return a pointer to it. It's more expensive to copy the data byte for byte than to simply return a pointer, and thus you would normally want to do that to save resources (both memory and CPU cycles). However, it doesn't come without cost; when you keep your data in heap memory you have to remember to free it when you stop using it, otherwise your program will leak memory.
The function returns who, which is a struct Person * - a pointer to a structure. The memory to hold the structure is allocated by malloc(), and the function returns a pointer to that memory.
If the function were declared to return struct Person and not a pointer, then who could also be declared as a structure. Upon return, the structure would be copied and returned to the caller. Note that the copy is less efficient than simply returning a pointer to the memory.
Structs are not pointers (or references) by default in C/C++, as they are for example in Java. Struct Person Function() would therefor return struct itself (by value, making a copy) not a pointer.
You often don't want to create copies of objects (shallow copies by default, or copies created using copy constructors) as this can get pretty time consuming soon.
To copy the whole struct and not just pointer is less efficient because a pointer's sizeof is usually much smaller than sizeof of a whole struct itself.
Also, a struct might contain pointers to other data in memory, and blindly copying that could be dangerous for dynamically allocated data (if a code handling one copy would free it, the other copy would be left with invalid pointer).
So shallow copy is almost always a bad idea, unless you're sure that the original goes out of scope - and then why wouldn't you just return a pointer to the struct instead (a struct dynamically allocated on heap of course, so it won't be destroyed like the stack-allocated entities are destroyed, on return from a function).