C - How to print a string element in a pointer to struct? - c

I'm relearning linked list data structure and I stumbled upon this problem.
#include <stdlib.h>
#include <stdio.h>
struct Node{
char url[50];
struct Node *next;
};
typedef struct Node Node;
void add_url(Node * h, Node * c, Node * n){
Node * temp;
temp = malloc(sizeof(Node));
printf("\nType or paste your URL: ");
scanf("%s", temp->url);
if(h == NULL){
h = temp;
h->next = NULL;
c = h;
}else{
c->next = temp;
c = c->next;
n = c->next;
}
}
int main(){
Node * h = NULL; // head
Node * c; // current
Node * n; // next
add_url(h, c, n);
printf("%s", h->url);
return 0;
}
Why is the output NULL? How exactly do you get a string input from a pointer to struct?

Here is a possible solution. I have added some checks to avoid segmentation fault (access violation), buffer overflow in scanf, initialized variables and the function now returns the new head (Could instead return current node).
#include <stdlib.h>
#include <stdio.h>
struct Node {
char url[50];
struct Node* next;
};
typedef struct Node Node;
Node *add_url(Node** h, Node** c, Node** n) {
Node* temp;
if ((h == NULL) || (c == NULL) || (n == NULL))
return NULL;
if ((temp = malloc(sizeof(Node))) == NULL)
return NULL;
printf("\nType or paste your URL: ");
if (scanf("%50s", temp->url) != 1)
return NULL;
if (*h == NULL) {
temp->next = NULL;
*h = temp;
*c = *h;
}
else {
(*c)->next = temp;
*c = temp;
*n = temp;
}
return *h;
}
int main() {
Node* h = NULL; // head
Node* c = NULL; // current
Node* n = NULL; // next
if (add_url(&h, &c, &n) == NULL) {
perror("add_url failed: ");
return 1;
}
printf("%s", h->url);
return 0;
}

Related

Values aren't being saved in a queue in C

