Initializing a char* value within struct within a struct in C - c

I have been looking online but so far nothing has helped me understand my problem. Currently I am trying to make two lists that each contain a list of words. Each space contains a word struct and within each word struct is list of 30 doc_list structs. I have been able to allocate memory and store a char*s within the word list struct but when I try to allocate memory and store a char* within a doc_list struct I get a segmentation error. I am confused because I declared my doc_list struct the same exact way as I did my word_list struct.
Below is the initialization of my structs
In my C file I initialize my Hash Table
#define BUFFSIZE 1000
#define STOPLIST_INDEX 0
#define DOCUMENTS_INDEX 1
struct HashTable{
int tableSize;
struct word_list** wordList;
};
struct word_list{
char* word;
struct doc_list** docList;
};
struct doc_list{
char* docName;
int timesAppear;
};
//Initialing lists associated with hash table
struct HashTable** initialize_hash_table(int argc, char** argv)
{
int k; //HashTables
int i; //Words
int q; //Document names
struct HashTable** hashTable = calloc(2, sizeof(struct HashTable **));
for(k =0; k < 2; k++)
{
hashTable[k] = calloc (1, sizeof(struct HashTable *));
hashTable[k]->wordList = calloc(BUFFSIZE, sizeof(struct word_list **));
for(i = 0; i < BUFFSIZE; i++)
{
hashTable[k]->wordList[i] = calloc(1, sizeof(struct word_list *));
hashTable[k]->wordList[i]->docList = calloc(30, sizeof(struct doc_list**));
for(q = 0; q < 30; q++)
{
hashTable[k]->wordList[i]->docList[q] = calloc(1, sizeof(struct doc_list*));
}
}
}
return hashTable;
}
then in my insert function where I store the document name char* value is where I get a segmentation error. I don't understand why this happens because I initialized my doc_list structure the exact same way that I initialized my word_list structure.
int insert(struct HashTable** hashTable, char* document_word, char* filename, int index)
{
//create the hash key
int key = hashFunction(document_word, BUFFSIZE);
//Check if word exists in Stop List
if(index == 0 || hashTable[STOPLIST_INDEX]->wordList[key]->word == NULL)
{
//insert into list
hashTable[index]->wordList[key] = malloc(sizeof(struct word_list*));
hashTable[index]->wordList[key]->word = strdup(document_word);
printf("%s%s\n", "INSERTED VALUE: ", hashTable[index]->wordList[key]->word);
//Add filename to words' document list
int w = 0;
puts("segfaulting here");
puts("1");
hashTable[index]->wordList[key]->docList[w] = malloc(sizeof(struct doc_list*));
hashTable[index]->wordList[key]->docList[w]->docName = strdup(filename);
printf("%s%s\n", "INSERTED ", filename);
printf("\n");
}
return 0;
}
What I believe is happening is that all the word structs are being declared NULL if they are not allocated memory for a word but none of the doc_list structs are being declared NULL for some reason. I allocated memory for them the exact same way I did the word_list structs.
The output when I run the program is this:
Hashing filename:stopwords.txt
---------
INSERTED VALUE: a
segfaulting here
1
Segmentation fault (core dumped)
What am I doing wrong??

Problems I see:
hashTable[k] = calloc (1, sizeof(struct HashTable *));
needs to be changed to
hashTable[k] = calloc (1, sizeof(struct HashTable));
Type of hasTable[k] is struct HashTable*. The object that it points to has to be of size struct HashTable, not struct HashTable*.
There is a similar error in:
struct HashTable** hashTable = calloc(2, sizeof(struct HashTable **));
It needs to be:
struct HashTable** hashTable = calloc(2, sizeof(struct HashTable*));
You won't see the error easily since sizeof(struct HashTable*) is equal to sizeof(struct HashTable**) in most cases.
More of such errors are in initialize_hash_table.
hashTable[k]->wordList[i]->docList = calloc(30, sizeof(struct doc_list**));
needs to be
hashTable[k]->wordList[i]->docList = calloc(30, sizeof(struct doc_list*));
hashTable[k]->wordList[i]->docList[q] = calloc(1, sizeof(struct doc_list*));
needs to be
hashTable[k]->wordList[i]->docList[q] = calloc(1, sizeof(struct doc_list));
You have similar errors in insert.
hashTable[index]->wordList[key] = malloc(sizeof(struct word_list*));
needs to be
hashTable[index]->wordList[key] = malloc(sizeof(struct word_list));
hashTable[index]->wordList[key]->docList[w] = malloc(sizeof(struct doc_list*));
needs to be
hashTable[index]->wordList[key]->docList[w] = malloc(sizeof(struct doc_list));

