I'm trying to implement a nested linked list in C, that will be used for a hierarchical menu. However, the GCC (v4.9.3-1) is complaining to nested structures, and I have no idea how to fix this. Here is the minimum (non)working example.
Is this nesting even possible in C?
main.c
#include "menu.h"
int main(void) {
Init_Menu();
return 0;
}
menu.c
#include "menu.h"
MenuItem_t LVL_0_MainMenu = {
.size = 0,
};
MenuItem_t LVL_1_Measurements = {
.size = 0,
};
void Init_Menu(void) {
Menu_Add_Child(&LVL_0_MainMenu, &LVL_1_Measurements);
}
void Menu_Add_Child(MenuItem_t *parent, MenuItem_t *child) {
parent->children[parent->size] = child;
child->parent = parent;
parent->size++;
}
menu.h
typedef struct {
unsigned char size;
MenuItem_t children[10];
MenuItem_t *parent;
} MenuItem_t;
extern MenuItem_t LVL_0_MainMenu;
extern MenuItem_t LVL_1_Measurements;
void Init_Menu(void);
void Menu_Add_Child(MenuItem_t *parent, MenuItem_t *child);
Based on answers by #bolov and #sps (once again, thanks to both of them), here is the minimum working example:
main.c
#include "menu.h"
int main(void) {
Init_Menu();
return 0;
}
menu.c
#include "menu.h"
MenuItem_t LVL_0_MainMenu = {
.size = 0,
};
MenuItem_t LVL_1_Measurements = {
.size = 0,
};
void Init_Menu(void) {
Menu_Add_Child(&LVL_0_MainMenu, &LVL_1_Measurements);
}
void Menu_Add_Child(MenuItem_t *parent, MenuItem_t *child) {
parent->children[parent->size] = child;
child->parent = parent;
parent->size++;
}
menu.h
struct MenuItem_t {
unsigned char size;
struct MenuItem_t *children[10];
struct MenuItem_t *parent;
};
typedef struct MenuItem_t MenuItem_t;
extern MenuItem_t LVL_0_MainMenu;
extern MenuItem_t LVL_1_Measurements;
void Init_Menu(void);
void Menu_Add_Child(MenuItem_t *parent, MenuItem_t *child);
The difference between this corrected program and the original (non)working program, is that the children array is defined as an array of pointers to variables of the type MenuItem_t instead of the array of variables of the same type. The other difference is that a nested list (inside the structure) should also contain the keyword struct as #bolov explained.
You need to use struct for the type used inside itself, even if you typedef it later on.
E.g. this won't work:
struct X_ {
X* next;
};
typedef struct X_ X;
But this will
struct X_ {
struct X_* next;
};
As a side note, I really don't like this form:
typedef struct {
} X;
I use:
struct X {
};
typedef struct X X;
But maybe this is just me being more fond of C++.
If you want to use that form, it's the same: you need to add struct and it works:
typedef struct {
struct X2* next;
} X2;
regarding:
struct X {
struct X arr[10];
};
You can't have that! The array is just in our way to understand why. So let's simplify:
struct X {
int a;
struct X var;
};
This can't be. What size would X be? sizeof(X) = sizeof(int) + sizeof(X) + padding. Do you see the problem? All you can do is have a pointer to X, but not an object X inside X.
Returning to your array. You need dynamic arrays:
struct X {
struct X* arr;
int arr_size;
};
It gets more complicated as you need to manage the memory (malloc/free fun), but you can't avoid it.
First of all, you cannot do,
typedef struct {
SomeName_t some_var;
} SomeName_t;
You need to do,
typedef struct somename {
struct somename some_var;
} SomeName_t;
Also, a struct cannot have a member which is an array of structure itself. However, a struct can have a member which is an array of pointer to the same structure.
struct foo {
struct foo foo_arr[10]; /* Will give error */
struct foo *foo_ptr_arr[10]; /* Legal */
};
However, I dont see a reason that your children member should be an array of struct anyways. Because, as can be seen in menu.c, you are doing
parent->children[parent->size] = child;
where the type of child is MenuItem_t *. So I think you basically wanted MenuItem_t.children to be an array of MenuItem_t *, and not an array of MenuItem_t.
So making this change should resolve your issue:
menu.h
typedef struct menuitem {
unsigned char size;
/* MenuItem_t children[10]; */ /* Not possible */
struct menuitem *children[10]; /* This is what you want to do */
struct menutem *parent;
} MenuItem_t;
Related
i need to create a struct with an attribute that is a pointer to the same struct.
i'm trying this solution but not work:
typedef struct
{
int number;
void *other;
}mystruct;
extern mystruct first[];
extern mystruct second[];
mystruct first[] = {{1,NULL},{2,second}};
mystruct second[] = {{3,NULL},{4,first}};
mystruct *wrap;
wrap = (mystruct *)first[1].other;
int main(void){
printf("%d\n",first[0].number);
printf("%d\n",second[0].number);
printf("%d\n",wrap[1].number);
}
can someone help me?
best regards and thankyou
In C, you can name the struct before using it and typdefing it:
typedef struct mystruct_
{
int number;
struct mystruct_ *other;
} mystruct
I'm not entirely sure but are you looking for some sort of linked-lists or precisely speak Self Referential structure
struct list {
int something;
struct list *use_this_to_point_to_similar_type;
};
Here is another good reference what-is-self-referencing-structure-in-c
just a little bit simplification, and moving few instructions here and there, below code is a loosely written example of possibly what you are looking forward to achieve
#include<stdio.h>
struct mystruct
{
int number;
struct mystruct *other;
};
struct mystruct first[] = {{1,NULL},{2,NULL}};
struct mystruct second[] = {{3,NULL},{4,NULL}};
struct mystruct *wrap;
int main(void)
{
first[1].other = second;
second[1].other = first;
wrap = first[1].other;
printf("%d\n",first[0].number);
printf("%d\n",second[0].number);
printf("%d\n",wrap[1].number);
return 0;
}
your first and second don't need to be extern as they are allocated within your program. you can declare and init. var prior to the main. but the rest you must move into the main function:
int main(void){
wrap = (first[1].other);
printf("%d\n",first[0].number);
printf("%d\n",first[1].number);
printf("%d\n",second[0].number);
printf("%d\n",wrap[1].number);
return 0;}
I'm getting the dereferencing pointer to incomplete type error when I try to run the following code. I've checked several other questions about this error and from what I can tell it's not due to a missing or extra struct keyword and I believe the pointer type is correct but I could be mistaken.
There might be other issues with the code as I'm just learning C, I'm happy to try and figure them out for myself I just can't seem to track down the issue with the incomplete type error.
Development/C/AI/test/src/test.c: In function ‘compare’:
Development/C/AI/test/src/test.c:10:19: error: dereferencing pointer to incomplete type ‘lrgraph_node {aka struct lrgraph_node}’
if ( strcmp(other->dataType, current->dataType == 0) ) {
test.c
#include "lrGraph.h"
#include <string.h>
int data = 1;
char *dataType = "int";
lrgraph_edge *connected[] = {};
unsigned numEdges = 0;
int compare( lrgraph_node *other, lrgraph_node *current ) {
if ( strcmp(other->dataType, current->dataType == 0) ) {
return (int)other->data - (int)current->data;
}
return -1;
}
int main() {
lrgraph_node *nodeA = lrgraph_createNode((void*)&data, dataType, &compare, connected, numEdges);
lrgraph_printVersion();
}
lrGraph.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lrGraph.h"
struct lrgraph_edge {
float weight;
lrgraph_node *nodeA;
lrgraph_node *nodeB;
};
struct lrgraph_node {
//data can be of any type
void *data;
//string to see if this node can be compared to another node based on data type
char *dataType;
int numEdges;
//comparator function which compares another node to this node
int (*compare)(lrgraph_node *other, lrgraph_node *current);
//array of connected edges
lrgraph_edge *connected[];
};
void lrgraph_printVersion() {
fprintf(stdout, "\nlrgraph version 0.01b\n");
}
lrgraph_node* lrgraph_createNode(void *data, char *dataType, int (*compare)(lrgraph_node* other, lrgraph_node* current), lrgraph_edge *connected[], unsigned numEdges) {
//allocate enough memory for the struct plus each pointer in the array of edges - https://stackoverflow.com/questions/32311269/can-we-have-a-struct-element-of-type-variable-length-array
lrgraph_node *node = malloc(sizeof(lrgraph_node) + numEdges * sizeof(lrgraph_edge));
if (NULL != node) {
node->data = data;
node->dataType = strdup(dataType);
node->compare = compare;
node->numEdges = numEdges;
//initialize each edge in the array
for( unsigned i=0; i < numEdges; i++) {
node->connected[i] = connected[i];
}
}
return node;
}
lrGraph.h
#ifndef LRGRAPH_H
#define LRGRAPH_H
typedef struct lrgraph_node lrgraph_node;
typedef struct lrgraph_edge lrgraph_edge;
lrgraph_node* lrgraph_createNode(void *data, char *dataType, int (*compare)(lrgraph_node *other, lrgraph_node *current), lrgraph_edge *connected[], unsigned numEdges);
void lrgraph_printVersion();
#endif /*LRGRAPH_H*/
"Incomplete type" means the compiler sees you're trying to use a struct type but there is no definition for that struct.
This is fine if you're only using pointers to structs (and is in fact how abstract data types are implemented in C), but if you want to dereference such a pointer, a struct definition must be visible.
In test.c only the contents of lrGraph.h are visible (i.e. typedef struct lrgraph_node lrgraph_node;), but the actual struct lrgraph_node { ... }; definition exists only in lrGraph.c.
Possible solution: Move the struct lrgraph_node { ... } definition into the header. (Alternatively, put the definition of compare into lrGraph.c).
I am still new in C. I know you can just use the already-declared struct as new data type such as int, double, etc. However, I encounter a struct written like this:
struct AdjListNode
{
int dest;
int weight;
struct AdjListNode* next;
};
In this struct, the data type of "next" pointer is struct AdjListNode*. What does struct have to do with the already-declared AdjListNode*? Thanks!
What does struct have to do with the already-declared AdjListNode*?
The answer is that the c syntax requires it.
You do not get a type AdjListNode by writing struct AdjListNode { ... };
AdjListNode is a struct tag and you always have to use struct AdjListNode when declaring variables.
See this simple example (without pointer inside the struct):
#include <stdio.h>
struct sSomeName
{
int x;
};
int main(void) {
struct sSomeName var; // OK, variable of type struct sSomeName
struct sSomeName* pVar; // OK, pointer to variable of type struct sSomeName
// sSomeName var2; // ERROR: unknown type name 'sSomeName'
var.x = 5;
pVar = &var;
printf("%d\n", pVar->x);
return 0;
}
So if you want to add a pointer inside the struct, you must write struct sSomeName just as you have to do inside main, i.e. like:
struct sSomeName
{
int x;
struct sSomeName* p;
};
Using typedef
If you want a type named AdjListNode you must use typedef.
A typedef example could look like:
#include <stdio.h>
typedef struct sSomeName sSomeName;
struct sSomeName
{
int x;
sSomeName* p;
};
int main(void) {
sSomeName var;
sSomeName* pVar;
var.x = 5;
var.p = NULL;
pVar = &var;
printf("%d\n", pVar->x);
printf("%p\n", (void*)pVar->p);
return 0;
}
Here with that declaration pointer to structure is declared. This is basically used for implementing linked list or for other data structures like tree.
It does'nt mean that struct is re-declared. It is similar to declare a struct variable.
The structure is created as follows: typedef struct AdjListNode. Example:
#include <stdio.h>
#include <stdlib.h>
typedef struct AdjListNode
{
int dest;
int weight;
struct AdjListNode* next;
}AdjListNode;
typedef struct Nodo{
char *nombre;
int *edad;
struct Nodo *siguiente;
}Nodo;
int main(int argc, char **argv) {
AdjListNode *nodo=malloc(sizeof(AdjListNode));
nodo->dest=1;
nodo->weight=2;
nodo->next=NULL;
printf("Nodo-->dest: %d", nodo->dest);
free(nodo);
}
i am currently having a lot of struggle with a, for me personally, very complex structure
struct crypto_tfm
{
uint32_t crt_flags;
union
{
struct ablkcipher_tfm ablkcipher;
struct aead_tfm aead;
struct blkcipher_tfm blkcipher;
struct cipher_tfm cipher;
struct hash_tfm hash;
struct compress_tfm compress;
struct rng_tfm rng;
} crt_u;
void (*exit)(struct crypto_tfm *tfm);
struct crypto_alg *crt_alg;
void *crt_ctx[] CRYPTO_MINALIGN_ATTR;
};
I completely have no idea how to use this struct. so basicly i am completely lost with this
the function using this expects a struct crypto_tfm *tfm
first idea is the following:
struct crypto_tfm *new_tfm()
{
struct crypto_tfm *tfm = malloc(sizeof(struct crypto_tfm));
tfm -> crt_flags = 0;
tfm -> crt_u.
}
but i dont know how to get further,
the given structs within the union are also using another structs. kinda too complicated for me right now
This is untested, but should be a good example:
struct st_a
{
int a;
};
struct st_b
{
int b;
};
union un_c
{
struct st_a aa;
struct st_b bb;
};
struct st_d
{
int d;
union un_c cc;
};
int main ()
{
struct st_d *dd = malloc (sizeof (struct st_d));
dd->d = 0;
/* The following two lines might (probably are) accessing
the same area of memory. */
dd->cc.aa.a = 0;
dd->cc.bb.b = 1;
}
Looked through many other SO posts related to this, but none were able to help me. So, I have the following structs defined:
typedef struct
{
int created;
double data;
int timeLeft;
int destination;
}dataPacket;
typedef struct
{
dataPacket *array;
int currIndex;
int firstIndex;
int nextTick;
int maxLength;
int length;
int stime;
int total;
}packetBuffer;
typedef struct{
int mac;
struct wire *lconnection;
struct wire *rconnection;
int numRecieved;
struct packetBuffer *buffer;
int i;
int backoff;
}node;
typedef struct{
float length;
float speed;
int busy;
struct dataPacket *currPacket;
struct node *lnode;
struct node *rnode;
}wire;
And then I'm trying to use the following function:
int sendPacket(node *n, int tick)
{
if(n->buffer->length > 0)
{
if(n->backoff <= 0)
{
if (n->lconnection->busy != 0 || n->lconnection->busy != 0)
{
n->i++;
n->backoff = (512/W * genrand()*(pow(2,n->i)-1))/TICK_LENGTH;
}
else
{
n->lconnection->busy = 1;
n->rconnection->busy = 1;
n->lconnection->currPacket = n->buffer[n->buffer->currIndex];
n->rconnection->currPacket = n->buffer[n->buffer->currIndex];
}
}
else
{
n->backoff--;
}
}
}
I'm getting the error described in the title everytime I try to access a member of buffer, lconnection, or rconnection.
struct packetBuffer *buffer;
You've defined a type packetBuffer (a typedef for an otherwise anonymous struct).
You haven't defined struct packetBuffer.
In the absence of an existing type struct packetBuffer, the compiler treats it as an incomplete type, assuming that you'll complete it later. The declaration
struct packetBuffer *buffer;
is perfectly legal, but you can't dereference buffer unless the type struct packetBuffer is visible.
Just drop the struct keyword.
(My personal preference is to drop the typedef and consistently refer to struct types as struct whatever, but that's a matter of style and taste.)
The following:
typedef struct {
int x;
char *y;
...
} my_struct;
creates an identifier for an anonymous structure. In order, for a structure to refer to an instance of itself, it must not be "anonymous":
typedef struct my_struct {
int x;
char *y;
struct my_struct *link
....
} my_struct_t;
This means that my_struct_t is now the type struct my_struct and not just an anonymous struct. Also, note that struct my_struct can be used within its own structure definition. That is not possible with anonymous structs.
As a final complication, the my_struct in struct my_struct is in a differenct "namespace" than the my_struct_t. This is sometimes used to to simplify (or confuse) things in code like this:
typedef struct my_struct {
int x;
char *y;
struct my_struct *link
....
} my_struct;
Now I can use my_struct anywhere in my code instead of struct my_struct.
Finally, you could separate the typedef from the structure definition to achieve the same effect:
struct my_struct {
int x;
char *y;
struct my_struct *link;
....
};
typedef struct my_struct my_struct;
As noted in David R.Hanson's C Interfaces and Implementations, "This definition is legal because structure, union, and enumeration tags occupy a same name space that is separate from the space for variables, functions, and type names."