Allocating memory for a structure within a structure - c

typedef struct{
char id[15];
int count;
}hashtag;
typedef struct node{
hashtag *hashtag;
struct node*next;
}*link;
I'm writing a program to read hashtags from a sentence, and I want to store them in a list. I've already defined this two structures, and I can read and pass the hashtags to the function below but I need help allocating memory in order to copy the string to the list.
void check_insert(char newh[]){
link x;
//malloc to allocate memory for the string I want to copy
strcpy(x->hashtag->id, newh);
x->hashtag->count += 1;
head = insert_end(head, x->hashtag); //head is a global variable that points to the 1st element of the list
}

You should allocate and initialize the pointer x in check_insert, it is undefined behavior to dereference it and access its members without allocation first:
void check_insert(char newh[]){
link x = malloc(sizeof *x);
x->hashtag = malloc(sizeof *x->hashtag);
// strcpy(x->hashtag->id, newh); <-- UB if newh is larger than 14 in size
x->hashtag->id[0] = '\0';
strncat(x->hashtag->id, newh, sizeof(x->hashtag->id));
x->hashtag->count = 1;
head = insert_end(head, x->hashtag);
}

Related

Array of struct in C, char**

I was looking forward to make an array of struct just like [ obj, obj, obj ].
I got this struct:
struct obj {
char name[MAX_NAME];
char desc[MAX_TEXT];
bool asible;
};
How can I make it?
I tried
struct obj **objInRoom = malloc(sizeof(struct obj));
But when I iterate in it, it doesnt have anything :D
I chose this solution because I need to put that array of struct into this struct:
struct room {
struct obj **objts; //HERE
int qntty_objts;
struct interact **interacts;
int qntty_interacts;
};
If you need to have a double pointer for some reason, then you can do something like this struct obj *objInRoom = malloc(sizeof(struct obj)); and then assign address of objInRoom to your struct room->objts=&objInRoom.
struct obj **objInRoom = malloc(sizeof(struct obj));
If I simplifies, in your try you are allocating an area for a struct and trying to assign its address to a 'struct obj address' address holder which is struct obj**. But you should use struct obj * to hold the address of newly allocated area.
Which in this case your struct room should be like this:
struct room {
struct obj *objts; //struct obj** to struct obj*
int qntty_objts;
struct interact **interacts;
int qntty_interacts;
};
You should assign your newly allocated area like this:
struct obj *objInRoom = (struct obj*)malloc(sizeof(struct obj));
But in this case you only allocated the area for one struct obj element. To increase this area you can take the backup of your previous data and allocate new area for more size. For example to increase your allocated area two times:
//cap is integer defined before to hold capacity information of array
struct obj *backup = (struct obj*)malloc(2*cap*sizeof(struct obj));
for(int i = 0; i < cap; ++i)
backup[i] = objInRoom[i];
free(objInRoom); //to prevent memory leak, because we allocated new area for our incremented sized array.
objInRoom = backup;
cap *= 2;
Or you can simply use realloc to increase your array capacity if an allocation happened before with malloc or calloc, realloc creates an array with desired size and holds the previous data:
objInRoom = (struct obj*)realloc(objInRoom, 2*cap*sizeof(struct obj))
Note: Always cast your malloc operation to your desired pointer type because it returns 'void *' for default.
Note 2: Always check outputs from malloc, realloc and calloc; they return NULL in case of error.

Having trouble allocating memory for my double pointer in structure

