Allocating memory to an array in a struct - c

I have defined a struct as below
struct Invariant
{
int * numberOfConstPi; // Saves the number of constant Pi in each kernel
Invariant * next;
};
I then modified it later in the code as
invariant->numberOfConstPi = (int *)calloc(invariant->numberOfUniqueKernels, sizeof(int));
invariant->numberOfConstPi[countKernel] = numberOfConstPi;
Where countKernel is an iterator and numberOfConstPi is a variable.
Is this the correct way? When I run the code I'm getting segmentation errors.
But when I instead defined the array as
int * hello = (int *)calloc(invariant->numberOfUniqueKernels, sizeof(int));
and
hello[countKernel] = numberOfConstPi;
It works perfectly fine.
Kindly ignore the int variable numerOfUniqueKernels. It's just a number which I deleted from the Struct(to make the struct look simpler for the question)

You don't show much code, but as for your question regarding this piece of code,
invariant->numberOfConstPi = (int *)calloc(invariant->numberOfUniqueKernels, sizeof(int));
invariant->numberOfConstPi[countKernel] = numberOfConstPi;
Is this the correct way?
I can say, this is a valid way to do it.
But you don't show much code and you say that you are running into segfault errors. I would guess that maybe you are not allocating memory for the pointer to struct?
You should have something like,
Invariant *invariant = malloc(sizeof*invariant);

Related

Initialising member elements of a dynamically allocated array of structs to zero

I have had a look around but have not been able to find an answer to this question already. I am trying to create a hash table of which each element is a struct. In each struct is a variable to let the program know if the cell has been occupied, for this to work I need to set all of them to zero. The thing is it worked fine but now and then (seemingly randomly) I'd get an access violation. I thought I fixed it but when I come to grow my array the error creeps up again, leading me to believe that I have made an error. My pointer knowledge is not that good at all, so any help would be appreciated. This is what the function looks like:
HashTableCell *initialiseTable(HashTableCell *hashTable, int *tableSizePtr)
{
int i = 0;
int totalSize = *tableSizePtr * sizeof(HashTableCell);
HashTableCell *tempStartingcell;
tempStartingcell = (HashTableCell*)malloc(sizeof(HashTableCell));
*tempStartingcell = *hashTable;
while (i <= *tableSizePtr)
{
/*we keep moving forward, need to use the first entry*/
*hashTable = *(tempStartingcell + (i * sizeof(HashTableCell)));
hashTable->isOccupied = 0;
i++;
}
free(tempStartingcell);
return hashTable;
}
And before I malloced some space for the table and passed it in another function like so:
HashTableCell *hashTable;
hashTable = (HashTableCell*)malloc((sizeof(HashTableCell)*tableSize));
hashTable = initialiseTable(hashTable, tableSizePtr);
The idea is to start at the beginning and move along the correct number of spaces along per iteration of the while loop. When I come to resize I merely make a new array with double the malloced space and pass it to the initialise function but this throws up an access violation error at seemingly random indexes.
I am using VS2015 if that helps anything.
Thank you for your help.
The problem is in this line:
*hashTable = *(tempStartingcell + (i * sizeof(HashTableCell)));
When you are adding an integer to a pointer, C and C++ already take into account the size of the array elements, so you should not multiply with sizeof(HashTableCell), but rather do:
*hashTable = *(tempStartingcell + i);
Otherwise, your extra multiplication will cause an access outside of the tempStartingCell array. It makes even more sense to write it like this:
*hashTable = tempStartingcell[i];
But there is more wrong with your code; if you just want to set isOccupied to zero for each element in hashTable, just do:
void initialiseTable(HashTableCell *hashTable, int tableSize)
{
for (int i = 0; i < tableSize; i++)
hashTable[i].isOccupied = 0;
}

Weird behaviour with variable length arrays in struct in C

