Trouble with structs and strings - c

I made a linked list whose nodes hold 4 string values. When I call the newNode function, an error says 'Node has no member named familyName', as well as the other members. My code:
I am really confused with how strings work in structs.

Your immediate problem is the type definition. You cannot call malloc() from within there, all you can do is define the fields. The memory allocation must come later. So, it should be:
typedef struct node{
char *familyName;
char *firstName;
char *address;
char *phoneNumber;
struct node *link;
}Node;
You'll strike another problem (run-time rather than compile-time) once you fix that. When you do something like:
p -> familyName = famName;
that simply copies the pointer into your structure, and the pointer is always the memory location of familyName in main().
That means every node will point to the same memory, and you're continuously updating that memory.
You won't notice the problem with the code as it stands, since you're only asking for one record. But it will become an issue when you start looping to get more records.
Your best bet is to use something like strdup() to make a copy of the string passed in, then each node will have its own memory location for strings:
p -> familyName = strdup (famName);
(don't forget to also free() the memory for each field once you're finished with it).
In the unlikely event your C implementation doesn't have a strdup(), see here.

There are several problems:-
It is not allowed to allocate memory when declaring a structure. Either, do the malloc inside your newNode() method Or, declare the structure like char familyName[50].
Result of malloc should not be casted.
It is better to use strcpy (or strdup) when copying strings

Related

free(struct variable) doesn't clear previous stored values associated with that variable when I malloc again?

I created a struct like the following:
typedef struct header{
int hc;
char src[18];
char dst=[18];
char reason[15];
char d[3];
char m[3];
char y[4];
struct measurements{
char h_ip[17];
int h_ttl;
int h_id;
float h_rtt;
}HOPS[100];
}HEADER;
INSIDE MAIN:
HEADER *head;
for(...){
head=(HEADER*) malloc(sizeof(HEADER));
.....
free(head);
}
Will the above malloc automatically allocate memory for the inner struct as well? Also, I'm facing a weird problem here. After I free the header, I'm still able to print the values of head->HOPS[i].h_ip. Should I explicitly free the inner struct as well so that even the values get cleared?
Yes, it allocates memory for the inner structure. And you need not free the inner structure separately.
If you have a pointer defined inside your structure, in that case you have to allocate separately for that pointer member of the structure and free that separately.
Consider freeing memory as a black box. All what you know is that after freeing you shouldn't refer to freed memory.
You may find that that memory block still exists and still contains some old values. That's ok: it just was marked as freed and probably it will be used again soon by allocator.
For example when you call malloc again and realized that just allocated block contains values from the old structure. It happens and that's alright. Just use this block as usually.
So, after the problem with the wrong declaration of head was resolved:
free returns a previously allocated memory block to the heap. It does not clear anything (for performance reasons). However, you are not supposed to access that block anymore afterwards. Doing so results in undefined behaviour and might let your computer fly out of the window.
Worst that can happen is ... nothing ... Yes, you might even not notice anything strang happens. However, that does not mean your program run correctly, it just does not show any symptoms.
To catch illegal accesses, you might set the pointer to NULL once you freed the object it points to. Some operating systems catch accesses to addresses near the null pointer address, but there is no guarantee. It is a good practice anyway and does no harm.
For your other question: malloc allocates a block of memory large enough to store that many bytes you passed as argument. If it cannot, it will return a null pointer. You should always check if malloc & friends returned a valid pointer (i.e. not a null pointer).
int *p = malloc(sizeof(int));
if ( p == NULL ) {
error: out of memory
}
...
Notice the omission of the cast of the result of malloc. In C you should not cast void * as returned by malloc & friends (but also elsewhere). As much as you did not for free(head). Both take the same type: void *, btw. (so why cast one and not the other?). Note that in C any object pointer can freely be assigned to/from void * without cast. Warning functions are no objects in the C standard!
Finally: sizeof(HEADER) returns the size of the struct. Of course that include all fields. A nested struct is a field. A pointer to another struct is a field. For the latter, however note: the pointer itself is a field, but not what it points to! If that was another struct, you have to malloc that seperately **and also free seperately (remember what I wrote above).
But as you do not have pointer inside your struct, that is not your problem here. (keep it in mind, if you continue programming, you will eventually need that!)

C structs sharing common pointer?