I'm trying to allocate memory for a pointer, but have a reference to the address of that pointer. I'm still pretty new to C and this is my first time working with double pointers really.
So I have two structures and they look like this:
typedef struct myNodes {
int data;
struct myNodes *next;
} listElement;
typedef struct {
listElement **ptrToElements;
} myStruct;
In another file, I'm trying to dynamically allocate memory for my pointer by doing something like this:
myStruct *myStruct = malloc(sizeof(*myStruct));
*(myStruct->ptrToElements) = (listElement*)malloc(sizeof(listElement));
but I keep encountering a segmentation fault from doing so. What could be the issue? Thanks!
The problem is with
*(myStruct->ptrToElements) ....
statement. Before dereferencing myStruct->ptrToElements, you need to make sure it points to a valid memory.
To elaborate, you allocate memory for myStruct. Fine.
That constitutes allocating memory for the member ptrToElements. Good.
Question: What does ptrToElements points to?
Answer: Indeterministic.
So, when you try to derefernce a pointer which points to an indeterministic memory address, it's pretty much invalid memory address and attempt to do so will invoke undefined behavior.
Solution: You need to allocate memory for myStruct->ptrToElements before you can go ahead and dereference it.
having said that, please see do I cast the result of malloc?
You define the structure to contain a pointer to a pointer to a listElement
typedef struct {
listElement **ptrToElements;
} myStruct;
As Sourav Ghosh wrote, you try to assign a value to the pointer where ptrToElements would point to without allocating memory.
Probably you should change the pointer type to
typedef struct {
listElement *ptrToElements;
} myStruct;
and when allocating the memory
myStruct *myStruct = malloc(sizeof(*myStruct));
/* If the list can be empty, initialize root with NULL pointer */
myStruct->ptrToElements = NULL;
/* when you add the first list element */
myStruct->ptrToElements = malloc(sizeof(listElement));
myStruct->ptrToElements->data = someValue;
/* at least for the last element you add here you should initialize next */
myStruct->ptrToElements->next = NULL;
Don't forget to handle errors, e.g. malloc returning NULL.
I think this is what you want:
typedef struct myNodes {
int data;
struct myNodes *next; // not clear what this pointer is used for...
} listElement;
typedef struct {
listElement *ptrToElements;
} myStruct;
// Memory Allocation
// allocate myStruct pointing to an array of N listElements
myStruct *ms = malloc(sizeof(myStruct));
ms->ptrToElements = malloc(N * sizeof(listElement));
// element access
for (int i = 0; i < N; i++) {
listElement *le = ms->ptrToElements[i];
le->data = ...
le->next = NULL; // not clear what this pointer is used for...
}
// Memory deallocation
free(ms->ptrToElements);
free(ms);

Declaring a pointer to struct creates a struct?

It seems to me like struct new_element *element = malloc(sizeof(*element)) creates a structure of type element, whereas I thought it would only create a pointer to it. The following code proves to me I'm wrong:
struct new_element
{
int i;
struct new_element *next;
};
int main(void)
{
struct new_element *element = malloc(sizeof(*element));
element->i = 5;
element->next = NULL;
printf("i = %d, next = %p\n", element->i, element->next);
}
Output:
i = 5, next = (nil);
element->i was given the value 5 and element->next was given the value NULL. Doesn't that mean that element points to a structure, which would mean that there is a structure that was created? I thought that malloc would only give a pointer the size needed in memory.
The variable element is a pointer. When you define it, that sets aside space for the pointer.
If you just did this:
struct new_element *element;
You've created a pointer. It just doesn't point anywhere.
When you then call malloc(sizeof(*element)), that sets aside space big enough for what element points to, i.e. an instance of struct new_element. You then point the variable element to this section of memory.
This syntax:
element->i = 5;
Is the same as:
(*element).i = 5;
It dereferences the pointer element, giving you a struct new_element, then you access the member i.
If you did this, as you suggested in the comments:
struct new_element *element = malloc(sizeof(element));
You're not allocating the proper amount of space. You're setting aside enough space for a struct new_element * instead of a struct new_element. If the struct is larger than a pointer to it (likely in this case, since it contains a pointer to its own type), then you end of writing past the end of the allocated memory when modifying one of the members. This invokes undefined behavior.

Swapping strings between nodes in C

I'm trying to swap the data fields between nodes in my linked list, having trouble swapping the char arrays. this is just a sample of the program.
struct node {
int count;
char word[50];
struct node *next;
};
void swap_nodes( struct node *first, struct node *second ) {
int temp_count;
char *temp_word;
temp_count = first->count;
temp_word = first->word;
first->count = second->count;
first->word = second->word;
second->count = temp_count;
second->word = temp_word;
}
Let me know what I'm doing wrong, I'm very new at writing in c.
When you assign an array of characters to a pointer, you do not make a copy of the array:
char *temp_word;
temp_word = first->word;
temp_word points to the initial element of the array, so assigning to the array would change the data pointed to by the pointer as well.
You can fix this by declaring an array of 50 characters, and using strcpy or memcpy to do the copying:
char temp_word[50];
memcpy(temp_word, first->word, sizeof(temp_word));
memcpy(first->word, second->word, sizeof(temp_word));
memcpy(second->word, temp_word, sizeof(temp_word));
Well, you have already received answers, I just want to point out that you could exchange the nodes position in the list (instead the node content). As you have a single linked list, you will need the parents of the nodes to do so.
Alternatively, you can use dynamic memory instead the static array for "word", this way you only have to swap the pointers, avoiding the array copy.
The word[50] is a part of struct node, it's inside of the struct node, while what you have done is just move a pointer *temp_word point to *first, then to *second, the content of the word[50] is not changed in deeply. you can use memcpy to change the contents.
An appropriate implementation with strncpy and strdup would be:
#include <string.h>
void swap_nodes( struct node *first, struct node *second ) {
int temp_count;
char *temp_word;
temp_count = first->count;
temp_word = strdup (first->word);
first->count = second->count;
strncpy (first->word, second->word, 50); /* 50 based on struct definition */
second->count = temp_count; /* could be ( strlen (temp_word) + 1 ) */
strncpy (second->word, temp_word, 50);
if (temp_word) /* free memory allocated with strdup */
free (temp_word);
}