I'm trying to implement a queue in C using a linked list. I ran my code through a C visualizer and it seems that the values A-E aren't being saved. As in, one node will contain the letter A then when queue_enqueue is called again, another node is created that holds the letter B and then the previous node that contained A just, disappears... My code contains other functions like dequeue and one to check if the queue is empty, but I took them out to keep my code short and they are independent of the functions provided here.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct node {
struct node *next;
struct node *prev;
char *value;
};
// The type for a list.
typedef struct list {
struct node head;
} List;
typedef struct queue {
List *list;
} Queue;
Queue *queue_create(void) {
Queue *q = (Queue*)malloc(sizeof(struct queue));
List *ptr = (List*)malloc(sizeof(struct list));
q->list = ptr;
q->list->head.next = NULL;
return q;
}
void queue_destroy(Queue *q) {
free(q->list->head.value);
free(q);
}
void queue_enqueue(Queue *q, const char *value) {
struct node *temp;
temp = malloc(sizeof(struct node));
temp->value = strdup(value);
temp->next = NULL;
q->list->head.next = temp;
q->list->head.value = temp;
}
int main(void) {
// Create an empty queue.
Queue *q = queue_create();
// Add the values A, B, ..., Z to the queue.
char str[] = "A";
for (char ch = 'A'; ch <= 'E'; ch++) {
str[0] = ch;
queue_enqueue(q, str);
}
// Clean up.
queue_destroy(q);
return 0;
}
To simplify your problem you should begin with a single-linked list and in your example there is no need to use char* as node value:
struct node {
struct node* next;
char value;
};
You also might want to add a element counter for your list:
typedef struct list {
struct node *head;
size_t num;
}
and a function to create a new node with the given value:
struct node *node_create(char value) {
struct node *nd = malloc(sizeof(struct node));
if (nd)
nd->value = value;
return nd;
}
The magic happens in the insert function but it is no rocket science at all. You either create your new node where head is pointing (empty list) or at the end of the list.
void list_insert(List *list, char value) {
if (!list)
return;
if (!list->head) {
// first element of list
list->head = node_create(value);
if (list->head)
list->num++;
}
else {
// move to the end of the list
struct node *nd = list->head;
while (nd->next) {
nd = nd->next;
}
nd->next = node_create(value);
if (nd->next)
list->num++;
}
}
Also make sure to properly initialize your list with some list_create function and when cleaning the list take care to free all list elements before releasing the memory of the list itself
You are not linking the chain pointers correctly.
And, setting q->list->head.value = temp; won't even compile.
For a doubly linked list, reusing a node struct as the front/back pointers (e.g prev/next) is doable but unclear. Better to redefine List slightly to use front/back--it's clearer.
Your destroy code is also wrong.
When appending to a list, the first time is slightly different than subsequent ones.
Here's the refactored code.
Since your code didn't change any of the list's next/prev pointers or temp's next/prev pointers, it wasn't clear whether you wanted to enqueue to the front or the back of the list, so I added both functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct node {
struct node *next;
struct node *prev;
char *value;
};
// The type for a list.
typedef struct list {
struct node *front;
struct node *back;
size_t count;
} List;
typedef struct queue {
List *list;
} Queue;
Queue *
queue_create(void)
{
Queue *q = malloc(sizeof(*q));
q->list = calloc(1,sizeof(List));
return q;
}
void
queue_destroy(Queue *q)
{
List *list = q->list;
struct node *cur;
struct node *next;
if (list != NULL)
cur = list->front;
else
cur = NULL;
for (; cur != NULL; cur = next) {
next = cur->next;
free(cur->value);
}
free(list);
free(q);
}
struct node *
node_create(const char *value)
{
struct node *temp = calloc(1,sizeof(*temp));
temp->value = strdup(value);
return temp;
}
void
queue_enqueue_front(Queue *q,const char *value)
{
struct node *temp = node_create(value);
List *list = q->list;
temp->next = list->front;
if (list->front != NULL)
list->front->prev = temp;
list->front = temp;
if (list->back == NULL)
list->back = temp;
list->count += 1;
}
void
queue_enqueue_back(Queue *q,const char *value)
{
struct node *temp = node_create(value);
List *list = q->list;
temp->prev = list->back;
if (list->back != NULL)
list->back->next = temp;
list->back = temp;
if (list->front == NULL)
list->front = temp;
list->count += 1;
}
void
queue_print_fwd(Queue *q,const char *who)
{
List *list = q->list;
struct node *cur;
if (who != NULL)
printf("%s:\n",who);
for (cur = list->front; cur != NULL; cur = cur->next)
printf(" %s\n",cur->value);
}
void
queue_print_rev(Queue *q,const char *who)
{
List *list = q->list;
struct node *cur;
if (who != NULL)
printf("%s:\n",who);
for (cur = list->back; cur != NULL; cur = cur->prev)
printf(" %s\n",cur->value);
}
int
main(void)
{
// Create an empty queue.
Queue *q = queue_create();
// Add the values A, B, ..., Z to the queue.
char str[] = "A";
for (char ch = 'A'; ch <= 'E'; ch++) {
str[0] = ch;
queue_enqueue_back(q, str);
#ifdef DEBUG
queue_print_fwd(q,"pushback");
#endif
}
for (char ch = 'K'; ch >= 'F'; ch--) {
str[0] = ch;
queue_enqueue_front(q, str);
#ifdef DEBUG
queue_print_fwd(q,"pushfront");
#endif
}
queue_print_fwd(q,"Forward");
queue_print_rev(q,"Reverse");
// Clean up.
queue_destroy(q);
return 0;
}
Here's the program output:
Forward:
F
G
H
I
J
K
A
B
C
D
E
Reverse:
E
D
C
B
A
K
J
I
H
G
F
UPDATE:
Here's a slightly cleaned up version.
There's probably no need to allocate q->list--It could just be declared as List list; instead of List *list;
Just for grins, I also added a node removal function (e.g. queue_unlink).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct node Node;
struct node {
Node *next;
Node *prev;
char *value;
};
// The type for a list.
typedef struct list {
Node *front;
Node *back;
size_t count;
} List;
typedef struct queue {
List list;
} Queue;
Queue *
queue_create(void)
{
Queue *q = calloc(1,sizeof(*q));
return q;
}
void
queue_destroy(Queue *q)
{
List *list = &q->list;
Node *cur;
Node *next;
for (cur = list->front; cur != NULL; cur = next) {
next = cur->next;
free(cur->value);
list->count -= 1;
}
free(q);
}
void
queue_unlink(Queue *q,Node *cur)
{
List *list = &q->list;
do {
if (cur == NULL)
break;
Node *prev = cur->prev;
Node *next = cur->next;
if (prev != NULL)
prev->next = next;
if (next != NULL)
next->prev = prev;
if (list->front == cur)
list->front = next;
if (list->back == cur)
list->back = prev;
cur->prev = NULL;
cur->next = NULL;
list->count -= 1;
} while (0);
}
Node *
node_create(const char *value)
{
Node *temp = calloc(1,sizeof(*temp));
temp->value = strdup(value);
return temp;
}
void
queue_enqueue_front(Queue *q,const char *value)
{
Node *temp = node_create(value);
List *list = &q->list;
Node *front = list->front;
temp->next = front;
if (front != NULL)
front->prev = temp;
list->front = temp;
if (list->back == NULL)
list->back = temp;
list->count += 1;
}
void
queue_enqueue_back(Queue *q,const char *value)
{
Node *temp = node_create(value);
List *list = &q->list;
Node *back = list->back;
temp->prev = back;
if (back != NULL)
back->next = temp;
list->back = temp;
if (list->front == NULL)
list->front = temp;
list->count += 1;
}
int
queue_print_node(Node *cur,int totlen)
{
int curlen;
curlen = strlen(cur->value);
if ((totlen + curlen + 1) >= 78) {
fputc('\n',stdout);
totlen = 0;
}
fputc(' ',stdout);
totlen += 1;
fputs(cur->value,stdout);
totlen += curlen;
return totlen;
}
void
queue_print_fwd(Queue *q,const char *who)
{
List *list = &q->list;
Node *cur;
int totlen = 0;
if (who != NULL)
printf("%s:\n",who);
for (cur = list->front; cur != NULL; cur = cur->next)
totlen = queue_print_node(cur,totlen);
if (totlen > 0)
fputc('\n',stdout);
}
void
queue_print_rev(Queue *q,const char *who)
{
List *list = &q->list;
Node *cur;
int totlen = 0;
if (who != NULL)
printf("%s:\n",who);
for (cur = list->back; cur != NULL; cur = cur->prev)
totlen = queue_print_node(cur,totlen);
if (totlen > 0)
fputc('\n',stdout);
}
int
main(void)
{
// Create an empty queue.
Queue *q = queue_create();
// Add the values A, B, ..., Z to the queue.
char str[] = "A";
for (char ch = 'A'; ch <= 'E'; ch++) {
str[0] = ch;
queue_enqueue_back(q, str);
#ifdef DEBUG
queue_print_fwd(q,"pushback");
#endif
}
for (char ch = 'K'; ch >= 'F'; ch--) {
str[0] = ch;
queue_enqueue_front(q, str);
#ifdef DEBUG
queue_print_fwd(q,"pushfront");
#endif
}
for (int iter = 1; iter <= 10; ++iter) {
char buf[35];
int len = (rand() % (sizeof(buf) - 1)) + 1;
int idx = 0;
for (; idx < len; ++idx) {
int chr = (rand() % 26) + 'a';
buf[idx] = chr;
}
buf[idx] = 0;
queue_enqueue_back(q, buf);
}
queue_print_fwd(q,"Forward");
queue_print_rev(q,"Reverse");
// Clean up.
queue_destroy(q);
return 0;
}

