While writing an adjacency list from scratch I'm facing some problem with addressing and allocating memory for an array of struct. (ignore directed/undirected list).After hours of debugging I've found the code is keeping (updates) only the last two inputs in the adjacency list. I want to know what and how actually I'm messing up the memory allocation and accessing it.
Don't forget to give me further study links on this topic/issue, please. Thank's in advance.
Here's my code-
/*a single node of an adjacency list*/
typedef struct adjList{
int dest;
struct adjList *next;
} adjList;
/*Image of a graph...*/
typedef struct Image{
int source;
adjList *head;
} Image;
void add_adj_edge(Image graph[], int source, int destiny);
int main() {
int vertices = 6;
Image graph[vertices];
//need not to mention detailed here
// initialize_graph(graph, vertices);
add_adj_edge(graph, 1, 2);
add_adj_edge(graph, 1, 4);
add_adj_edge(graph, 1, 5);
add_adj_edge(graph, 1, 6);
print_graph(graph, vertices);
printf("graph[1].head->dest: %d\n", graph[1].head->dest);
return 0;
}
void add_adj_edge(Image *graph, int src, int dest){
adjList *cache = malloc(sizeof(adjList));
/*create a single node*/
cache->dest = dest;
cache->next = NULL;
if(graph[src].head == NULL){
graph[src].head = cache;
}
else{
while( graph[src].head->next != NULL){
graph[src].head = graph[src].head->next;
}
graph[src].head->next = cache;
}
return;
}
The output
node: 1 5 6
node: 2
node: 3
node: 4
node: 5
node: 6
graph[1].head->dest: 5
Instead of
node: 1 2 4 5 6
node: 2
node: 3
node: 4
node: 5
node: 6
graph[1].head->dest: 2
As I mentioned as comment, your source code has some missing and also misunderstanding on how to update a linked-list.
First problem: (allocating Image graph[vertices]; in your main() doesn't initialize value).
It is necessary to set adjList *head; property to NULL to be sure
that if(graph[src].head == NULL) will be true at the first access.
int vertices = 6;
Image graph[vertices];
for(int i=0;i<vertices;i++) {
graph[i].head = NULL; // list is empty
graph[i].source = 0; // or what ever you want
}
Second problem: (when adding a new node at the end of a linked-list, it is necessary to use a temporary variable to explore previous node).
If you are using graph[src].head = graph[src].head->next; you will
overwrite all previous nodes by the last one.
Use the following method in add_adj_edge()to explore nodes:
adjList *pTmp;
// point to the first node
pTmp = graph[src].head;
// explore node until the last has no node
while( pTmp->next != NULL){
pTmp = pTmp->next;
}
// update the next node
pTmp->next = cache;
Related
I'm still learning how to program in C and I've stumbled across a problem.
Using a char array, I need to create a linked list, but I don't know how to do it. I've searched online, but it seems very confusing. The char array is something like this char arr[3][2]={"1A","2B","3C"};
Have a look at this code below. It uses a Node struct and you can see how we iterate through the list, creating nodes, allocating memory, and adding them to the linked list. It is based of this GeeksForGeeks article, with a few modifications. I reccommend you compare the two to help understand what is going on.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char value[2];
struct Node * next;
};
int main() {
char arr[3][2] = {"1A","2B","3C"};
struct Node * linked_list = NULL;
// Iterate over array
// We calculate the size of the array by using sizeof the whole array and dividing it by the sizeof the first element of the array
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
// We create a new node
struct Node * new_node = (struct Node *)malloc(sizeof(struct Node));
// Assign the value, you can't assign arrays so we do each char individually or use strcpy
new_node->value[0] = arr[i][0];
new_node->value[1] = arr[i][1];
// Set next node to NULL
new_node->next = NULL;
if (linked_list == NULL) {
// If the linked_list is empty, this is the first node, add it to the front
linked_list = new_node;
continue;
}
// Find the last node (where next is NULL) and set the next value to the newly created node
struct Node * last = linked_list;
while (last->next != NULL) {
last = last->next;
}
last->next = new_node;
}
// Iterate through our linked list printing each value
struct Node * pointer = linked_list;
while (pointer != NULL) {
printf("%s\n", pointer->value);
pointer = pointer->next;
}
return 0;
}
There are a few things the above code is missing, like checking if each malloc is successful, and freeing the allocated memory afterwards. This is only meant to give you something to build off of!
void AlternatingSplit(struct Node* source, struct Node** aRef,
struct Node** bRef)
{
/* split the nodes of source to these 'a' and 'b' lists */
struct Node* a ;
struct Node* b;
struct Node* current = source;
if(current){
a=current;
b=current->next;
current=b->next;
a->next=NULL;
b->next=NULL;
}
while(current) {
a->next=current;
b->next=current->next;
if(b)
current=b->next;
b=b->next;
a=a->next;
}
*aRef = a;
*bRef = b;
}
I am getting segmentaton fault here i dont know why pls help.
This question is to alternating split linkedlist nodes. I m using two pointers a and b and adding to it alternatingly but its giving error . pls help me
Like most linked-list rearrangement exercises, pointers to pointers make the job much, much easier. The point of this exercise it to flex your ability to change the next pointers without ever changing the data values of said-same. Pointers to pointers are an excellent way to do that in C.
This is especially trivial because you were already provided the target pointer-to-pointer arguments that we can reuse for building each list. How that works is best understood by demonstrating a technique for building a forward-chained linked list using a single head pointer and a pointer to pointer p:
struct Node *head, **pp = &head;
for (int i = 1; i <= 20; ++i)
{
*pp = malloc(sizeof **pp);
(*pp)->data = i;
pp = &(*pp)->next;
}
*pp = NULL;
Yes, it needs error checking, but the algorithm is what to focus on here. This code uses only pp to build the actual list. The rule is this: pp is a pointer to pointer to Node, and always holds the address of the next pointer to Node to populate. That's what pointers to pointers do: hold addresses of pointers. In this case pp initially holds the address of the head pointer. With each new node added pp takes the address of the next pointer of the previously just-added node. Makes sense, right? That will be the next pointer where we want to hang the next node. This process continues until we finish the loop. At that pointer pp holds the address of the last node's next pointer, which we set to NULL to terminate the list.
Now, knowing what we learned above, consider this:
void AlternatingSplit(struct Node* source, struct Node** a, struct Node** b)
{
while (source)
{
*a = source;
a = &(*a)->next;
source = source->next;
if (source)
{
*b = source;
b = &(*b)->next;
source = source->next;
}
}
*a = *b = NULL;
}
Example
A short example using both the forward-chaining build algorithm I showed first, and the split algorithm I showed after, appears below. Some utility functions for printing the list are included. I leave freeing the lists (there are two now, remember to walk both and free each node) as an exercise for you:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
void AlternatingSplit(struct Node* source, struct Node** a, struct Node** b)
{
while (source)
{
*a = source;
a = &(*a)->next;
if ((source = source->next))
{
*b = source;
b = &(*b)->next;
source = source->next;
}
}
*a = *b = NULL;
}
void PrintList(struct Node const *p)
{
while (p)
{
printf("%d ", p->data);
p = p->next;
}
fputc('\n', stdout);
}
int main(void)
{
struct Node *head, **pp = &head;
for (int i = 1; i <= 20; ++i)
{
*pp = malloc(sizeof **pp);
(*pp)->data = i;
pp = &(*pp)->next;
}
*pp = NULL;
PrintList(head);
struct Node *a = NULL, *b = NULL;
AlternatingSplit(head, &a, &b);
PrintList(a);
PrintList(b);
return EXIT_SUCCESS;
}
Output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 3 5 7 9 11 13 15 17 19
2 4 6 8 10 12 14 16 18 20
There are few errors in your code -
Trying to access node->next , without checking whether node exists or not .
Not tackling the corner cases depending on the length of linked list (i.e. if length (linked list) < 3 )
And then comes the blunder , you are trying to make the new linked lists and then in the end aRef and bRef is assigned to the last node in their respective linked lists.
Try to deal with these problems and for reference you can see the code below.
void AlternatingSplit(struct Node* source, struct Node** aRef,
struct Node** bRef)
{
struct Node* a,b;
struct Node* current = source;
if(current){
a=current;
b=current->next;
// moving 'current' one step at a time will secure the code from crashing for corner cases
current = current->next;
if(b)
current=b->next;
a->next=NULL;
b->next=NULL;
//link aRef bRef right here
*aRef = a;
*bRef = b;
}
else {
*aRef = source; // Null
*bRef = source; // Null
return;
}
while(current)
{
a->next=current;
a=a->next;
b->next=current->next;
b=b->next;
current=current->next;
if(b){
current = b->next;
}
}
b->next = NULL;
a->next = NULL;
}
Hope this will help .
Keep asking , keep growing :)
I have doubly linked list set up using an insertion method which works.
Using this struct:
struct NODE
{
struct NODE *fwd;
struct NODE *bwd;
int value;
};
typedef struct NODE Node;
And this initialization:
void initializeList(Node *rt)
{
rt->fwd = NULL;
rt->bwd = NULL;
rt->value = 0;
}
My main function is:
main()
{
Node root;
int j;
initializeList(&root);
for (j = 0; j < 15; j++)
insertFirst(&root, j);
printf("The list traversed forward \n");
traverseForward(root);
printf("\n");
printf("The list traversed backward \n");
traverseBackward(root);
printf("\n");
printf("After first deletion traverse forward\n");
deleteFirst(&root);
traverseForward(root);
printf("\n");
printf("After first deletion traverse backwards\n");
printf("\n");
traverseBackward(root);
}
My deletefirst function is:
void deleteFirst(Node *rt)
{
Node *newnode = rt;
Node *tmp = NULL;
if (newnode != NULL)
{
if (newnode->fwd != NULL)
{
newnode = newnode->fwd;
tmp = newnode->bwd;
*rt = *newnode;
}
else
tmp = newnode;
}
free(tmp);
}
Insert function:
int insertFirst(Node *rt, int val)
{
Node *node = (Node *)malloc(sizeof(Node));
if (node == NULL) return 0;
node->value = val;
/* For a previously empty list */
if (rt->fwd == NULL)
{
rt->fwd = node;
rt->bwd = node;
node->fwd = NULL;
node->bwd = NULL;
}
/* For a list with at least one node */
else
{
/* previous first node now new node's successor */
rt->fwd->bwd = node;
node->fwd = rt->fwd;
/* no predecessor to the new first node */
node->bwd = NULL;
/* root points to this new first */
rt->fwd = node;
}
return 1;
}
Traverse functions:
void traverseForward(Node root)
{
Node *q = root.fwd;
while (q)
{
printf("%d ", q->value);
q = q->fwd;
}
}
void traverseBackward(Node root)
{
Node *q = root.bwd;
while (q)
{
printf("%d ", q->value);
q = q->bwd;
}
}
The system prints out the list traversed forward
14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
The system prints out the list traversed backward
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
After first deletion forward traversal
13 12 11 10 9 8 7 6 5 4 3 2 1 0
After first deletion backward traversal
(Nothing is printed)
I cant figure out how to adjust the pointers to get it to work.
I believe the problem is because the odd way you are storing the head and tail pointers to the start and end of the list in a root node and then mixing that interchangeably with the actual nodes of the list. This confusion could be eliminated if you just have simple Node *head and Node *tail pointers, but that is only a suggestion.
In your delete function, you set the root node to effectively rt->fwd, which is fine for forwards traversal as rt->fwd->fwd is what is desired, but you forget to consider the value of rt->fwd->bwd which is always pointing at NULL for the first item in the list (as there is nothing technically before this node), not the actual tail of the list which is the desired functionality by that logic.
This obviously causes a problem when you try to use it to iterate backwards as it thinks the list is empty. You should change your deletion code to something like this:
void deleteFirst(Node *rt)
{
if (rt == NULL)
{
return; /* Return if an invalid root was passed in */
}
if (rt->fwd == NULL) {
return; /* Return if the list is already empty */
}
Node *tmpfwd = rt->fwd; /* Store the current "head" */
rt->fwd = rt->fwd->fwd; /* Set the root's head to the current head's next node */
rt->fwd->bwd = NULL; /* Set the new head's previous node to NULL as it is the start of the list */
free(tmpfwd); /* Delete the old "head" */
}
There are a lot of other problems here regarding edge cases and things the comments have mentioned (just the overall design makes this very problematic) but I think this is the problem you are having currently.
I have a simple question about removing an element from a linked list. The only difference between what I am trying to accomplish and what I have seen in code online is that I am trying to remove an element, given a position, rather than given the actual element that needs to be removed.
Any help is appreciated.
You can do that, Here is the sample program which can delete any node based on the index you are supplying as an argumenT.
start -> Pointing to the first node
traverse ->pointing to the node which has to be deleted
traverseNext->pointing to the previous of node which has to be deleted.
And the code looks like below.
#include <iostream>
struct myList
{
int data;
struct myList *next;
};
struct myList *start=NULL;
//this method removes a node from the position index
void remove(int index)
{
myList *traverse = start;
myList *traverseNext = NULL;
int i = 1;
while(i<(index-1))
{
traverse = traverse->next;
i++;
}
traverseNext = traverse;
traverse = traverse->next;
if(traverse->next == NULL)
{
delete traverse;
traverseNext->next = NULL;
traverse = NULL;
return;
}
else
{
traverseNext->next = traverse->next;
delete traverse;
traverse = NULL;
return;
}
}
int main(void)
{
myList *node1;
myList *node2;
myList *node3;
node1 = new myList;
node2 = new myList; //Created 3 nodes of type myList
node3 = new myList;
node1->data = 10;
node1->next = node2;
node2->data = 20;
node2->next = node3;
node3->data = 30;
node3->next = NULL;
start = node1; //start is pointing to node1
remove(2); //removing the node 2, so the output will be 10 30
while(start) //iterating through all the nodes from start, since start
{ //is pointing to the first node.
std::cout<<start->data<<" ";
start = start->next;
}
}
Deleting a node in a linked list to which the pointer is given can be done in O(1) time. We don't have to do traversal.
I am assuming that by position you meant the pointer to the node is given:
Lets say node is the element that needs to be removed.
node->data = node->next->data;
Node* temp = node->next;
node->next = node->next->next;
free(temp);
But if the position means the nth element in the list, the only way would be to traverse up to the (n-1)th element and delete the next element by (regular deletion in a linked list):
Node* temp = previous->next;
previous->next = temp->next;
free(temp);
This is all assuming that the linked-list is a pointer based linked-list
This is simple:
1) Locate the Nth item by iterating through the list, additionally using a counter to keep track of which node you're one.
2) Remove that node, as you would any other linked list.
Seek the list until you find the nth element (use a counter), and then update the previous node's next pointer to point to the one after the one you're currently at (effectively removing it). Adjust the previous pointer if you're using them, too.
If you want to remove multiple items you can first iterate over the list and then collect all items that you want to remove to another list. Then simply call 'removeAll' passing in the collected list.
#include <stdio.h>
#include <stdlib.h>
typedef struct element{
int num;
struct element * next;
} element;
void delNth(element **header, int pos){//pos : zero origin
element *prev, *tmp;
int i;
if(header == NULL || *header == NULL || pos < 0) return ;
if(pos == 0){
tmp = (*header)->next;
free(*header);
*header = tmp;
} else {
prev = *header;
tmp = (*header)->next;
for(i=1;i<pos;++i){
prev = tmp;
tmp = tmp->next;
if(tmp == NULL) return ;//or rise error
}
prev->next = tmp->next;
free(tmp);
}
}
void drop(element *header){
if(header){
drop(header->next);
free(header);
}
}
void printList(element *header){
while (header!=NULL){
printf("%d ",header->num);
header=header->next;
}
printf("\n");
}
int main(int argc, char **argv){
int pos = atoi(argv[1]);
element *a;
element *b;
element *c;
a=malloc(sizeof(element));
b=malloc(sizeof(element));
c=malloc(sizeof(element));
a->num=5;
b->num=6;
c->num=7;
a->next=b;
b->next=c;
c->next=NULL;
printList(a);
delNth(&a, pos);
printList(a);
drop(a);
return 0;
}
/* execute result
>a 0
5 6 7
6 7
>a 1
5 6 7
5 7
>a 2
5 6 7
5 6
>a 3
5 6 7
5 6 7
*/
I have the following code, when I add nodes why does it reset all nodes to the most recent nodes data? Assuming everything else in the codes works correctly, parsing etc. can anyone identify a problem with the list. See output at the bottom.
typedef char* string;
typedef struct linked_list listType;
typedef struct linked_list* linked_list;
typedef struct node NodeType;
typedef struct node* Node;
typedef enum boolean{
true = 1,
false = 0
}boolean;
struct node{
Node next;//next node in the list
string *transData;//listAdd--->string data[]
};
struct linked_list{
Node head;//first node in the list
int size;//size of list, number of nodes in list
};
boolean add(linked_list list, string *data)
{
boolean retval = false;//default retval is false
Node nod;//node to add
nod = (Node)malloc(sizeof(NodeType));
nod->transData = data;
nod->next = NULL;
//list size is 0
if(list->head == NULL)
{
list->head = nod;
printf("First Node added: '%s'\n", nod->transData[0]);fflush(stdout);
retval = true;
}
//nodes already in list
else
{
printf("List with nodes already\n");
fflush(stdout);
Node node = list->head;
//iterating through nodes
while(node->next != NULL)
{
node = node->next;
}//while
node->next = nod;
printf("Node added: '%s'\n", nod->transData[0]); fflush(stdout);
retval = true;
}
list->size+=1;
return retval;//success
}
/**
* Returns the size of the list.
*/
int listSize(linked_list list)
{
return list->size;
}
/**
*Can only print with 2 or more elements
*/
void printList(linked_list list)
{
int i=0;
Node nod = list->head;
int length = listSize(list);
printf("ListSize:%d\n",listSize(list));
fflush(stdout);
while(nod->next != NULL)
{
printf("Node %d's data: %s\n", i, nod->transData[0]);
fflush(stdout);
nod = nod->next;
i++;
}
}//printlist
Output:
trans 5 5
Argument 1: trans
Argument 2: 5
Argument 3: 5
Last spot(4) is: (null)
name of command: trans
ID 1
First Node added: 'trans'
ListSize:1
>>check 4
Argument 1: check
Argument 2: 4
Last spot(3) is: (null)
name of command: check
ID 2
List with nodes already
Node added: 'check'
ListSize:2
Node 0's data: check
>>trans 4 4
Argument 1: trans
Argument 2: 4
Argument 3: 4
Last spot(4) is: (null)
name of command: trans
ID 3
List with nodes already
Node added: 'trans'
ListSize:3
Node 0's data: trans
Node 1's data: trans
>>check 5
Argument 1: check
Argument 2: 5
Last spot(3) is: (null)
name of command: check
ID 4
List with nodes already
Node added: 'check'
ListSize:4
Node 0's data: check
Node 1's data: check
Node 2's data: check
(The OP tells me that the nodes need to have arrays of strings, so the pointer-to-a-pointer thing is actually correct).
Anyhow, it looks like your problem is that every node has a pointer to the same buffer. You just keep copying different strings into the same buffer, and then you assign the address of a pointer to that buffer to each new node.
First, I'd get rid of those typedefs. I don't know how much clarity they're really adding.
Next, you need to allocate new storage for each string. The standard library strdup() function is a handy way to do that:
// Turns out it's a fixed-size array, so we can blow off some memory
// management complexity.
#define CMDARRAYSIZE 21
struct node {
Node next;
char * transData[ CMDARRAYSIZE ];
};
// Node initialization:
int i = 0;
struct node * nod = (struct node *)malloc( sizeof( struct node ) );
// Initialize alloc'd memory to all zeroes. This sets the next pointer
// to NULL, and all the char *'s as well.
memset( nod, 0, sizeof( struct node ) );
for ( i = 0; i < CMDARRAYSIZE; ++i ) {
if ( NULL != data[ i ] ) {
nod->transData[ i ] = strdup( data[ i ] );
}
}
...but then be sure that when you free each node, you call free( nod->transData[n] ) for every non-NULL string pointer in nod->transData. C is not a labor-saving language.
Your issue is probably due to pointer copying. You are likely referencing the same buffer in all your nodes. Try to make a copy of your string data with strdup for example.
Not the main issue, but your printList won't print out the last element.
Instead of while(nod->next != NULL) use while(nod != NULL)