Tip: Only use calloc if you actually need your memory zeroed. malloc is faster.
Also, there is no need to test unequality to 0 NULL \0, unless you need your truth value normalized to 0|1, and even then !! is preferrable. ! for equality to 0 in any of its guises.
But your real problem is something else:
struct HashTable** hashTable = calloc(2, sizeof(struct HashTable **));
The above line alloates zeroed memory for 2 struct HashTable**, and stores the pointer in hashTable, which has type sttruct HashTable** too!!
You actually want to allocate space for 2 struct HashTable*.
In this one specific case it does not kill you, because those two pointer types happen to use the same amount of space on this architecture, but it's a pattern which is repeated with worse results later, and allocating too little memory leads to buffer overruns, which as Undefined Behavior mean anything can happen (and naturally mostly bad things).
When you want to point with pointer p to a memory block, allocate it thus:
p = malloc(count * sizeof *p);
p = calloc(count, sizeof *p); /* only for zeroed memory */
You do not want to use sizeof on the type, because it is far too easy to get it wrong, adding or leaving off one or more levels of indirection or taking a completely unrelated type.
Unless you name a VLA to sizeof, it will not evaluate its arguments, but only get the type and derive a compile-ime-constant.
Some more things you should read:
How to Debug Small Programs
C99 with Technical corrigenda TC1, TC2, and TC3 included
MCVE

Related

Problem with setting the array of pointers in the struct using malloc

I want to allocate a memory to an array of pointers in struct, but I receive the following error:
expression must be a modifiable lvalue
Here's struct code:
typedef struct {
int id;
char *entity[];
}entity;
Here's memory allocation in main function:
entity s;
s.entity= malloc(30 * sizeof(char *));
IDE underlines s.entity and pops the error I mentioned.
Please, help me out to solve this issue.
Your structure does not have a member called entity, only id and set.
You apparently want to allocate the whole structure. This type of struct member called flexible array member is useful if you want to allocate the whole structure in one malloc.
entity *s;
s = malloc(sizeof(*s) + 30 * sizeof(s -> set[0]));
This kind of struct members are very useful as you can realloc or free them in a single call.
Increase the size of the set array to 50
entity *tmp = realloc(s, sizeof(*s) + 50 * sizeof(s -> set[0]));
if(tmp) s = tmp;
Thats how you would allocate the pointers:
typedef struct {
int id;
char **set;
}entity;
int how_many_pointers = 30;
entity s;
s.set= malloc(how_many_pointers * sizeof(char *));
And for each pointer you would have to allocate the space for the corresponding string:
int i, string_size;
for(i = 0; i < how_many_pointers; i++)
{
printf("How many chars should have string number %d ?", i + 1);
scanf("%d", &string_size);
s.set[i] = malloc((string_size + 1) * sizeof(char)); // string + 1 due to space for '\0'
}

How do I dynamically allocate memory to a pointer array inside a structure

here is what i have in done so far
struct test_case {
int n;
int *test[];
};
struct test_case *test_case_struct = (struct test_case *)malloc(
sizeof(struct test_struct) + 100 * sizeof(int));
I need to allocate n pointers in the "test" pointer array. As far as i know i need to allocate space to the structure and then some more for the pointer array, but when i try to compile this, i get the error
invalid use of sizeof operator for to incomplete type struct test_struct
if someone could please inform me how i can take the value of n as a user input and have int *test [n] made possible.
Don't repeat type names. You already stumbled over your own code twice because you did that. You made the mistake of typing the wrong struct tag and confusing int* for int.
A more hardy allocation would look like this
struct test_case *test_case_struct =
malloc(sizeof (*test_case_struct) + sizeof (test_case_struct->test[0]) * 100);
This here will allocate the size of whatever test_case_struct points at, plus 100 more of whatever test_case_struct->test[0] should be. Now you can play with the structure definition without breaking this call to malloc. And if you do perform a breaking change (like renaming test), you'll be notified by your compiler promptly.
You need to change
sizeof(struct test_struct)
to
sizeof(struct test_case)
as test_struct is not the correct structure type.
In a better way, you can also use the already-declared variable name, like
struct test_case *test_case_struct = malloc(
sizeof (*test_case_struct) + n * sizeof(int*));
That said, you need to allocate memory worth of int *s, not ints, for the flexible member.
Also, below is a snippet which shows the count is taken as user input
int main(void)
{
int n = 0;
puts("Enter the count of pointers");
if (scanf("%d", &n) != 1) {
puts("Got a problem in the input");
exit (-1);
}
struct test_case *test_case_struct = malloc( sizeof(struct test_case) + n * sizeof(int*));
printf("Hello, world!\n");
return 0;
}
Currently you are using flexible array(aka zero length array).
Which can be allocated as below.
struct test_case *test_case_struct =
malloc(sizeof (*test_case_struct) + 100 * sizeof (int *));
Note missing * for int and typo sizeof(struct test_struct) in your code.
Alternatively you can use pointer to pointer as below.
struct test_case {
int n;
int **test;
};
struct test_case *test_case_struct = malloc(
sizeof(*test_case_struct));
test_case_struct->test = malloc(100 * sizeof(int *)); // Allocates 100 pointers