Stack push function using c, implemented using doubly linked list

I am trying to implement Hierholzer's algorithm using C.
I have made a push function for a simple stack implemented using doubly linked list but the pointer always moves on to the else condition, even when the starting node is empty.
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<stddef.h>
typedef struct node
{
int source;
int num;
struct node *l, *r;
int done;
}node;
void push(int source, int num, struct node *head)
{
node *n = malloc(sizeof(node));
n->num = num;
n->l = NULL;
n->done = 0;
n->source = source;
if (*head == NULL)
{
head = n;
head -> r = NULL;
}
else
{
n -> r = head;
head->l = n;
head = n;
}
}
int pop(node *head)
{
if(head == NULL)
{
return -1;
}
else
{
node *temp = head;
head = head->r;
int num = temp->num;
free(temp);
return num;
}
}
void append(node *extra, node *head)
{
node *temp = extra;
while(temp->r != NULL)
{
temp = temp->r;
}
temp->r = head;
head->l = temp;
head = extra;
}
node** read(int num)
{
char a[2000] = "Assignment1.txt" ,c[1000];
FILE *f = fopen(a,"r");
printf("Got file\n");
node *adj[num];
int i=0;
node *l;
printf("l: %d\n", l);
while(fscanf(f,"%s",c))
{
char *p = strtok(c, ",");
while(p!=NULL)
{
push(i, atoi(p), l);
p = strtok (NULL, ",");
}
adj[i++] = l;
}
printf("Adjacency list created\n");
return adj;
}
node* euler(node *adj[],int n, int i)
{
node *cpath = NULL;
node *fin = NULL;
node *extra;
node *temp = adj[i];
node *tempi;
while(temp!=NULL)
{
if(temp->r->r == NULL)
{
tempi = temp;
}
if(temp->done == 0)
{
temp->done = 1;
push(i, temp->num, cpath);
extra = euler(adj, n, temp->num);
append(extra, cpath);
}
else
{
temp = temp->r;
}
}
while(tempi->l != NULL)
{
push(i,tempi->num, fin);
extra = euler(adj, n, tempi->num);
append(tempi, fin);
tempi = tempi->l;
}
if(tempi != NULL)
{
push(i,tempi->num, fin);
extra = euler(adj, n, tempi->num);
append(tempi, fin);
}
return fin;
}
int main()
{
int n;
printf("Enter the number of vertices: ");
scanf("%d", &n);
node **adj = read(n);
node *fin = euler(adj, n, 0);
node *temp = fin;
while(temp!=NULL)
{
printf("%d ", temp->num);
temp = temp->r;
}
return 0;
}
I am yet to debug the entire code but I am getting stuck at the read() function where the input is an Assignment1.txt which includes:
2,3
3,1
1,2
I am not able to understand why I am getting a segmentation fault.
The function deals with a copy of the value of the passed to it pointer to the head node. So the original pointer itself is not changed in the function. It is the copy of the value of the passed pointer that is changed within the function.
You need to pass the pointer by reference that is indirectly through pointer to the pointer.
The function can be declared and defined the following way.
int push( struct node **head, int source, int num )
{
node *n = malloc(sizeof(node));
int success = n != NULL;
if ( success )
{
n->source = source;
n->num = num;
n->done = 0;
n->l = NULL;
n->r = *head;
if ( *head != NULL ) ( *head )->l = n;
*head = n;
}
return success;
}
In read function you are returning adj. However, it is a local variable. You are not using malloc type function. So, local variables destroy after function returned. Therefore, you are trying to access a random place when you try to access adj in main. I guess the problem is caused by this reason.

