managing a collection of structs in c - c

I am learning c, and have come across an issue storing and managing structs; let me explain.
I am quite familiar with Java, and I am starting to understand how to properly use pointers and references in c. My goal is to make and store hundreds of stuct:
struct creature{
int id;
char name[12];
}
In java, I am able to create an Array like:
creature c [];
and then store and manipulate objects inside that array. I want the same effect in c using a struct "creature".
My first attempt was:
creature *creatures = malloc(sizeof(creature));
I am not entirely sure what that even does. My goal was to create a block of memory that strictly held struct pointers, like the Java array.
from here, I want to create new creature structs, and store their pointers in the creatures variable, that has memory allocated from using malloc.
I hope this was enough information to explain my problem.
Thanks!

Right, so what you want is an array of pointers. Note that in Java, whenever you have something like:
String s = ...;
This translates to a pointer in c:
String *s = ...;
Let's take the easy case first of a fixed-size array of pointers. This is simply:
creature *creatures[10];
for (var i=0; i < 10; i++) {
creatures[i] = malloc(sizeof(creature));
}
Now you have an array of pointers to creatures, each malloced separately. But, if you don't know how big your array of creatures should be, then you have to malloc the array of creatures. Note that if you have, say, a malloced int array, you'd do the following:
int *ints = malloc(sizeof(int) * 10);
ints[0]; ints[1]; //etc...
That is, an array is represented as a pointer to the first element. What you want now is an array of pointers, which ends up being a pointer to a pointer:
var numCritters = 10;
creature **creatures = malloc(sizeof(creature *) * numCritters);
for (var i=0; i < numCritters; numCritters++) {
creatures[i] = malloc(sizeof(creature));
}
The first malloc creates a pointer to an array of creature * pointers. Note we use sizeof(creature *) here, not sizeof(creature), because the array is of pointers, not of creatures.
Each of the next mallocs then creates a pointer to a creature, same as in the case of a fixed-size array.
Be sure to have a free for each malloc - that is, one for each creature * and one for the creature **.
Note that this is different from what Pankrates suggested. Which solution you want to use depends on what you want to do. His creates a big block of creatures:
creature *creatures = +--------------------+
| |
| |
| Creature 0 |
| |
| |
+--------------------+
| |
| |
| Creature 1 |
| |
| |
+--------------------+
| |
| |
| Creature 2 |
| |
| |
+--------------------+
| ... |
Whereas mine creates an array of pointers, each one pointing to a creature:
+--------------------+
| |
creature *creatures = +------+ | |
| ptr0 | ----> | Creature 0 |
+--------------------+ +------+ | |
| | +-- | ptr1 | | |
| | | +------+ +--------------------+
| Creature 1 | <-+ | ptr2 | --+
| | +------+ | +--------------------+
| | | .... | | | |
+--------------------+ | | |
+-> | Creature 2 |
| |
| |
+--------------------+

You are almost there. malloc takes the number of bytes that you want to allocate as an argument, therefore you need to multiply the size of the struct times the number of structs that you want to allocate:
int number_of_creatures = 10;
creature *creatures = malloc(sizeof(creature) * number_of_creatures);
You should also always check the returned pointer from malloc() to check if the allocation was successful
if (creatures == NULL)
printf("Allocating memory failed!\n");

Related

container_of sample code in lwn.net

When seeing:
void my_object_release(struct kobject *kobj)
{
struct my_object *mine = container_of(kobj, struct my_object, kobj);
/* Perform any additional cleanup on this object, then... */
kfree (mine);
}
in LWN’s The zen of kobjects, it seems incorrect in the third parameter kobj. I think it should be kobject.
The given code is correct: the third argument is the name of the container structure member to which the pointer points, not its type, so kobj is right. The example is somewhat confusing since the first kobj doesn’t correspond to the same thing as the second kobj: the first is the pointer in the caller’s scope.
Here’s a diagram to hopefully clarify the parameters of container_of:
container_of(kobj, struct my_object, kobj)
| | |
| | |
\------------+----------+--------------------------------\
| | |
| | |
/-----------------/ | |
| | |
V /-------------/ |
+------------------+ | |
| struct my_object | { | |
+------------------+ V V
+------+ +------+
struct kobject | kobj |; <-- You have a pointer to this, called | kobj |
+------+ +------+
...
};
container_of allows you to pass around a kobject pointer and find the containing object (as long as you know what the containing object is) — it allows you to use your knowledge of “what” to answer “where”.
It’s worth pointing out that container_of is a macro, which is how it can do seemingly impossible things (for developers not used to meta-programming).

Thread1: EXC_BAD_ACCESS (code=2, address = ox7fff5eb364bc) Parsing a CSV-file in c [duplicate]