What should I use as the argument of sizeof when malloc [duplicate]

This question already has answers here:
malloc(sizeof(int)) vs malloc(sizeof(int *)) vs (int *)malloc(sizeof(int))
(2 answers)
Closed 5 years ago.
I always confuse about what to put inside of sizeof when malloc
for example,
struct sth *p = malloc(sizeof(struct sth));
or
struct sth *p = malloc(sizeof(struct sth *));
or, char ***p = malloc(sizeof(WHAT_SHOULD_I_PUT_HERE));???
someday, some c guru told me that use the variable like this:
struct sth *p = malloc(sizeof(*p));
So i wrote some code:
void main() {
int n = 1000000, i;
char **p = malloc(sizeof(char *) * n); // works
//char **p = malloc(sizeof(**p) * n); // not work, segfault
for(i=0; i<n; i++) {
// p[i] = malloc(sizeof(char)); // works
// p[i] = malloc(sizeof(p[i])); // works
// p[i] = malloc(sizeof(*p[i])); // works
}
for(i=0; i<n; i++) {
free(p[i]);
}
free(p);
}
still get confused, any easy way to remember?
sizeof(struct sth) is the size your struct takes in memory.
sizeof(struct sth*) is the size of a pointer to struct sth (usually 4 or 8 bytes); actually it's the size of any pointer on your platform.
So you need:
struct sth *p = malloc(sizeof(struct sth));
But it is better to write:
struct sth *p = malloc(sizeof(*p));
sizeof(*p); being the size of the object p points to and as p points to struct sth, sizeof(*p) is the same thing as sizeof(struct sth).
When you write sizeof, the C compiler computes the actual size of what you gave it. When you type sizeof (*int) for instance, you ask the compiler to compute the size of a ... pointer ! That is 4 or 8 bytes (32, 64 bits respectively) depending on your machine architecture.
However, if you type sizeof (struct foo) it will return the amount of bytes a struct of type foo would occupy in memory.
At some point you need to create enough memory for a struct and its values. So generally you want to pass sizeof (struct foo) to malloc.
If you want to use the *p rule then in the case below you need to do
char **p = malloc(sizeof(*p) * n);
Even if you have char ***p you would still use
char ***p = malloc(sizeof(*p) * n);

What is wrong with my dynamically allocated array of pointers to structs?

