1

I want to know how to store custom objects (not their pointers) in C. I have created a custom structure called Node

#define MAXQ 100

typedef struct {
  int state[MAXQ];
  int height;
} Node;

(which works) and I want to store a few of these Nodes in a container (without using pointers, since they are not stored elsewhere) so I can access them later.

The internet seems to suggest something like calloc() so my last attempt was to make a container Neighbors following this example, with numNeighbors being just an integer:

Node Neighbors = (Node*)calloc(numNeighbors, sizeof(Node));

At compilation, I got an error from this line saying
initializing 'Node' with an expression of incompatible type 'void *'

and in places where I referenced to this container (as in Neighbors[i]) I got errors of
subscripted value is not an array, pointer, or vector

Since I'm spoiled by Python, I have no idea if I've got my syntax all wrong (it should tell you something that I'm still not there after scouring a ton of tutorials, docs, and stackoverflows on malloc(), calloc() and the like), or if I am on a completely wrong approach to storing custom objects (searching "store custom objects in C" on the internet gives irrelevant results dealing with iOS and C# so I would really appreciate some help).

EDIT: Thanks for the tips everyone, it finally compiled without errors!

mehfluffy
  • 49
  • 1
  • 9

4 Answers4

2

You can create a regular array using your custom struct:

Node Neighbors[10];

You can then reference them like any other array, for example:

Neighbors[3].height = 10;
2

If your C implementation supports C.1999 style VLA, simply define your array.

Node Neighbors[numNeighbors];

(Note that VLA has no error reporting mechanism. A failed allocation results in undefined behavior, which probably expresses itself as a crash.)

Otherwise, you will need dynamic allocation. calloc is suitable, but it returns a pointer representing the contiguous allocation.

Node *Neighbors = calloc(numNeighbors, sizeof(*Neighbors));

Note, do not cast the result of malloc/calloc/realloc when programming in C. It is not required, and in the worst case, can mask a fatal error.

jxh
  • 69,070
  • 8
  • 110
  • 193
1

malloc and calloc are for dynamic allocation, and they need pointer variables. I don't see any reason for you to use dynamic allocation. Just define a regular array until you have a reason not to.

#define MAXQ 100
#define NUM_NEIGHBORS 50

typedef struct {
  int state[MAXQ];
  int height;
} Node;

int main(void)
{
  Node Neighbors[NUM_NEIGHBORS];

  Neighbors[0].state[0] = 0;
  Neighbors[0].height = 1;
}

Here NUM_NEIGHBORS needs to be a constant. (Hence static) If you want it to be variable or dynamic, then you need dynamic allocations, and pointers inevitably:

#define MAXQ 100

typedef struct {
  int state[MAXQ];
  int height;
} Node;

int main(void)
{
  int numNeighbors = 50;
  Node *Neighbors;

  Neighbors = (Node*)calloc(numNeighbors, sizeof(Node));
  Neighbors[0].state[0] = 0;
  Neighbors[0].height = 1;
}
jaeheung
  • 1,208
  • 6
  • 7
1

I want to store a few of these Nodes in a container (without using pointers, since they are not stored elsewhere) so I can access them later.

If you know the amount of them at compile-time (or at the very least a reasonable maximum); then you can create an array of stack-allocated objects. For instance, say you are OK with a maximum of 10 objects:

#define MAX_NODES 10

Node nodes[MAX_NODES];
int number_nodes = 0;

Then when you add an object, you keep in sync number_nodes (so that you know where to put the next one). Technically, you will always have 10, but you only use the ones you want/need. Removing objects is similar, although more involved if you want to take out some in the middle.

However, if you don't know how many you will have (nor a maximum); or even if you know but they are way too many to fit in the stack; then you are forced to use the heap (typically with malloc() and free()):

int number_nodes; // unknown until runtime or too big
Node * nodes = malloc(sizeof(Node) * number_nodes);
...
free(nodes);

In any case, you will be using pointers in the dynamically allocated memory case, and most probably in the stack case as well.

Python is hiding and doing all this dance for you behind the scenes -- which is quite useful and time saving as you have probably already realized, as long as you do not need precise control over it (read: performance).

Acorn
  • 24,970
  • 5
  • 40
  • 69