I've got this code in C language:
char *options[100000];
int k[100000];
char *param[100000];
int n;
int i,j;
...
scanf("%d",&n);
for (i=0;i<n;i++)
{
scanf("%s%d",&options[i],&k[i]);
param[i]="On";
}
...
just as the programm reaches this point:
scanf("%s%d",&options[i],&k[i]);
I get the runtime error (stack overflow).
The input here should be like this:
word1 number1
word2 number2
and so on. I've got no idea why is this happening. What's the problem?
Ok... so I thought someone would provide an answer to your stack overflow problem but so far everybody only mentioned a problem you actually have (more on this later) that is unrelated to the stack overflow (it'll be problematic but only once you fix this first).
-----------------
| Your stack |
| (grows down) |
| |
-----------------
| |
| |
| |
| |
| |
| | -- max stack size is here
| |
| |
| |
| |
| |
-----------------
| Your heap |
| (grows up) |
| |
-----------------
And then you try to allocate a bunch of really big arrays and run out of space
-----------------
| Your stack |
| (grows down) |
| |
| |
| |
| |
| |
| |
| |
| | -- max stack size is here
| |
----------------- -- what you actually need
| |
| |
| |
| |
-----------------
| Your heap |
| (grows up) |
| |
-----------------
So you get a run-time error (stack overflow) because you've tried to use more stack space than what you have available.
The trick here is to use heap allocation (because on most platforms, at least all the ones I've heard of) the heap is massively bigger than the stack.
To allocate memory on the heap you use malloc (also, when you're done with it don't forget to release the memory using free, or else you'll leak the memory).
EDIT:
Bonus: The other problem you have. Other answers seem to indicate you're access/dereferencing/using memory that's not allocated. You're partially actually fine on this point.
You scanf call point to a char array (here's the problem) and an int in the array k (no problem. So right now all the entries in the options array point to nowhere/anywhere. You need to allocate memory for them (again using malloc).
As for strdup it allocates the memory itself and returns the pointer, again no problem here. Just don't forget to free it after you're done using it because again this would be a memory leak.
char *options[100000] allocates 100000 string pointers, not strings.
scanf is being passed gibberish.

How memory is allocated when we use malloc to create 2-dimensional array?

I want to create an integer array[5][10] using malloc(). The difference between memory address of array[0] and array[1] is showing 8. Why?
#include <stdio.h>
#include <stdlib.h>
int main() {
int *b[5];
for (int loop = 0; loop < 5; loop++)
b[loop] = (int*)malloc(10 * sizeof(int));
printf("b=%u \n", b);
printf("(b+1)=%u \n", (b + 1));
printf("(b+2)=%u \n", (b + 2));
}
The output is:
b=2151122304
(b+1)=2151122312
(b+2)=2151122320
The difference between memory address of array[0] and array[1] is showing 8. Why?
That's because sizeof of a pointer on your platform is 8.
BTW, use of %u to print a pointer leads to undefined behavior. Use %p instead.
printf("(b+1)=%p \n",(b+1));
printf("(b+2)=%p \n",(b+2));
Difference between array of pointers and a 2D array
When you use:
int *b[5];
The memory used for b is:
&b[0] &b[1] &b[2]
| | |
v v v
+--------+--------+--------+
| b[0] | b[1] | b[2] |
+--------+--------+--------+
(b+1) is the same as &b[1]
(b+2) is the same as &b[2]
Hence, the difference between (b+2) and (b+1) is the size of a pointer.
When you use:
int b[5][10];
The memory used for b is:
&b[0][0] &b[1][0] &b[2][0]
| | |
v v v
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ ...
| | | | | | | | | | | | | | | | | | | | | ...
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ ...
(b+1) is the same as &b[1], The value of that pointer is the same as the value of &b[1][0] even though they are pointers to different types.
(b+2) is the same as &b[2], The value of that pointer is the same as the value of &b[2][0]
Hence, the difference between (b+2) and (b+1) is the size of 10 ints.
First, with int *b[5] you are not creating a two dimensional array, but an array of pointers.
The elements of the array b are pointers. Each occupies the size of a pointer, which depends on your architecture. In a 64-bits architecture it will probably occupy 64 bits (8 bytes). You can check that by printing sizeof(int*) or sizeof(b[0])
Memory allocation will look like
b
+-----+
| | +------+------+-----------+-----+-----+-----+-----+
| b[0]+--------------> | | | | | | | |
| | +------+------+-----------+-----+-----+-----+-----+
+-----+
| | +------+------+-----------+-----+-----+-----+-----+
| b[1]+--------------> | | |....... | | | | |
| | +------+------+-----------+-----+-----+-----+-----+
+-----+
| | +------+------+-----------+-----+-----+-----+-----+
| b[2]+--------------> | | | ...... | | | | |
| | +------+------+-----------+-----+-----+-----+-----+
+-----+
| | +------+------+-----------+-----+-----+-----+-----+
| b[3]+--------------> | | | ...... | | | | |
| | +------+------+-----------+-----+-----+-----+-----+
+-----+
| | +------+------+-----------+-----+-----+-----+-----+
| b[4]+--------------> | | | ...... | | | | |
| | +------+------+-----------+-----+-----+-----+-----+
+-----+
b will point to b[0], after decay, and b + 1 will give the address of b[1]. Size of pointer on your machine is 8 bytes, therefore you are getting a difference of 8 in the address.
Beside of this
Do not cast return value of malloc
b[loop]=malloc(10*sizeof(int));
and use %p for pointer data type
printf("b=%p \n",(void *)b);
printf("(b+1)=%p \n",(void *)(b+1));
printf("(b+2)=%p \n",(void *)(b+2));
What you've declared is not technically a two dimensional array but an array of pointers to int, each of which points to an array of int. The reason array[0] and array[1] are 8 bytes apart is because you have an array of pointers, and pointers on your system are 8 bytes.
When you allocate each individual 1 dimensional array, they don't necessarily exist next to each other in memory. If on the other hand you declared int b[5][10], you would have 10 * 5 = 50 contiguous integers arranged in 5 rows of 10.

runtime error (stack overflow)

I've got this code in C language:
char *options[100000];
int k[100000];
char *param[100000];
int n;
int i,j;
...
scanf("%d",&n);
for (i=0;i<n;i++)
{
scanf("%s%d",&options[i],&k[i]);
param[i]="On";
}
...
just as the programm reaches this point:
scanf("%s%d",&options[i],&k[i]);
I get the runtime error (stack overflow).
The input here should be like this:
word1 number1
word2 number2
and so on. I've got no idea why is this happening. What's the problem?
Ok... so I thought someone would provide an answer to your stack overflow problem but so far everybody only mentioned a problem you actually have (more on this later) that is unrelated to the stack overflow (it'll be problematic but only once you fix this first).
-----------------
| Your stack |
| (grows down) |
| |
-----------------
| |
| |
| |
| |
| |
| | -- max stack size is here
| |
| |
| |
| |
| |
-----------------
| Your heap |
| (grows up) |
| |
-----------------
And then you try to allocate a bunch of really big arrays and run out of space
-----------------
| Your stack |
| (grows down) |
| |
| |
| |
| |
| |
| |
| |
| | -- max stack size is here
| |
----------------- -- what you actually need
| |
| |
| |
| |
-----------------
| Your heap |
| (grows up) |
| |
-----------------
So you get a run-time error (stack overflow) because you've tried to use more stack space than what you have available.
The trick here is to use heap allocation (because on most platforms, at least all the ones I've heard of) the heap is massively bigger than the stack.
To allocate memory on the heap you use malloc (also, when you're done with it don't forget to release the memory using free, or else you'll leak the memory).
EDIT:
Bonus: The other problem you have. Other answers seem to indicate you're access/dereferencing/using memory that's not allocated. You're partially actually fine on this point.
You scanf call point to a char array (here's the problem) and an int in the array k (no problem. So right now all the entries in the options array point to nowhere/anywhere. You need to allocate memory for them (again using malloc).
As for strdup it allocates the memory itself and returns the pointer, again no problem here. Just don't forget to free it after you're done using it because again this would be a memory leak.
char *options[100000] allocates 100000 string pointers, not strings.
scanf is being passed gibberish.

casting void** to 2D array of int - C

i am trying to cast a void** pointer to an int** 2D array in C
here is the code that i am trying to work with (with all the extraneous bits removed):
\*assume that i have a data structure called graph with some
*element "void** graph" in it and some element "int order" */
void initialise_graph_data(graph_t *graph)
{
void **graph_data = NULL;
int (*matrix)[graph->order];
size_t size = (graph->order * graph->order) * sizeof(int);
graph_data = safe_malloc(size); /*safe malloc works fine*/
matrix = (int(*)[graph->order])graph_data;
graph->graph = graph_data;
}
when i compile that, it works fine, but gives me a warning that variable 'matrix' is set but not used. i dont really want to have to use the interim matrix variable because the function is just supposed to initialise the array, not put anything in it; but if i try to cast graph_data directly to an int** when i am assiging it to graph->graph like so:
graph->graph = (int(*)[graph->order])graph_data;
it gives me an assignment from incompatible pointer type warning.
am i just not casting it properly? does anyone have any suggestions as to how i can make it work without the interim "matrix" variable? or if not, what i can do with that variable so that it doesnt give me the warning that it is set but not used?
thanks
The compiler is right, an array of arrays (or a pointer to an array) is not the same as a pointer to a pointer. Just think about how they would be laid out in memory:
A matrix of size MxN in the form of an array of arrays:
+--------------+--------------+-----+----------------+--------------+-----+------------------+
| matrix[0][0] | matrix[0][1] | ... | matrix[0][N-1] | matrix[1][0] | ... | matrix[M-1][N-1] |
+--------------+--------------+-----+----------------+--------------+-----+------------------+
A and the same "matrix" in the form of pointer to pointer:
+-----------+-----------+-----------+-----+
| matrix[0] | matrix[1] | matrix[2] | ... |
+-----------+-----------+-----------+-----+
| | |
| | V
| | +--------------+--------------+-----+
| | | matrix[2][0] | matrix[2][1] | ... |
| | +--------------+--------------+-----+
| |
| V
| +--------------+--------------+-----+
| | matrix[1][0] | matrix[1][1] | ... |
| +--------------+--------------+-----+
|
V
+--------------+--------------+-----+
| matrix[0][0] | matrix[0][1] | ... |
+--------------+--------------+-----+
It doesn't matter if you allocate the correct size, the two variables simply are incompatible which is what your compiler is telling you.

Resources