I have the following program that references array elements through a double pointer.
typedef struct {
int num1;
int num2;
int num3;
} DATA_SET;
typedef struct {
int structID;
DATA_SET *data_set_array; // Pointer to an array of DATA_SET structs
} MY_STRUCT;
int main () {
MY_STRUCT *Struct1;
DATA_SET **DataSetArray; // Array of pointers
Struct1 = malloc(sizeof(MY_STRUCT));
Struct1->data_set_array = malloc(sizeof(DATA_SET*)) //Allocate mem for the pointer to array of DATA_SETs
DataSetArray = malloc(sizeof(DATA_SET*) * 2) // Allocate mem for an array of 2 DATA_SET pointers
DataSetArray[0] = malloc(sizeof(DATA_SET)) // Allocate mem for the actual DATA_SET struct
DataSetArray[0]->num1 = 1;
DataSetArray[0]->num2 = 2;
DataSetArray[0]->num3 = 3;
DataSetArray[1] = malloc(sizeof(DATA_SET)) // Allocate mem for the actual DATA_SET struct
DataSetArray[1]->num1 = 1;
DataSetArray[1]->num2 = 2;
DataSetArray[1]->num3 = 3;
memcpy(Struct1->data_set_array, *DataSetArray, sizeof(DATA_SET*); //Copy data set array into Struct1
When I print all the data out in Struct1, i get:
Struct1->data_set_array[0].num1 = 1
Struct1->data_set_array[0].num2 = 2
Struct1->data_set_array[0].num3 = 3
Struct1->data_set_array[1].num1 = 50 //This should be 1
Struct1->data_set_array[1].num2 = 50 //This should be 2
Struct1->data_set_array[1].num3 = 65 //This should be 3
Seems to be misuse/data corruption for the 2nd element in the array.
I know there's probably different ways to do this, but I wanted to get familiar with referencing the array indices via double pointers. Am I allocating memory properly? I have a feeling the memcpy is incorrect.
Struct1->data_set_array = malloc(sizeof(DATA_SET*)
/* ^ wrong */
DataSetArray = malloc(sizeof(DATA_SET*) * 2)
/* ^ wrong */
You need to do sizeof(DATA_SET) because that is the actual size of a struct, not a pointer to a DATA_SET struct.
You're making the mistake of allocating only the size of a pointer times 2, which in many cases can be smaller than you'd hope for.
memcpy(Struct1->data_set_array, *DataSetArray, sizeof(DATA_SET*);
This is also wrong. You must copy the sizeof(DATA_SET). Keep in mind that sizeof(DATA_SET) is not equal to sizeof(DATA_SET*). A pointer's size in bytes is the same regardless of the type of pointer.
What is wrong with my dynamically allocated array of pointers to structs?
DataSetArray is an array of pointers to struct and there is not anything wrong with it.
The problem is 2 other things:
You can't use memcpy on an array of pointers to struct. The memory isn't consecutive.
Further, data_set_array is not an array of pointers to struct so you are trying to copy between incompatible types.
I guess you basically want to create a Double Dimension array. So basically you can do the code like this
struct abc {
int i;
};
struct abc **arr;
arr = (struct abc **) malloc(sizeof(struct abc) * 2);
arr[0] = (struct abc*)malloc(sizeof(struct abc));
arr[0]->i = 100;
arr[1] = (struct abc*)malloc(sizeof(struct abc));
arr[1]->i = 200;
One thing that you need to remember is that the outer array is just a pointer, so it doesn't need to be sizeof(abc) , it could very well be sizeof(int*) / sizeof (void*) etc.
so basically the above code could be written as
struct abc **arr;
arr = (struct abc **) malloc(sizeof(int *) * 2);
arr[0] = (struct abc*)malloc(sizeof(struct abc));
arr[0]->i = 100;
arr[1] = (struct abc*)malloc(sizeof(struct abc));
arr[1]->i = 200;
Hope this helps in underlying memory management you want to do with your code

How can I initialize and dynamically allocate an int pointer member in an array of structs?

How can I initialize and dynamically allocate an int pointer that is in an array of structs?
My program allows me to print enroll[0].grades[x], but when I try to access any other index value of enroll other than 0 (such as enroll[1].grades[x] or enroll[2].grades[x]), my program segmentation faults.
Here's my code...
How can I make enroll[2].grades[x], for example, initialize and equal zero?
In my struct:
struct Enroll
{
int *grades;
};
In main:
struct Enroll *enroll = (struct Enroll *) calloc(count.enroll, 10 * sizeof(struct Enroll));
enroll->grades = (int *) calloc(count.grades, 10 * sizeof(int));
In functions:
enroll[x].grades[y];
Allocate memory for number of struct Enrollements
struct Enroll *p = calloc(count.enroll, sizeof(struct Enroll));
Now you have the number of structures to be filled in and what you need is memory for the int pointer to hold values and the number of int pointers is count.enroll
for(i=0;i<count.enroll;i++)
{
p[i].grades = calloc(count.grades,sizeof(int));
// Fill in the values
}
PS: Alternatively you can go for malloc() followed by memset()
In main you should have
struct Enroll *enroll = calloc(count.enroll, sizeof(struct Enroll));
for(int i = 0; i < count.enroll ;i++)
{
enroll[i].grades = calloc(count.grades, sizeof(int));
}
In your code you have not allocated memory for each integer pointer.

Resources