why this search function in list doesn't work?

I made this easy linked list and i would like to add element in it checking if the element is already present.
If the new element to add is already present, the node won't be inserted in the list.
Well, the problem begins when a insert the second element; gdb says:
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554bda in search (name=0x5555557576d0 "alfred")
at Scrivania/test.c:*line*
*line* while(strncmp(name,temp->name,strlen(name))!=0)
Code:
typedef struct node{
char *name;
struct node *n;
} N;
N *h = NULL;
void insert(char *name){
N *temp = malloc(sizeof(N));
if (h == NULL){
h=temp;
temp->n = NULL;
temp->name = strdup(name);
} else {
N *curr = h;
while (curr->n != NULL)
curr = curr->n;
curr->n = temp;
temp->name = strdup(name);
}
}
N *search(char *name) {
N *temp = h;
if (temp == NULL)
return NULL;
else{
while (strncmp(name, temp->name, strlen(name)) != 0)
temp=temp->n;
return temp;
}
}
int main() {
char *name = N * temp=search(name); //getting input
if (temp == NULL)
insert(name);
//these four lines sequence repeat for every input
}

Exception thrown in linked list

I need to write a function that returns the size of a linked list. It seems simple enough, but I get an exception when I try to advance my pointer.
This is the code:
int List_size(List *list)
{
List_node *p;
int counter = 0;
p = list->head;
while (p != NULL)
{
p = p->next;
counter = counter + 1;
}
return counter;
}
This is the code that defines the linked list:
typedef struct List_node
{
int data;
struct List_node *next;
struct List_node *prev;
}List_node;
typedef struct List
{
List_node *head;
}List;
And this is the code that creates the list:
List *create_list(int n)
{
List *list = (List*) calloc(n,sizeof(List));
list->head = NULL;
return list;
}
Lastly, I have inserted data (numbers) into the list using these two functions: (so don't think the lists are empty).
void insert_first(List_node *x, List *list)
{
x->next = list->head;
list->head = x;
}
void insert(List_node *x, List_node *y)
{
x->next = y->next;
y->next = x;
}
List_node *mk_node(int data, int n)
{
List_node *node = (List_node *)calloc(n, sizeof(List_node));
node->data = data;
return node;
}
Using a breakpoint I discovered that the problem lies in p = p->next, but I don't understand why.
Thank you very much.
edit - I did not think the full code is necessary, but here it is:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include "List.h"
void merge(List *small_list, List *big_list)
{
List_node *x, *y;
y = small_list->head;
x = big_list->head;
t = x->prev;
// while (y < x) //If there are smaller numbers on the small list, insert them first
// {
// insert(y,t)
// t = t->next;
// y = y->next;
// }
while (y != NULL && x->next != NULL)
{
if (x <= y && x->next >= y)
{
insert(y, x);
y = y->next;
}
else
x = x->next;
}
while (y != NULL)
{
insert(y, x);
y = y->next;
}
}
void main()
{
List *L1, *L2, *big_list, *small_list;
int num1, num2;
int i;
int a, b;
create_list(5,&L1);
create_list(3,&L2);
printf("Insert first number into L1\n");
scanf("%d", &num1);
node = mk_node(0,5);
insert_first(node, &L1);
for (i = 0; i<5; i++)
{
printf("Now insert the rest of the numbers\n");
scanf("%d", &num1);
next = mk_node(&num1,5);
insert(next, node);
node = next;
}
printf("Insert first number into L2\n");
scanf("%d", &num2);
node = mk_node(0,3);
insert_first(node, &L2);
for (i = 0; i<3; i++)
{
printf("Now insert the rest of the numbers\n");
scanf("%d", &num2);
next = mk_node(&num2,3);
insert(next, node);
node = next;
}
//If lists are in descending order, reverse them to ascending order
//if (L1->head > L1->head->next)
// reverse(L1);
// if (L2->head > L2->head->next)
// reverse(L2);
int size_L1 = List_size(L1);
int size_L2 = List_size(L2);
if (size_L1 <= size_L2)
{
big_list = L2;
small_list = L1;
}
else
{
big_list = L1;
small_list = L2;
}
merge(small_list, big_list);
print_list(L3);
getchar(); getchar();
}
As you can see, I inserted the numbers using the function insert(). I hope it is okay.
The function reverse is: (I really hope it works, I translated it from pseudo-code)
List reverse(List *list)
{
List_node *x, *y, *z;
if (list->head == NULL || list->head->next == NULL)
{
return *list;
}
x = list->head;
y = list->head->next;
z = list->head->next->next;
x->next = NULL;
while (z != NULL)
{
y->next = x;
x = y;
y = z;
z = z->next;
}
y->next = x;
list->head = y;
}
Basically, this is an assignment that says I have two 2-directional sorted linked lists, and I'm supposed to merge them into one big sorted linked list.
As for the exception - Unhandled exception at 0x00E21766 in Lists.exe: 0xC0000005: Access violation reading location 0xCCCCCCD0.
Edit - the print_list function:
void print_list(List *list)
{
List_node *p;
p = list->head;
printf("The linked list consists of: ");
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
The problem is in code you did not show, because all the code you give is fine (*).
I could use your structs and functions to :
create a List
add a first node (with insert_first)
add other nodes (with insert)
get the size (using List_size)
display the data value of every node
free the nodes and the list
Here's the full code :
#include <stdio.h>
#include <malloc.h>
typedef struct List_node
{
int data;
struct List_node *next;
struct List_node *prev;
}List_node;
typedef struct List
{
List_node *head;
}List;
List *create_list()
{
List *list = (List*) malloc(sizeof(List));
list->head = NULL;
return list;
}
int List_size(List *list)
{
List_node *p;
int counter = 0;
p = list->head;
while (p != NULL)
{
p = p->next;
counter = counter + 1;
}
return counter;
}
void insert_first(List_node *x, List *list)
{
x->next = list->head;
list->head = x;
}
void insert(List_node *x, List_node *y)
{
x->next = y->next;
y->next = x;
}
/* my own additions */
List_node *mk_node(int data) {
List_node *node = (List_node *) malloc(sizeof(List_node));
node->data = data;
return node;
}
void delete_list(List *list) {
List_node *node = list->head;
while (node != NULL) {
List_node *next = node ->next;
free(node);
node = next;
}
free(list);
}
int main() {
List* list = create_list();
List_node *node, *next;
int i;
node = mk_node(0);
insert_first(node, list);
for (i=1; i<5; i++) {
next = mk_node(i);
insert(next, node);
node = next;
}
int n = List_size(list);
printf("size : %d\n", n);
node = list->head;
while (node != NULL) {
printf("node val : %d\n", node->data);
node = node->next;
}
delete_list(list);
return 0;
}
(*) Your code is not perfect because List_node struct contains a pointer prev that is never used, so you end with a single-linked list with every third value unused.
I added a comment above that I copied your code into my compiler and that it doesn't compile, so it won't run: the calls to create_list don't compile: they return a value as function return, not in a parameter; there are undeclared variables. Further, it is useless to give create_list and mk_node a parameter: they will allocate an array, not create a single list element. A call of calloc(1, sizeof(your_thing)) would suffice. After fixing these erors, several bugs became apparent:
in insert_first(node, &L2); you give it the address of the list, which is already a pointer. Remove the '&' (the compiler should have complained!).
same for List_size(&L1); L1 is already a pointer. Remove the '&'.
in: if (x <= y ...) you compare memory addresses. Change to: if (x->data <= y->data...)
in that statement the part "x->next >= y" also compares memory address, and I don't see why it is needed. I removed it.
The real problem seems to be in merge. You should either merge the lists into L1, or into L2, and preferably should create a result list. But you "randomly" insert an element into L1, then into L2, then again into L1, etcetera. In my test it ran indefinitly. The following merge works fine:
List *merge(List *small_list, List *big_list)
{
List_node *x, *y, *r;
List *result= create_list();
y = small_list->head;
x = big_list->head;
if (x->data < y->data)
{result->head= x; x= x->next;}
else {result->head= y; y= y->next;}
r= result->head;
while (y != NULL && x != NULL)
{
if (x->data < y->data)
{
r->next= x;
x = x->next;
}
else {
r->next= y;
y = y->next;
}
r= r->next;
}
while (y != NULL)
{
r->next= y;
y = y->next;
r= r->next;
}
while (x != NULL)
{
r->next= x;
x = x->next;
r= r->next;
}
r->next= 0;
return (result);
}
So the problem is that you allocate the list head, but never allocate memory for the list elements. Serge added mk_node which does the allocation (so Serge solved it).

Segmentation Fault (core dumped) in C in Delete() function

i am writing a Dictionary using linked list in C, and all my functions work except my delete function, which is shown below along with all other necessary code. Every time i try to run my program as soon as it reaches a line in which it must delete a node, it gives me the error: Segmentation Fault (core dumped) which means it has something to do with the memory allocation or a null pointer i think. I know that the rest of my code works. All and any help is appreciated! :)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include"Dictionary.h"
// NodeObj
typedef struct NodeObj{
char* key;
char* value;
struct NodeObj* next;
} NodeObj;
// Node
typedef NodeObj* Node;
// newNode()
// constructor of the Node type
Node newNode(char* key, char* value)
{
Node N = malloc(sizeof(NodeObj));
assert(N!=NULL);
// if(key!=NULL && value!=NULL){
N->key = key;
N->value = value;
N->next = NULL;
// }
return(N);
}
// DictionaryObj
typedef struct DictionaryObj{
Node head;
int numItems;
} DictionaryObj;
// newDictionary()
// constructor for the Dictionary type
Dictionary newDictionary(void){
Dictionary D = malloc(sizeof(DictionaryObj));
assert(D!=NULL);
D->head = NULL;
D->numItems = 0;
return D;
}
Node findKey(Dictionary D, char*key){
Node N;
N = D->head;
while(N != NULL){
if(strcmp(N->key,key)==0){
return N;
}
N = N->next;
}
return NULL;
}
char* lookup(Dictionary D, char* k){
if(findKey(D, k)==NULL){
return NULL;
}else{
Node N;
N = findKey(D, k);
return N->value;
}
}
void delete(Dictionary D, char* k)
{
if(lookup(D,k) == NULL){
fprintf(stderr,
"KeyNotFoundException: Cannot delete non-existent key\n");
exit(EXIT_FAILURE);
}
int check = strcmp(D->head->key, k);
if(check == 1){
D->head = D->head->next;
return;
}
Node cur;
Node prev;
cur = D->head;
prev = NULL;
while( cur != NULL){
int ret1;
ret1 = strcmp(cur->key, k);
while( ret1 == 0){
prev = cur;
cur = cur->next;
}
}
prev->next = cur->next;
D->numItems--;
}
The NodeObject should store copy of the string and care for deleting it:
typedef struct Node Node;
struct Node {
Node *next;
char *key, *value;
};
Node* newNode(char* key, char* value) {
assert(key && value);
Node* node = (Node*)malloc(sizeof(Node));
assert(node);
node->next = NULL;
node->key = strdup(key);
node->value = strdup(value);
}
void delNode(Node* node) {
free(node->key);
free(node->value);
}
Consider using the original code (without that strdup) in this scenairo:
Node* prepare() {
char key_buf[20]; strcpy(key_buf, "mykey");
char val_buf[20]; strcpy(val_buf, "myval");
return newNode(key_buf, val_buf);
}
void examine(Node* node) {
printf("Node key=%s value=%s\n", node->key, node->value);
}
int main() {
examine(prepare());
}
the above code would crash because Node would have pointers to stack (in your case without that strdup), but key_buf+val_buf were only valid inside prepare() (garbage outside and therefore inside examine() - node->key points to random data).

Resources