I'm currently having an issue with the following struct:
typedef struct __attribute__((__packed__)) rungInput{
operation inputOperation;
inputType type;
char* name;
char numeroInput;
u8 is_not;
} rungInput;
I create multiple structs like above inside a for loop, and then fill in their fields according to my program logic:
while (a < 5){
rungInput input;
(...)
Then when I'm done filling the struct's fields appropriately, I then attempt to copy the completed struct to an array as such:
rungArray[a] = input; //memcpy here instead?
And then I iterate again through my loop. I'm having a problem where my structs seem to all have their name value be the same, despite clearly having gone through different segments of code and assigning different values to that field for every loop iteration.
For example, if I have three structs with the following names: "SW1" "SW2" SW3", after I am done adding them to my array I seem to have all three structs point me to the value "SW3" instead. Does this mean I should call malloc() to allocate manually each pointer inside each struct to ensure that I do not have multiple structs that point to the same value or am I doing something else wrong?
When you write rungArray[i] = input;, you are copying the pointer that is in the input structure into the rungArray[i] structure. If you subsequently overwrite the data that the input structure is pointing at, then you also overwrite the data that the rungArray[i] structure is pointing at. Using memcpy() instead of assignment won't change this at all.
There are a variety of ways around this. The simplest is to change the structure so that you allocate a big enough array in the structure to hold the name:
enum { MAX_NAME_SIZE = 32 };
…
char name[MAX_NAME_SIZE];
…
However, if the extreme size of a name is large but the average size is small, then this may waste too much space. In that case, you continue using a char *, but you do indeed have to modify the copying process to duplicate the string with dynamically allocated memory:
rungArray[i] = input;
rungArray[i].name = strdup(input.name);
Remember to free the memory when you discard the rungArray. Yes, this code copies the pointer and then overwrites it, but it is more resilient to change because all the fields are copied, even if you add some extra (non-pointer) fields, and then the pointer fields are handled specially. If you write the assignments to each member in turn, you have to remember to track all the places where you do this (that would be a single assignment function, wouldn't it?) and add the new assignments there. With the code shown, that mostly happens automatically.
You should malloc memory for your struct and then store the pointers to the structs inside your array. You could also turn your structs into a linked list by adding a pointer to each struct that points to the next instance of your struct.
http://www.cprogramming.com/tutorial/c/lesson15.html

C - transferring information to a struct (specifically an array of strings)

This seems to be a very simple problem but I can't quite figure out which part is causing it. Basically, I have a struct that just contains an array of strings
struct command_stream{
char **tokens;
};
typedef struct command_stream *command_stream_t;
command_stream_t test;
Then later on, I parse some strings into shorter ones and end up with another array of strings
char **words = *array of strings*
words contains the correct information I want, I looped through and printed out each element to make sure I wasn't getting a faulty string. So now I just point tokens to words
test->tokens = words;
But it gives me a segmentation fault. I'm not sure why though. They're both pointers, so unless I'm missing something obvious...
EDIT: The function as a whole has to return a pointer, which is why it was set up like this, which I keep forgetting. But I think I've got it, if I just create a new typedef
typedef struct command_stream command_stream_s;
command_stream_s new_command_stream;
and just return
&new_command_stream;
That should work right? Even though new_command_stream itself isn't a pointer.
From your code excerpt, it seems that you have not declared the struct. You have successfully declared a pointer to the struct command_stream_t test; but this pointer does not point to anywhere yet.
You need to allocate memory for your struct in some way and make test reference it. For instance:
command_stream_t test =
(command_stream_t) malloc(sizeof(struct command_stream));
This way you can successfully use:
test->tokens = words;
as you intended.
Note that you don't need to use malloc to allocate the memory. The pointer can reference a local/global variable as long as it has memory associated to it (N.B. if you use a local var don't use the pointer outside the declaration scope of that var).
typedef struct command_stream *command_stream_t;
command_stream_t test;
This makes "test" a pointer. There is no memory allocated for the structure.
You need to allocate memory for the structure and make the test pointer point to the block of memory before you can dereference by saying -
test->tokens = words;
Do this:
typedef struct command_stream command_stream_t;
command_stream_t test;
test.tokens = words;
The difference is that, command_stream_t is no more a pointer type, it is the actual structure.

malloc in c, struct

I made a struct like this:
struct a{
char *name;
char *value;
struct a *next;
};
when I malloc for memory at first time, it's ok, and I can set 'name' and 'value' a corresponding value.
but when I malloc for the second time, errors come. And It's a cgi, just show me "500 Internal server error".
I changed the pointer 'name' and 'value' to array, everything works.
I thought maybe the complier doesn't know how much memory to assign.
And do you have some ideas with this? I will appreciate every answer!
struct a {
char *name;
char *value;
struct a *next;
};
struct a *head = malloc(sizeof *head);
The above allocates space for a single struct a object, but it doesn't initialize any of hte three pointers contained in a struct a. In particular, if you want name and value to point to strings, you'll need to allocate space for those strings:
head->name = malloc(5);
strcpy(head->name, "Fred");
head->value = malloc(8);
strcpy(head->value, "abcdefg";
This is considerably oversimplified. 5 and 8 are "magic numbers"; you should specify the sizes in a way that will remain consistent if you change the initial values. And you should always check whether malloc() returns a null pointer (even if you just terminate the program with an error message).
If you don't initialize name and value to point to some chunk of allocated memory, you might still be able to initialize what they point to (e.g., by doing the strcpys above without the mallocs). More precisely, the system won't necessarily diagnose the error.
Finally, you'll need a call to free() corresponding to each malloc() call.
Note that this is largely a guess based on your description. If you can show us your actual code, we can help you better.
If you use malloc with sizeof(struct a) it's just going to assign enough space to store the pointers name and value. You want these to be char arrays, then it'll know how much space to set aside for each instance of a.

Why does pointer to malloc'd area fail unless copied?

I have a pointer to a struct. I call a routine that determines whether I need this struct and allocates space for it using malloc, returning the pointer to that area or zero if unused.
struct node *node_p;
node_p = need_this();
This works and I can properly access all the elements of the struct. One of the elements of struct node is *next which points to the next node struct and a pointer to a string but it's returning a pointer to a string that doesn't even exist in this routine.
node_p=find_string(node_p->next,"string");
However, this does return a pointer in the struct to the correct string.
struct node *node_p, *node_copy;
node_copy=find_string(node_p->next,"string");
The only difference is using a second pointer instead of the original. Am I doing something wrong here or must it be deeper into the called function? The problem with blaming the called function is I use it in multiple places for months without issue, however the other calls only look for the string and never go to 'next'.
EDIT: Further debugging has shown the problem actually lies with the pointer being passed to find_string and not the returned pointer. That changes the question and the problem so I need to open another question.
In this snippet:
struct node *node_p, *node_copy;
node_copy=find_string(node_p->next,"string");
you dereference node_p when it is not yet initialized (doesn't point to a legally allocated memory block). That's undefined behavior. You should set node_p to a legally allocated memory block of appropriate size first.
You need to allocate memory explicitly for every struct, i.e. allocate a new struct and set next pointer to point to it.
Pointers in C prior to initialization point to random place and you never should dereference them. Safe policy would be to init them to be NULLs.

Resources