#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct strqueue {
struct lnode *front;
struct lnode *back;
int length;
};
struct lnode {
char *item;
struct lnode *next;
};
StrQueue create_StrQueue(void) {
struct strqueue *sq = malloc(sizeof(struct strqueue));
sq->length = 0;
sq->front = NULL;
sq->back = NULL;
return sq;
}
void destroy_nodes(struct lnode *l) {
while (l!=NULL) {
struct lnode *c = l;
l=l->next;
free(c);
}
}
void destroy_StrQueue(StrQueue sq) {
destroy_nodes(sq->front);
free(sq);
}
void sq_add_back(StrQueue sq, const char *str) {
struct lnode *n = malloc(sizeof(struct lnode));
n->item = malloc(sizeof(char)*(strlen(str)+1));
strcpy(n->item, str);
n->next = NULL;
if (sq->length == 0) {
sq->front = n;
sq->back = n;
} else {
sq->back->next = n;
sq->back = n;
}
sq->length++;
}
char *sq_remove_front(StrQueue sq) {
if (sq->front == NULL) {
return NULL;
} else {
struct lnode *f = sq->front;
char *temp = sq->front->item;
sq->front = sq->front->next;
sq->length--;
//Delete the line below will not cause an error of not free all memory
free(f->item);
free(f);
return temp;
}
}
int sq_length(StrQueue sq) {
return sq->length;
}
Here I wanna make the strqueue like a linked list but when I use it, it always says that I am attempting to double free something. Which part of my code is wrong? Is there a memory leak or something wrong about the memory allocation?
In
struct lnode *f = sq->front;
char *temp = sq->front->item;
sq->front = sq->front->next;
sq->length--;
//Delete the line below will not cause an error of not free all memory
free(f->item);
free(f);
return temp;
It returns pointer temp to freed memory in free(f->item), reading the string through that pointer is undefined behaviour. And if you free it that is going to be the double free. Basically, the returned pointer is useless.
The fix would be to avoid doing free(f->item) in that function. The caller would need to free the pointer to the string after use.
Singly-linked list is best represented by:
struct lnode *head, **tail;
Initialized as:
head = NULL;
tail = &head;
In this case there is no need for special handling of an empty list on appending. Appending always is:
*tail = n;
tail = &n->next;
Removing from the front is:
struct lnode *n = head;
if(head) {
head = head->next;
if(!head)
tail = &head;
}
return n;
You could try this in char *sq_remove_front(StrQueue sq) :
if (f->item != NULL) {
free(f->item);
f->item = NULL;
}
if (f != NULL) {
free(f);
sq->front = NULL;
}
It would avoid performing free() twice on the pointers.
Related
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;
}
I am implementing a simple version of malloc, realloc, and free for an assignment and having trouble debugging. My code seems to be working for malloc, but the realloc tests are resulting in a seg fault. Specifically, the pointer passed to free() seems to be the problem.
There is a "free list" to manage the list of previously allocated blocks of memory. Each node in this list maintains the next and previous blocks, and an int free which is set to 1 when the memory is available, 0 otherwise.
void *mm_malloc(size_t size) {
if (size <= 0) return NULL;
struct list_node *node;
if (!list_head) {
node = request_block(size);
list_head = node;
list_tail = node;
} else {
node = get_free_block(size);
if (!node) { //no available existing block
node = request_block(size);
if (!node) { //request failed
return NULL;
}
} else { //available existing block
//TODO: split block
node->free = 0;
}
}
return memset(node+1, 0, node->size);
}
void *mm_realloc(void *ptr, size_t size) {
if (size <= 0) return NULL;
if (!ptr) return mm_malloc(size);
struct list_node *node = (struct list_node*)ptr - 1;
if (node->size >= size) {
// TODO: free extra space
return ptr;
}
void *new_block = mm_malloc(size);
if (!new_block) return NULL;
memcpy(new_block, ptr, node->size);
free(ptr); //Error happens with this call.
return new_block;
}
void mm_free(void *ptr) {
if (!ptr) return;
struct list_node *node = (struct list_node*)ptr - 1;
node->free = 1;
}
EDIT: left out some important helper functions
struct list_node *get_free_block(size_t size) {
struct list_node *curr = list_head;
while (curr && !(curr->free && curr->size >= size)) {
curr = curr->next;
} return curr;
}
struct list_node *request_block(size_t size) {
struct list_node *node = sbrk(0);
void *request = sbrk(size + NODE_SIZE);
if (request == (void*) -1) { // attempted sbrk failed
return NULL;
}
if (list_tail) {
node->prev = list_tail;
list_tail->next = node;
list_tail = node;
}
node->next = NULL;
node->free = 0;
node->size = size;
return node;
}
I have been trying to free the allocated memory of a file loaded into a linked list, I have managed to free the nodes, but I can't figure out how to free the allocated memory of the file's values copies.
I have tried something like that:
void FreeString(struct node * newNode)
{
for (int i = 0; i < 5; i++)
{
free(newNode->string);
}
}
but the compiler would crash with a segmentation fault, and valgrind would still point out to memory leaks.
it would be appreciated if anyone can tell me what am I doing wrong, and point me to the right direction.
Full code:
The struct:
typedef struct node
{
char *string;
struct node *next;
}node;
// main function here...
void Push(struct node **RefHead, char *word)
{
struct node *newNode = NULL;
newNode = (struct node *)malloc(sizeof(node));
newNode->string = (char*)malloc(strlen(word) + 1); // can't free this part here
strcpy(newNode->string, word);
newNode->next = *RefHead;
*RefHead = newNode;
}
Loading the file into memory:
void FileToNode()
{
struct node *head = NULL, *current = NULL;
infile = fopen("file.txt", "r");
if (infile == NULL)
{
printf("Could not open file\n");
exit(1);
}
while (fgets(word, sizeof(word), infile))
{
Push(&head, word);
}
fclose(infile);
current = head;
while(current)
{
printf("%s", current->string);
current = current->next;
}
freeAll(head);
}
The Free function:
void freeAll(struct node *head)
{
struct node *current = NULL;
while ((current = head) != NULL)
{
head = head->next;
free(current);
}
}
Am I missing something? What's wrong with:
void freeAll(struct node *head)
{
struct node *current = NULL;
while ((current = head) != NULL)
{
head = head->next;
free(current->string);
free(current);
}
}
It's not the problem, but you should probably replace:
newNode->string = (char*)malloc(strlen(word) + 1); // can't free this part here
strcpy(newNode->string, word);
with:
newNode->string = strdup (word);
The problem is this:
void FreeString(struct node * newNode)
{
for (int i = 0; i < 5; i++)
{
free(newNode->string);
}
}
Once you call free, newNode->string no longer points to an allocated object (because you just freed it). So you can't pass it to free again.
#define SIZE 7000
static char buf[SIZE];
static char *bufptr = buf;
struct node
{
int reg_num;
int val;
char var_name[30];
char var_str[100];
struct node *memroy;
struct node *next;
};
struct node* add(struct node *head, int i)
{
struct node *temp;
if (head == NULL)
{
temp = (struct node *)malloc(sizeof(struct node));
temp->next = NULL;
temp->reg_num = i;
head = temp;
}
else
{
head->next = add(head->next, i);
}
return head;
}
void* malloc(int n)
{
if (buf + SIZE - bufptr >= n)
{
bufptr += n;
return bufptr - n;
}
else
{
return NULL;
}
}
When I run my programm it crashes during the assignment temp->next = NULL.
I think the problem is in my malloc function. I tested it with malloc in libraries and it worked correctly, but I not allowed to use libraries and must write a new malloc function.
You never check the return of your malloc yet you know it can return NULL;.
Check if temp is NULL before doing temp->next = NULL;
My problem don't has relation with kind of pointer and returned value from malloc().I have problem with size of buf[] and by increment of size my problem solved.Tnx from every one.
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).