C - dynamically allocating a circular-buffer of structs within a struct

I am attempting to develop a dynamically-allocated circular-buffer in C using two structs. One holds detailed information and another is essentially used as a pointer from main to the circular-buffer structure (as there will be multiple arrays allocated at runtime).
Since it is a circular-buffer, I have a pointer "next" which points to the next item in the array (so last array index points to the first, etc.)
These are the two struct objects I have:
typedef struct {
int a;
int b;
struct1 *next; // pointer to next struct1 object in array
} struct1;
typedef struct {
struct1 *curr;
struct1 *start = NULL;
struct1 *end = NULL;
} struct2;
I then have my initialize function that is called from main to initiate a new circular-buffer.
This is the part where I am not entirely sure what to do.
#define minSize 10
struct2 * initialize()
{
struct2 **newBuf = malloc(sizeof(*newBuf));
newBuf->malloc(sizeof(*newBuf->quotes) * newBuf->minSize);
// set the start pointer
newBuf.curr[0] = newBuf->start;
newBuf.curr[0]->next = NULL;
for (int i = 1; i < minSize; i++)
{
struct1 *new = NULL;
newBuf.curr[i] = new; // make index i = NULL
// have the previous index point to the "next" current
if (i > 0)
newBuf.curr[i-1]->next = newBuf.curr[i];
}
// connect last index with first
newBuf.curr[minSize - 1]->next = newBuf.curr[0];
// set the end pointer
newBuf->end = newBuf->start;
return newBuf;
}
From searching I found this answer on how to initialize an array of structs within a struct by using malloc for initially allocating the space, but am confused how my code would line up since I have pointers to define start and end of the circular-buffer defined in struct2, as well as the next pointer as part of struct1.
Additionally, I've chosen to define ***newBuf* instead of **newBuf* as I was considering it as a pointer to pointers in a way (thinking about singly-linked lists). Though, please correct me if I am wrong.
I've done dynamically allocated circular-buffers in Java, but not C nor C++, so I am having a hard time figuring out the differences in how to initialize everything. I'm basically stuck at this mess and not sure where to go next.
Any help that can be given would be much appreciated!
The reason you're running into trouble is because you're trying to have the pointer to a pointer, rather than just using an ordinary pointer. You want to access the pointer that is contained at the address pointed to by the first pointer. As it stands you're trying to access a member that is outside of the memory space of the original pointer's address (which is only as large as an address). And then you're running into trouble because you aren't initializing your array 'curr' either. Another thing I did that doesn't really matter but helps you understand pointers is made your array a pointer- which is how arrays work in C. The array is simply the address of the first member of the array, and when you index into the array, it just adds an offset to that address = index * sizeof(yourstruct).
What you want is
typedef struct {
struct1 *curr;
struct1 *start = NULL;
struct1 *end = NULL;
} struct2;
#define minSize 10
struct2* initialize()
{
struct2 *newBuf = (struct2 *) malloc(sizeof(struct2));
newBuf->curr = (struct1 *) malloc(sizeof(struct1) * minSize);
// set the start pointer
newBuf.curr[0] = newBuf->start;
newBuf.curr[0]->next = NULL;
for (int i = 1; i < minSize; i++)
{
struct1 *new = (struct1 *) malloc(sizeof(struct1));
newBuf.curr[i] = new;
newBuf.curr[i-1]->next = newBuf.curr[i];
}
// connect last index with first
newBuf.curr[minSize - 1]->next = newBuf.curr[0];
// set the end pointer
newBuf->end = newBuf->start;
return newBuf;
}

Resources