Why do I need double pointers? - c

I don't understand why I need double pointers inside 'struct graph'. Is it because it allows me to access one of the nodes that I made inside the function makeGraph()?
If I use one pointer (struct node *adjList) then I can't set the nodes to NULL that I made inside makeGraph().
I got the code frome programiz.com and in the article that explains this code it says: Don't let the struct node** adjList overwhelm you. All we are saying is we want to store a pointer to struct node*. This is because we don't know how many vertices the graph will have and so we cannot create an array of Linked Lists at compile time.
If I do: graph->adjList[1] does it go to the address of the second node or goes it inside the node? (I'm talking about the nodes that I create inside makeGraph())
I understand the rest of the code. If anyone can help me it would be appreciated.
#include <stdlib.h>
#include <stdio.h>
struct node
{
int vertex;
struct node *next;
};
struct graph
{
int numVertices;
struct node **adjList; // <--- THIS ONE
};
struct graph *makeGraph(int vertices) // Creating a Graph
{
struct graph *graph = malloc(sizeof(struct graph));
graph->numVertices = vertices;
graph->adjList = malloc(sizeof(struct node) * vertices); // creating the nodes
for (int i = 0; i < vertices; i++)
graph->adjList[i] = NULL; // Setting all nodes to NULL
return graph;
}
void addEdge(struct graph *graph, int src, int dest) // Add Edge
{
struct node *newNode = makeNode(dest);
newNode->next = graph->adjList[src];
graph->adjList[src] = newNode;
struct node *newNode2 = makeNode(src);
newNode2->next = graph->adjList[dest];
graph->adjList[dest] = newNode2;
return;
int main()
{
struct graph *graph1 = makeGraph(4);
addEdge(graph1, 0, 1);
addEdge(graph1, 0, 2);
addEdge(graph1, 0, 3);
}

An adjacency list is being represented as a linked list of struct node. The list is accessed by a pointer to the first element of the list. (The pointer will be NULL when the list is empty.) The pointer has type struct node *.
The graph has a number of vertices as set in the numVertices member of struct graph. Each vertex needs an adjacency list, and each adjacency list needs a struct node *. So the graph needs an array of struct node * of length numVertices. The authors of the code chose to allocate the array dynamically as a separate memory block pointed to by the adjList member. The type of the adjList member is a pointer to the element type. The element type is struct node * so the type of the adjList member is struct node **.
There is another way to allocate the memory for the struct graph and its adjacency list. They could be allocated as single block by changing the adjList member to be a flexible array member, as shown below:
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
struct node
{
int vertex;
struct node *next;
};
struct graph
{
int numVertices;
struct node *adjList[]; // <--- FLEXIBLE ARRAY MEMBER
};
struct graph *makeGraph(int vertices) // Creating a Graph
{
struct graph *graph = malloc(offsetof(struct graph, adjList[vertices]));
graph->numVertices = vertices;
for (int i = 0; i < vertices; i++)
graph->adjList[i] = NULL; // Setting all nodes to NULL
return graph;
}
offsetof(struct graph, adjList[vertices]) is the offset in bytes from the address of a struct graph to the address of the adjList[vertices] array member element. Allocating a block of memory of that size is just large enough to hold a struct graph plus the array of pointers. Another way to specify the size is sizeof(struct graph) + vertices * sizeof(struct node *) or alternatively sizeof(struct graph) + vertices * sizeof(graph->adjList[0]), but I think using the offsetof macro is a more succinct way to specify the size.

Related

C bus error when trying to acces a pointer in a pointer list, which is a struct point to a pointer

I get a bus error whenever I try the following to do the following:
#include <stdio.h>
#include <stdlib.h>
// The nodes that hold the data
typedef struct node {
struct node *next;
struct node *previous;
} Node;
// The list of the data
typedef struct list {
Node* head; // start of list of data
Node* tail; // end of list of data
} List;
// A vertex node, e.g. node 1. The list represents all the nodes (aka vertecies) that this vertex is connected to
typedef struct vertex {
List *L; // all the connected nodes (called nodes but is actually the numbers this node is connected to)
} Vertex;
// the list of all the vertices, which in themselves contain which nodes they are connected to (using a linked list)
typedef struct list_of_vertices {
Vertex** Lv;
} l_vertex;
// creats a list with init values of NULL, so we do not access garbage memory later on.
List* createL() {
List* L = malloc(sizeof(List));
L->head = NULL;
L->tail = NULL;
return L;
}
int main() {
l_vertex* L = malloc(sizeof(l_vertex));
L->Lv = malloc(sizeof(Vertex)*5); // 5 vertices in the list of vertex
for(int i = 0; i < 5; i++) {
L->Lv[i]->L = createL();
}
if(!L->Lv[0]->L->head) { // crash (bus error)
printf("There was no init\n");
}
return 0;
}
I do not get any compiler errors. What I am trying to do is have a list of Vertices, each vertex has a linked list with which vertex they are connected to. This means l_vertex -> list of vertices -> individual vertex -> list of connections -> individual connect.
How do I achieve this and why do I get "Bus error"? I know a bus error is, e.g., when you try to access un-allocated memory.
You've defined the Lv member of l_vertex to be a pointer-to-pointer to Vertex:
typedef struct list_of_vertices {
Vertex** Lv;
} l_vertex;
This means that Lv can contain an array of pointers to Vertex. But then here:
L->Lv = malloc(sizeof(Vertex)*5);
You allocate space for 5 instances of Vertex instead of 5 instances of Vertex, so you're not allocating the right amount of space. Then when you do this:
L->Lv[i]->L = createL();
The pointer L->Lv[i] has not been initialized, so attempting to dereference it triggers undefined behavior.
What you actually want in l_vertex is to hold an array of Vertex, so change it to:
typedef struct list_of_vertices {
Vertex *Lv;
} l_vertex;
This subsequently makes the allocation correct. Then you would access a Vertex like this:
L->Lv[i].L = createL();

Following C code why it is correct to use graph->array[i].head and graph->array[i]->head gives error?

I know that . is used when there is a direct access to a variable in the structure and -> is used when you are accessing a variable of a structure through a pointer to that structure. Also a->b is equivalent to (*a).b
Here we are accessing the pointer variable head of structure AdjList through a pointer stored in graph->array[i] but still using . for access.
graph->array[i].head = *((*graph).array+i).head
graph->array[i]->head = (* *((*graph).array+i)).head
// A structure to represent an adjacency list node
struct AdjListNode
{
int dest;
struct AdjListNode* next;
};
// A structure to represent an adjacency list
struct AdjList
{
struct AdjListNode *head;
};
// A structure to represent a graph. A graph
struct Graph
{
int V;
struct AdjList* array;
};
// A utility function that creates a graph of V vertices
struct Graph* createGraph(int V)
{
struct Graph* graph =
(struct Graph*) malloc(sizeof(struct Graph));
graph->V = V;
// Create an array of adjacency lists. Size of
// array will be V
graph->array =
(struct AdjList*) malloc(V * sizeof(struct AdjList));
// Initialize each adjacency list as empty by
// making head as NULL
int i;
for (i = 0; i < V; ++i)
graph->array[i].head = NULL;
return graph;
}
But when we do tree traversal we do root->left->left = (*(*root).left).left then it works fine.
If anyone can help me understand this with memory diagram that would be a great help, I made this memory diagram for better understanding.

How to access array linked lists on heap?

I am having a problem accessing an subarray of a node. I have two structs written where one contains the other. I'm not able to access the beyond the first node of the subarray.
struct node{
int distance;
int destination;
int weight;
node *adj;
};
struct adjList{
struct node *node;
adjList *array;
};// adjList a is made out of an array of "nodes". Essentially each element in the adjList a should have a pointer to a subarray of "nodes" that i can access.
a=(adjList*) malloc(numOfNodes * sizeof(struct adjList));//allocate space for array of linked lists
for(int j=0; j<numOfNodes; j++){
array[j].node=malloc(numOfEdges * sizeof(struct node));//allocate space for each linked list in the array
}
for(int j=0; j<numOfNodes; j++){
a[j].node->adj[j]=NULL; //trying to set the "jth's" element of the adjacencylist's "jth" node. This syntax does not work as the compiler wont let me even use it.
}
My whole goal here is to have an array of linked lists. Not sure why this method isnt working.
To have array of linked list, you need to create an array of pointers to the first node of linked lists.
struct node **array = malloc(sizeof(struct node*) * arraySize /* numOfNodes */);
Now array[i] will be pointing to ith linked list.
for(int i=0; i<arraySize ; i++){
struct node *head = NULL;
/* Allocate nodes for ith linked list */
for(int j=0; j<numOfNodes; j++) {
if(0 == j) {
array[i] = malloc(sizeof(struct node)); //First node of ith linked list
memset(array[i], 0, sizeof(struct node)); //OR you can use calloc. Required to remove junk pointers in node.
head = array[i];
} else {
head->adj = malloc(sizeof(struct node)); /* Allocate jth node */
memset(head->adj, 0, sizeof(struct node)); //OR you can use calloc. Required to remove junk pointers in node.
head = head->adj;
}
}
}
You can traverse ith linked list as below.
struct node *head = array[i];
while(head) {
printf("\ndist %d dest %d weight %d\n", head->distance, head->destination, head->weight);
head = head->adj;
}
You should read the man page malloc(3), in particular the calloc() part.
It is not enough to just put a pointer into a struct and assume that magically there will be an array. You have to reserve memory for it by using the functions described in that man page. And more importantly you have to free() the reserved memory, when you don't need it anymore.
Also you should consider making the length of your array part of your struct.
Like so:
struct node{
int distance;
int destination;
int weight;
node *adj;
size_t adj_count;
};
struct adjList{
struct node *node;
size_t node_count;
adjList *next; // I renamed this member to next,
// which makes it more clear that this is a linked list
};
EDIT: After you edited your question, there is suddenly a malloc(), but it is most certainly wrong. Or your naming of your data structures is very misleading.

array not storing the address of structure

I am trying to implement graph using adjacency list ,according to my knowledge that i have learnt so far if i created variable array pointer to struct adjlistnode of size v*sizeof(struct adjlistnode) thin i can store the addresses of v struct adjlistnode type node in each index of array
Means that each index of array will point to the node of type struct adjlistnode but when i am assigning G->array[i]=NULL it gives me error
||=== Build: Debug in teeest (compiler: GNU GCC Compiler) ===|
C:\Users\Mahi\Desktop\DATA STR\teeest\main.c||In function 'creategraph':|
C:\Users\Mahi\Desktop\DATA STR\teeest\main.c|59|error: incompatible types when assigning to type 'struct adjlistnode' from type 'void *'|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
why i am not able to assign NULL to index of array
what should i do if i want to access adjacency list like using G->array[i]=first node address adjacent to ith vertex of graph and later i will add another node if needed
struct adjlistnode{
int dest;
struct adjlistnode* next;
};
struct graph{
int V;
struct adjlistnode* array;
};
struct adjlistnode* getnewnode(int dest){
struct adjlistnode* newnode =(struct adjlistnode*)malloc(sizeof(struct adjlistnode));
newnode->dest=dest;
newnode->next=NULL;
return newnode;
}
struct graph* creategraph(int v){
struct graph* G=(struct graph*)malloc(sizeof(struct graph));
G->V=v;
G->array=(struct adjlistnode*)malloc(v*sizeof(struct adjlistnode));
for(int i=0;i<v;i++){
G->array[i] =NULL;
}
return G;
}
G->array is of type struct adjlistnode *
But
G->array[i] is of type struct adjlistnode.
Thus you cannot assign NULL (of type void *) to G->array[i] of type struct adjlistnode
You should probably have to define array in the struct graph as pointer to pointer
struct graph{
int V;
struct adjlistnode** array;
};
and then the following should work for you
struct graph* creategraph(int v){
struct graph* G=malloc(sizeof(struct graph));
G->V=v;
G->array=malloc(v*sizeof(struct adjlistnode*));
for(int i=0;i<v;i++){
G->array[i] =NULL;
}
return G;
}
** Note1 (as also mentioned by #alk in the comments) that in C, at least since C89 standard, malloc returns void *. void * can be assigned to any other pointer type (and visa versa), thus casting the return value of malloc is not required.
** Note2 (also noted by #alk) that malloc signature is defined with the parameter of type size_t and not int so better to modify the code a little and use the proper type ( Read comparing int with size_t and size_t vs int in C++ and/or C for more info)
array is a (single) pointer to struct adjlistnode. So it can be set to NULL.
G->array = NULL; //is okay
But it is not an array of pointers, so you cannot access the elements of the array and they cannot be set to NULL as well.
For dynamic allocation, you should do this:
struct graph{
int V;
struct adjlistnode** array;
};
struct graph* creategraph(int v){
struct graph* G = malloc(sizeof(struct graph));
G->V = v;
G->array = malloc(v * sizeof(struct adjlistnode*)); //allocation for an array of v pointers
for(int i = 0; i < v; i++){
G->array[i] = NULL;
}
return G;
}
As suggested by #alk, it is better if you pass v as size_t instead of int, as malloc takes size_t.
G->array[i] returns *(array + i * sizeof(struct adjlistnode)) as if array was struct adjlistnode array[].
What you do is store v objects of struct, but you try to initialize them with NULL, like you would a pointer.
What you probably want is
struct graph{
int V;
struct adjlistnode** array;
};
[...]
G->array=(struct adjlistnode**)malloc(v*sizeof(struct adjlistnode*));
That would make array a pointer to an array of pointers.
Then G->array[i] would return a struct adjlistnode* pointer to an object of struct, that you can then initialize with your getnewnode().

Is it possible to store a struct into a linked list?

I'm writing a program that solves a maze using DFS algorithm and stack. I was thinking of storing the coordinates of the path used to get to the end onto a struct containing integers x,y for coordinates and then pushing that struct onto a stack to perform other instructions on (print, pop, etc.).
I have searched all over and have yet to find anything that helps. So I went ahead and set it up but I'm getting an error about type compatibility since I have my node data as an int but I'm trying to put in a struct. Being new to linked lists I have only seen data as an int or char. Finally, is it even possible to do what I want? If not could you suggest a way of passing both x,y coordinates onto the stack? Thank you in advance.
Here's a sample of my code, where to save space a1 is an instance of COORD, and list is initialized as well as the maze and such.
typedef struct node {
int data; /* Value or data stored in node*/
struct node *pNext; /* Reference to the next node address */
} NODE;
/*Structure declares pointers for front and back of the list*/
typedef struct LIST {
NODE *front;
NODE *back;
} LIST;
/* Structure to pass multiple values onto stack */
typedef struct COORD{
int x;
int y;
}COORD;
/*Example of one of the functions */
void lst_push_front(LIST *l, COORD *a1) {
NODE *p = malloc(sizeof(NODE));
p->data = a1;
p->pNext = l->front;
l->front = p;
if(l->back == NULL) // was empty, now one elem
l->back = p;
}
Check the code below.
Since COORD is a structure you can include it in another structure as shown in the below code.
Also make sure that the ordering of the structures are proper.
p->data.x is the right way to access the members of the structure COORD
#include <stdio.h>
/* Structure to pass multiple values onto stack */
typedef struct COORD{
int x;
int y;
}COORD;
typedef struct node {
COORD data; /* --> Changes done here */
struct node *pNext; /* Reference to the next node address */
} NODE;
/*Structure declares pointers for front and back of the list*/
typedef struct LIST {
NODE *front;
NODE *back;
} LIST;
void func(COORD *q)
{
NODE *p = malloc(sizeof(NODE));
p->data.x = q->x;
p->data.y = q->y;
printf("%d %d",p->data.x,p->data.y);
free(p);
}
int main(void) {
COORD *q = malloc(sizeof(COORD));
q->x = 20;
q->y = 30;
func(q);
free(q);
return 0;
}
As #barak manos mentions you should put COORD struct before NODE and change int data to COORD data and use p->data = *a1

Resources