I came across a concept which some people call a "Struct Hack" where we can declare a pointer variable inside a struct, like this:
struct myStruct{
int data;
int *array;
};
and later on when we allocate memory for a struct myStruct using malloc in our main() function, we can simultaneously allocate memory for our int *array pointer in same step, like this:
struct myStruct *p = malloc(sizeof(struct myStruct) + 100 * sizeof(int));
p->array = p+1;
instead of
struct myStruct *p = malloc(sizeof(struct myStruct));
p->array = malloc(100 * sizeof(int));
assuming we want an array of size 100.
The first option is said to be better since we would get a continuous chunk of memory and we can free that whole chunk with one call to free() versus 2 calls in the latter case.
Experimenting, I wrote this:
#include<stdio.h>
#include<stdlib.h>
struct myStruct{
int i;
int *array;
};
int main(){
/* I ask for only 40 more bytes (10 * sizeof(int)) */
struct myStruct *p = malloc(sizeof(struct myStruct) + 10 * sizeof(int));
p->array = p+1;
/* I assign values way beyond the initial allocation*/
for (int i = 0; i < 804; i++){
p->array[i] = i;
}
/* printing*/
for (int i = 0; i < 804; i++){
printf("%d\n",p->array[i]);
}
return 0;
}
I am able to execute it without problems, without any segmentation faults. Looks weird to me.
I also came to know that C99 has a provision which says that instead of declaring an int *array inside a struct, we can do int array[] and I did this, using malloc() only for the struct, like
struct myStruct *p = malloc(sizeof(struct myStruct));
and initialising array[] like this
p->array[10] = 0; /* I hope this sets the array size to 10
and also initialises array entries to 0 */
But then again this weirdness where I am able to access and assign array indices beyond the array size and also print the entries:
for(int i = 0; i < 296; i++){ // first loop
p->array[i] = i;
}
for(int i = 0; i < 296; i++){ // second loop
printf("%d\n",p->array[i]);
}
After printing p->array[i] till i = 296 it gives me a segmentation fault, but clearly it had no problems assigning beyond i = 9.
(If I increment 'i' till 300 in the first for loop above, I immediately get a segmentation fault and the program doesn't print any values.)
Any clues about what's happening? Is it undefined behaviour or what?
EDIT: When I compiled the first snippet with the command
cc -Wall -g -std=c11 -O struct3.c -o struct3
I got this warning:
warning: incompatible pointer types assigning to 'int *' from
'struct str *' [-Wincompatible-pointer-types]
p->array = p+1;
Yes, what you see here is an example of undefined behavior.
Writing beyond the end of allocated array (aka buffer overflow) is a good example of undefined behavior: it will often appear to "work normally", while other times it will crash (e.g. "Segmentation fault").
A low-level explanation: there are control structures in memory that are situated some distance from your allocated objects. If your program does a big buffer overflow, there is more chance it will damage these control structures, while for more modest overflows it will damage some unused data (e.g. padding). In any case, however, buffer overflows invoke undefined behavior.
The "struct hack" in your first form also invokes undefined behavior (as indicated by the warning), but of a special kind - it's almost guaranteed that it would always work normally, in most compilers. However, it's still undefined behavior, so not recommended to use. In order to sanction its use, the C committee invented this "flexible array member" syntax (your second syntax), which is guaranteed to work.
Just to make it clear - assignment to an element of an array never allocates space for that element (not in C, at least). In C, when assigning to an element, it should already be allocated, even if the array is "flexible". Your code should know how much to allocate when it allocates memory. If you don't know how much to allocate, use one of the following techniques:
Allocate an upper bound:
struct myStruct{
int data;
int array[100]; // you will never need more than 100 numbers
};
Use realloc
Use a linked list (or any other sophisticated data structure)
What you describe as a "Struct Hack" is indeed a hack. It is not worth IMO.
p->array = p+1;
will give you problems on many compilers which will demand explicit conversion:
p->array = (int *) (p+1);
I am able to execute it without problems, without any segmentation faults. Looks weird to me.
It is undefined behaviour. You are accessing memory on the heap and many compilers and operating system will not prevent you to do so. But it extremely bad practice to use it.

Allocating pointers inside an array of structs

OK, so the problem is basically like the title. Couldn't find a question that got all bits of it, so I figured I'd ask.
Say I want an array of structs shaped like the following
typedef struct s_woo{
char** n;
char* x;
} t_woo;
So I believe I should do
t_woo* woos = malloc(num_woos * sizeof(*woos));
Seems simple enough (and should deter people from yelling at me for my habit of casting malloc).
Then I want to initialize the things in each of those structs.
So intuitively I do:
for(i = 0; i < num_woos; i++){
num_ns = randomint1 / randomint2; //let's say num_ns is big, like 250-ish, average, and changes every round of the loop
woos[i].n = malloc(num_ns * sizeof(char*));
woos[i].x = malloc(num_ns * sizeof(char));
for(j = 0; j < num_ns; j++){
woos[i].n[j] = malloc(16 * sizeof(char)); // I just want 16 characters per char*
}
}
This is the boiled down version of what I have in my code. I want to know what can possibly go wrong with what I've written - like any possible thing. I'm not looking for anything in particular, just general problems with the above, like memory/heap issues, pointer mistakes etc.
Leave out "Virtual Memory Exhausted". My code error checks for that using a wrapper function on malloc, so I'm very sure that's not it.
Even better:
static const size_t woo_n_size = 16;
/* To make sure you use 16 everywhere,
* also easier to change it
*/
struct woo_item {
char n[woo_n_size];
char x;
};
struct s_woo {
struct woo_item *items;
size_t size; / * optinal, to keep track of item count */
}
With the woo_item struct you can make sure there is no x without n[woo_n_size] allocated, and vice versa.
You can remember the count of woo_items by having a designated null element to close each of your lists, or just store a size member in s_woo

Card game issues - memory and odd values

I got the most parts working, including randomizing and shuffling, but when it comes to allocating the right face / suit values, I can't get it right. Also, I'm getting 'Aborted (core dumped)', probably because I have very little idea what I'm doing with malloc (If anything at all, in this case).
typedef struct cards {
char suits[4][9], faces[13][6];
int suit, face, card;
} cards;
const int SHOE_SIZE = DECK_SIZE * numberOfDecks; // user given input, please disregard
cards shoe[SHOE_SIZE];
init_struct(&shoe);
cards *shoe_p = malloc(sizeof(cards) + 1000 * sizeof(int));
shoe_p = shoe;
int i;
for (i = 0; i < SHOE_SIZE; i++) {
shoe[i].card = i;
shoe[i].suit = shoe[i].card % 4; // maybe one of these should be % and another /
shoe[i].face = shoe[i].card % 13; // but when I try that, I get strings like "ace of ace"
printf("card #%d = %s of %s\n", i+1, shoe->faces[shoe[i].face], shoe->suits[shoe[i].suit]);
}
free(shoe);
The parts of code that I left out are doubtfully sources of the problems described. Please let me know if I should provide more information!
Edit: Additional question; Am I accessing my the struct members 'faces' and 'suits' in a proper manner? To me it would seem so, but then again, I can't see what else should cause the weird output of my string (see comment in code).
Also, can I have SHOE_SIZE as a member of my array, and access it in the same manner(shoe->variable), without having to assign it through the variable SHOE_SIZE first?
cards *shoe_p = malloc(sizeof(cards) + 1000 * sizeof(int));
shoe_p = shoe;
Here you are leaking memory: shoe_p pointed to some mallocated memory, but now you loose that pointer because you re-assign it to a pointer to the first element of shoe. I don't think you need these two lines at all.
free(shoe);
is wrong too: you didn't create shoe using malloc(), so you don't need to and must not free() it.
probably because I have very little idea what I'm doing with malloc
Right, but don't worry: you can improve your knowledge by reading this.
const int SHOE_SIZE = DECK_SIZE * numberOfDecks;
cards shoe[SHOE_SIZE];
These lines doesn’t make sense at all. The first line calculates (even as user given input) a constant at runtime. So while compiling its value isn't known yet. But in the next line you are using this unknown number to allocate non-dynamic memory at compilation time. So if you want to do this right, throw the second line away and use malloc() (as you did correctly a few lines below). Furthermore, you are discarding this memory with the shoe_p = shoe; line. The right way to solve this problem is:
...
const int SHOE_SIZE = DECK_SIZE * numberOfDecks;
cards *shoe = malloc(sizeof(cards) + 1000 * sizeof(int));
init_struct(&shoe);
int i;
...
And because you're using malloc() it is absolutely correct to free() it at the and.

Why does this C code work?

EDIT: Thank you very much for your responses. I understand this properly now!
I am trying to learn more on C pointers. Tinkering around, I am questioning the difference between two actions I am using.
This code seems to work at first glance, but I am not sure of what's the difference, and if any of these two approaches is wrong in some way.
I'd like to know what's the difference between the two pieces of code, when I should I pass the adress, and when a pointer to an array?
Is any of the pieces wrong? If so, what would be the proper way?
having a simple struct grid pretty much like struct grid { int val; } (for demonstration purposes)
First piece of code. Passing address of the pointer to the array.
void set (mygrid *grid, int foo){
grid->bar = foo; //should this be '*grid->bar?' But this seems to work properly.
}
void main(){
int i;
int* array;
int max = 24;
array = malloc(sizeof(grid) * max);
for(i = 0; i < max; i++){
set(&array[i], 0);
}
}
Second piece of code. I am not entirely sure why this works, but the compiler doesn't output any warning.
I am supposed to be passing the pointer to the start of the array like this?
void set(mygrid *grid, int foo){
int i; int max = 24; //so this example code compiles :P
for(i = 0; i < max; i++){
grid[i].bar = foo;
}
}
void main(){
int* array;
int max = 24;
array = malloc(sizeof(grid) * max);
set(array, 0); //Why not &array?
}
Passing an array decays into a pointer that points to the first member of the array, just like &array[0].
In your second example, array is just a pointer, and the return value from malloc is just the address of the start of the block of memory you get.
It doesn't have to be used for an array; it could be used for storage of an arbitrary sizeof(int) * max bytes of data. An array (in C) is really just a nice way of thinking about & working with a solid block of memory divided up into equal size portions.
Secondly, you should understand how my_array[i] works. All it does is take the address of where your block of array data starts (which is the actual value of my_array), and then look at what value is stored at a particular offset from there. Specifically, if my_array is of a (made up) type of WhatEver, then it will access the data from my_array + i*sizeof(WhatEver) to my_array + (i+1)*sizeof(WhatEver).
On a related note (since you're learning C), it's highly recommended to check that the return from malloc is not NULL before doing anything with it.
I'm no C guru but am also trying to improve my understanding so if this is incorrect, please leave a comment or edit my answer so I can learn from my mistakes :)
In your first piece of code
grid->bar is same as (*grid).bar
. and using name of an array refers to its base address. so writing array is equivalent &array[0]
&array[i] is equivalent to array+i
array[i] is equivalent to *(array +i)
In you second piece of code i dont understand why there is no error because in your function set you do not declare max and i dont see a global max variable too.
also in your second piece of code you use
set(array,0) because array is already an integer pointer(see the declaration int * array).As far as i understand the mygrid is not a struct but is an array of structs in the second example
In C, an array is pretty much the same as a pointer. For me this isn't so amazing, since it is one of the earlier programming languages I learned, but if you're coming from a high level language where an array is a different type of object, then it might come across as strange.

Resources