Own free() in c | melt free data blocks - c

i had to write my own free & malloc function.
So far I have not had a problem with that, but now I am supposed to merge neighboring free memory blocks in the halde_free() function. I would be really grateful if you could help me there.
#include "halde.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
/// Magic value for occupied memory chunks.
#define MAGIC ((void*)0xbaadf00d)
/// Size of the heap (in bytes).
#define SIZE (1024*1024*1)
/// Memory-chunk structure.
struct mblock {
struct mblock *next;
size_t size;
char memory[];
};
/// Heap-memory area.
char memory[SIZE];
/// Pointer to the first element of the free-memory list.
static struct mblock *head;
/// Helper function to visualise the current state of the free-memory list.
void halde_print(void) {
struct mblock* lauf = head;
// Empty list
if ( head == NULL ) {
fprintf(stderr, "(empty)\n");
return;
}
// Print each element in the list
while ( lauf ) {
fprintf(stderr, "(addr: 0x%08zx, off: %7zu, ", (uintptr_t) lauf, (uintptr_t)lauf - (uintptr_t)memory);
fflush(stderr);
fprintf(stderr, "size: %7zu)", lauf->size);
fflush(stderr);
if ( lauf->next != NULL ) {
fprintf(stderr, " --> ");
fflush(stderr);
}
lauf = lauf->next;
}
fprintf(stderr, "\n");
fflush(stderr);
}
void *halde_malloc (size_t size) {
static int initialized = 0;
if(initialized == 0){
head = (struct mblock *) memory;
head->size = sizeof(memory) - sizeof (struct mblock);
head->next = NULL;
initialized = 1;
}
if(size == 0){
return NULL;
}
struct mblock *lauf = head;
struct mblock **prev_next = &head;
while (lauf != NULL && lauf->size < size){
prev_next = &(lauf->next);
lauf = *prev_next;
}
if(lauf == NULL){
errno = ENOMEM;
return NULL;
}
if((lauf->size -size) <= sizeof(struct mblock)){
*prev_next = lauf->next;
} else {
//mblock anlegen und init.
struct mblock* neu = (struct mblock*) (lauf->memory + size);
neu->size = lauf->size - sizeof(struct mblock) - size;
neu->next = lauf->next;
//mblock anpassen
lauf->size = size;
//verketten wiederherstellen
*prev_next = neu;
}
lauf->next = MAGIC;
return lauf->memory;
}
void halde_free (void *ptr) {
if(ptr == NULL){
return;
}
struct mblock *mbp = (struct mblock *) ptr - 1;
if(mbp->next != MAGIC){
abort();
} else {
mbp->next = head;
head = mbp;
}
}
The code works so far but i have really no idea how to merge blocks..
The memory management runs over a simply linked lists. The variable head points to the first free memory block.
My idea is to merge the blocks directly in the else part but i don't have a good idea to do that..

Related

How can I free all instances of dynamically allocated memory in this C code

I've written this C code. In the beginning, I used file handing to read a text file and insert every line as a string in a linked list. I need to free all cases of memory allocation in the program in a separate void function. How do I do that? I only included the parts of the code that are relevant because it's a pretty long program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#include <ctype.h>
/*Node of linked list*/
typedef struct node {
char *data;
struct node *next;
} node;
node *start = NULL;
node *current;
typedef enum {
not_tested, found, missed
} state;
/*Appending nodes to linked list*/
void add(char *line) {
node *temp = (node *)malloc(sizeof(node));
temp->data = strdup(line);
temp->next = NULL;
current = start;
if (start == NULL) {
start = temp;
}
else {
while (current->next != NULL) {
current = current->next;
}
current->next = temp;
}
}
/*read text file*/
void readfile(char *filename) {
FILE *file = fopen(filename, "r");
if (file == NULL) {
exit(1);
}
char buffer[512];
while (fgets(buffer, sizeof(buffer), file) != NULL) {
add(buffer);
}
fclose(file);
}
This is not exactly what you're asking for, but I show you how to build a little class that allocates chunks of memory that can bee freed in a single call. This is especially useful when you have lots of small pieces of memory to allocate and therefore to free after usage.
It could seem too many codes for your usage, but note that such a class can be saved in a independent file and reused each time it's needed :
struct Allocator {
void * buffer;
size_t capacity;
size_t usedSize;
};
struct Allocator * newAllocator(size_t initialSize) {
struct Allocator * allocator = malloc(sizeof(*allocator));
if (! allocator) return NULL;
allocator->buffer = malloc(initialSize);
if (! allocator->buffer) { free(allocator); return NULL; }
allocator->capacity = initialSize;
allocator->usedSize = 0;
return allocator;
}
void freeAllocator(struct Allocator * allocator) {
if (!allocator) return;
if (allocator->buffer) free(allocator->buffer);
free(allocator);
}
void * allocate(struct Allocator * allocator, size_t size) {
if (size + allocator->usedSize > allocator->capacity) {
while (size + allocator->usedSize > allocator->capacity) allocator->capacity *= 2;
allocator->buffer = realloc(allocator->buffer, allocator->capacity);
}
void * ptr = allocator->buffer + allocator->usedSize;
allocator->usedSize += size;
return ptr;
}
//-------- END ALLOCATOR
struct node {
//...
};
// How to replace a call to malloc to allocate a node :
void add(struct Allocator *allocator, char *line) {
struct node *temp = allocate(allocator, sizeof(*temp));
//...
}
int main()
{
FILE *file = fopen("myfileName", "r");
if (file == NULL) exit(1);
// Allocates the buffer and as many nodes as needed
struct Allocator *allocator = newAllocator(1024);
char * buffer = allocate(allocator, 512);
while (fgets(buffer, 512, file) != NULL) {
add(allocator, buffer);
}
// Free all allocated memory in a single call
freeAllocator(allocator);
return 0;
}

segmentation fault in a linked list while loop?

I'm trying to setup a graph in C. I tried the graph with user input and it works perfectly. However, i am trying to implement a read from file. The last else statement is where the error is coming from because when i commented it out it compiles without any problems. I have included a comment over the block i think that has the problem. Please let me know if there is anything else needed for this question.
#include <stdio.h>
#include <stdlib.h>
struct node{
int data;
struct node* next;
};
//int counter and mainVertex would be used to determine if graph is connected.
// void graphConnection(){
//
//
//
//
//
//
// }
char* deblank(char* input)
{
int i,j;
char *output=input;
for (i = 0, j = 0; i<strlen(input); i++,j++)
{
if (input[i]!=' ')
output[j]=input[i];
else
j--;
}
output[j]=0;
return output;
}
struct node *G[1000];
int counter = 0;
char *mainVertex;
void readingEachLine(){
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
//Read file and exit if fail
fp = fopen("test.txt", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
line = deblank(line);
int i = 0;
struct node* cursor = malloc(sizeof(struct node));
struct node* secondcursor = malloc(sizeof(struct node));
struct node* tempitem;
while(line[i] != '\n'){
//If its the first of the line look into the array and set struct cursor to the corresponding
//array position
if (i == 0){
mainVertex[counter] = line[0];
int convertor = line[i] - '0';
cursor = G[convertor];
counter++;
}
//if its not the first, then set a struct with that number as data
else{
tempitem = malloc(sizeof(struct node));
int convertor = line[i] - '0';
tempitem->data = convertor;
tempitem->next = NULL;
}
//if there is no element connected to the struct in array, connect the tempitem
if (cursor->next == NULL){
cursor->next = tempitem;
}
//If there are already connected elements, loop until the end of the linked list
//and append the tempitem
//ERROR: I GET SEGMENTATION FAULT FROM HERE. TRIED AFTER COMMENTING IT OUT
else{
secondcursor = cursor;
while(secondcursor->next != NULL){
secondcursor = secondcursor->next;
}
secondcursor->next = tempitem;
}
i++;
}
printf("\n");
}
}
int main(void){
for (int i = 1; i < 1000; i++)
{
G[i]= malloc(sizeof(struct node));
G[i]->data = i;
G[i]->next = NULL;
}
readingEachLine();
}
EDIT: This is how the text file looks like:
1 3 4
2 4
3 1 4
4 2 1 3
Your code has several misconceoptions:
Apparently, you can have a maximum of 1,000 nodes. You have an array G of 1,000 head pointers to linked lists. Don't allocate memory for all 1,000 nodes at the beginning. At the beginning, all lists are empty and an empty linked list is one that has no node and whose head is NULL.
In your example, cursor is used to iterate oer already existing pointers, so don't allocate memory for it. If you have code like this:
struct node *p = malloc(...);
// next use of p:
p = other_node;
you shouldn't allocate. You would overwrite p and lose the handle to the allocated memory. Not all pointers have to be initialised with malloc; allocate only if you create a node.
Your idea to strip all spaces from a line and then parse single digits will fail if you ever have more then 9 nodes. (But you cater for 1,000 node.) Don't try to parse the numbers yourself. There are library functions for that, for example strtol.
It is not clear what mainVertex is supposed to be. You use it only once, when you assign to it. You treat it like an array, but it is a global pointer, initialised to NULL. When you dereference it, you get undefined behaviour, which is where your segmentation fault probably comes from.
Here's a program that does what you want to do. (It always inserts nodes at the head for simplicity and it should have more allocation checks.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum {
maxNodes = 1000
};
struct node{
int data;
struct node* next;
};
struct node *G[maxNodes];
size_t nnode = 0;
int read_graph(const char *fn)
{
FILE * fp;
char * line = NULL;
size_t len = 0;
fp = fopen(fn, "r");
if (fp == NULL) return -1;
while (getline(&line, &len, fp) != -1) {
char *p;
char *end;
int id;
int n;
id = strtol(line, &end, 10);
if (end == line) continue;
if (id < 1 || id > maxNodes) break;
if (id > nnode) nnode = id;
id--;
p = end;
n = strtol(p, &end, 10);
while (p != end) {
struct node *nnew = malloc(sizeof(*nnew));
nnew->data = n - 1;
nnew->next = G[id];
G[id] = nnew;
p = end;
n = strtol(p, &end, 10);
}
}
fclose(fp);
free(line);
return 0;
}
int main(void)
{
if (read_graph("test.txt") < 0) {
fprintf(stderr, "Couldn't gread raph.\n");
exit(1);
}
for (int i = 0; i < nnode; i++) {
struct node *p = G[i];
if (p) {
printf("%d:", i + 1);
for (; p; p = p->next) {
printf(" %d", p->data + 1);
}
puts("");
}
}
for (int i = 0; i < nnode; i++) {
struct node *p = G[i];
while (p) {
struct node *old = p;
p = p->next;
free(old);
}
}
return 0;
}

Trouble with Malloc and Linked List

I have a function that reads a text file filled with a word on every line. Here is an example of a text file I'm using
and
but
five
follows
four
has
is
like
line
lines
littlest
not
once
one
only
other
six
the
three
twice
two
word
words
Code:
typedef struct node node_t;
struct node {
char data[MAX_WORD];
int term;
node_t *next;
};
node_t *head;
int
int_struct(int lines){
FILE *fp;
char ch;
int n = 0, i, switch_num=1, test_first=0, test_first_2=0;
node_t *node, *curr_add;
fp = fopen("text.txt", "r");
node = (node_t*)malloc(sizeof(node_t));
for (i=1; i<=lines; i++){
switch_num = 1;
n=0;
if (test_first != 0){
if (test_first_2){
node = (node_t*)malloc(1000000);
}
test_first_2=1;
while ((ch = getc(fp)) != '\n'){
node -> term = i;
node -> data[n] = ch;
n++;
}
curr_add -> next = node;
curr_add = node;
}
else{
test_first = 1;
head = curr_add = node;
}
}
curr_add -> next = NULL;
fclose(fp);
return num;
}
What I want to do is to read each word and add it to a linked list.
However I am having trouble with malloc (at the moment I just add in a lot of bytes) and need advice on how to properly use it inside the function I have. I've done a general search and tried my best to try and do what most examples do. But I still can't seem to get my function working. For example, every time I execute the program it will read and add all the words into the linked list. However, the program crashes on the last word, and returns NULL. If anyone is able to point me in the right direction, I'd be very grateful.
Issues
There are no checks for return values. Particularly, fopen and malloc
may return NULL. If they do, you'll catch a segmentation fault error on the
first attempt to access the returned value.
Overcomplicated logic. You don't need these switch_num, test_first and test_first_2
variables (see sample code below).
No need in getc when you're reading a text file line-by-line - use
fgets instead.
Too many memory allocations. You don't need more than sizeof(node_t) + length of the line bytes per line.
The allocated memory is not freed. The dynamic memory should be freed as
soon as it is not needed.
Example using linked list
The following reads a text file into a linked list. Memory is allocated for
each list item, and for each line in the file resulting in n * 2 memory
allocations, where n is the number of lines in the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strerror, strdup */
#include <errno.h>
typedef struct _node {
unsigned line;
char *data;
struct _node *next;
} node_t;
static void
destroy_list(node_t *list)
{
node_t *node;
for (node = list; node; node = node->next) {
if (node->data != NULL)
free(node->data);
free(node);
}
}
static node_t *
create_list_item(const char *data, unsigned line)
{
node_t *node = calloc(1, sizeof(node_t));
if (node == NULL) {
fprintf(stderr, "calloc: %s\n", strerror(errno));
} else {
node->line = line;
node->data = strdup(data);
if (node->data == NULL) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
free(node);
node = NULL;
}
}
return node;
}
/* Returns pointer to new linked list */
static node_t *
read_file(FILE *fp, char *buf, size_t buf_len)
{
node_t *list = NULL;
node_t *prev = NULL;
node_t *node;
unsigned i;
for (i = 0; fgets(buf, buf_len, fp); prev = node) {
if ((node = create_list_item(buf, ++i)) == NULL) {
fprintf(stderr, "calloc: %s\n", strerror(errno));
break;
}
if (list == NULL)
list = node;
if (prev != NULL)
prev->next = node;
}
return list;
}
static void
print_list(const node_t *list)
{
const node_t *node;
for (node = list; node; node = node->next)
printf("%d: %s", node->line, node->data);
}
int main(int argc, char const* argv[])
{
const char *filename = "text.txt";
char buf[1024] = {0};
FILE *fp = NULL;
node_t *list = NULL;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "failed to open file %s: %s\n",
filename, strerror(errno));
return 1;
}
list = read_file(fp, buf, sizeof(buf));
fclose(fp);
if (list) {
print_list(list);
destroy_list(list);
}
return 0;
}
Example using dynamic array
It is inefficient to allocate memory for each line (twice) in the file,
not only because the system calls (malloc, realloc, etc.) are costly,
but also because the items are placed non-contiguously. Accessing contiguous
region of memory is usually faster.
In the following code, the linked list is replaced with dynamic array. We
initialize memory for 10 lines at once. The size is increased as necessary.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strerror, strdup */
#include <errno.h>
typedef struct _node {
size_t line;
char *data;
} node_t;
static void
destroy_array(node_t *array, size_t size)
{
size_t i;
node_t *item;
for (i = 0; i < size; i++) {
item = &array[i];
if (item->data)
free(item->data);
}
free(array);
}
static void
print_array(node_t *array, size_t size)
{
size_t i;
node_t *item;
for (i = 0; i < size; i++) {
item = &array[i];
if (item->data) {
printf("%ld: %s", item->line, item->data);
}
}
}
static node_t *
read_file(FILE *fp, char *buf, size_t buf_len,
const size_t array_step, size_t *array_size)
{
node_t *item;
node_t *array = calloc(array_step, sizeof(node_t));
size_t size = 0;
if (array == NULL) {
fprintf(stderr, "calloc:%s\n", strerror(errno));
return array;
}
while (fgets(buf, buf_len, fp)) {
if (size && size % array_step == 0) {
array = realloc(array, sizeof(node_t) * (array_step + size));
if (array == NULL) {
fprintf(stderr, "realloc:%s\n", strerror(errno));
break;
}
}
item = &array[size++];
item->line = size;
item->data = strdup(buf);
if (item->data == NULL) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
break;
}
}
*array_size = size;
return array;
}
int main(int argc, char const* argv[])
{
node_t *array;
const size_t array_step = 10;
size_t array_size;
const char *filename = "text.txt";
char buf[1024] = {0};
FILE *fp = NULL;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "failed to open file %s: %s\n",
filename, strerror(errno));
return 1;
}
array = read_file(fp, buf, sizeof(buf), array_step, &array_size);
fclose(fp);
if (array) {
print_array(array, array_size);
destroy_array(array, array_size);
}
return 0;
}
Note the changes in node_t structure.

Segmentation fault while allocating memory for front element of a queue in C

I have Node and Queue structs in the file queue.h
#ifndef QUEUE_H
#define QUEUE_H
#include<stdio.h>
#include<stdbool.h>
typedef struct rcb
{
int seq_no;
int file_desc;
FILE *fp;
long sent;
long sizeOfFile;
char *request_http_method;
char *request_file;
char *request_http_version;
int level;
bool is_new_created;
int remaining;
}* RCB;
/*
* Node of the queue.
*/
typedef struct node {
RCB info; //Data of each node.
struct node *ptr;//pointer to the next node.
} * Node;
/*
* Queue for the requests.
*/
typedef struct req_queue {
Node front; //front node.
Node rear; //rear node.
int size; //size of the queue.
} * Queue;
/**
* Create the queue.
*/
void create(Queue queue);
/**
* For inserting an item to the queue in sorted order of file size.
* #param data
*/
void enque_SJF(Queue queue, RCB data);
#endif
queue.c
#include "queue.h"
Node temp, front1;
int count = 0;
/**
* For creating the queue.
*/
void create(Queue queue) {
queue->front = queue->rear = NULL;
queue->size=0;
}
/**
* Enqueing in the order of increasing file size.
* #param data
*/
void enque_SJF(Queue que, RCB data) {
bool found = false;
Node temp = que->front;
while (!found) {
if (que->front == NULL) { //if the queue is empty.
que->front = malloc(sizeof (struct node));
que->front->ptr = NULL;
que->front->info = data;
que->rear = que->front;
break;
} else {
if (temp->ptr == NULL) {
Node newnode = (struct node *) malloc(1 * sizeof (struct node));
newnode->info = data;
if (temp->info->sizeOfFile >= data->sizeOfFile) {
newnode->ptr = temp;
que->front = newnode;
break;
} else { //else enqueue at the rear.
temp->ptr = newnode;
}
} else {
if (temp == que->front && temp->info->sizeOfFile >= data->sizeOfFile) {
Node newnode = (struct node *) malloc(1 * sizeof (struct node));
newnode->info = data;
newnode->ptr = temp;
que->front = newnode;
break;
}
if (temp->ptr->info->sizeOfFile >= data->sizeOfFile) {
Node newnode = (struct node *) malloc(1 * sizeof (struct node));
newnode->info = data;
newnode->ptr = temp->ptr;
temp->ptr = newnode;
break;
} else
temp = temp->ptr;
}
}
}
que->size++;
}
I am trying to enqueue a new node to a queue in the function enque_SJF in queue.c file. The enqueue function is called in sws.c by the function serve_client function. Here is the sws.c There are some more functions in those files but they are not related with my problem so i didnt wrote all functions to be more simple;
#include "Queue.h"
#include "network.h"
#include "schedulers.h"
#include "shared.h"
char scheduler[4];
pthread_t tid[2];
int port;
Queue req_queue;
bool flag[2];
int turn;
int sequence_number;
void *serve_client()
{
static char *buffer; /* request buffer */
int fd;
req_queue = (struct req_queue *) malloc( sizeof (struct req_queue));
create(req_queue);
if (port != 0)
{
network_init( port ); /* init network module */
fprintf(stderr, "Connection port %d\n", port);
for( ;; )
/* main loop */
{
network_wait();
if( !buffer ) /* 1st time, alloc buffer */
{
buffer = malloc( MAX_HTTP_SIZE );
if( !buffer ) /* error check */
{
perror( "Error while allocating memory" );
abort();
}
}
for( fd = network_open(); fd >= 0; fd = network_open() ) /* get clients */
{
memset( buffer, 0, MAX_HTTP_SIZE );
if( read( fd, buffer, MAX_HTTP_SIZE ) <= 0 ) /* read req from client */
{
perror( "Error while reading request" );
abort();
}
printf("file path %s\n",buffer);
//Initializing memory for the job.
RCB request = (RCB) malloc(1 * sizeof (struct rcb));
//breaking the request in appropriate format.
request-> request_http_method = strtok(buffer, " "); //request method.
request->request_file = strtok(NULL, " /"); //request file
request->request_http_version = strtok(NULL, "\n"); //HTTP version
request->file_desc = fd;
request->level = 1; // for multilevel scheduler.
request->seq_no = sequence_number;
sequence_number++; //increment global counter.
enque_SJF(req_queue, request); //Enqueue for Shortest Job First.
}
}
}
return 0;
}
bool isValidRequest(RCB request)
{
// the request is parsed and checked the validity
}
void *SJF( )
{
// function implemented
}
int main(int argc, char **argv )
{
//default port, if no port is supplied.
/* check for and process parameters
*/
if( ( argc < 3 ) || ( sscanf( argv[1], "%d", &port ) < 1 ) || ( sscanf( argv[2], "%s", scheduler ) < 1 ) )
{
printf("port %d\n",port);
printf("port %s\n",scheduler);
printf( "usage: sms <port> <scheduler>\n" );
return 0;
}
sequence_number = 1; //counter for number of requests.
if (argc == 3)
{
port = atoi(argv[1]);
}
printf("port %d\n",port);
pthread_create(&(tid[0]), NULL, serve_client, NULL);
if(strcmp(scheduler,"SJF") ==0)
{
pthread_create(&(tid[1]), NULL, SJF, NULL);
}
else if(strcmp(scheduler,"RR")==0)
{
pthread_create(&(tid[1]), NULL, Round_Robin, NULL);
}
else if(strcmp(scheduler,"MLFB")==0)
{
pthread_create(&(tid[1]), NULL, MultilevelQueueWithFeedback, NULL);
}
else
{
printf("Scheduler Algorithm is not defined. Please enter one of them; SJF, RR, MLFB");
return 0;
}
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
While adding a new node to the queueu i am getting a segmentation fault error at the following line;
que->front->ptr = NULL;
While debugging, i see that after memory allocation the address for que->front is still 0x0. Is there any suggestion why it does not allocate memory?
That is why you should always perform success check for the called function(s).
In case, if malloc() is failure, it will return a NULL pointer which gets stored in que->front. After that, without a NULL check, if you try to access
que->front->ptr
you'll be de-referencing a NULL pointer (i.e, accessing invalid memory) which invokes undefined behavior.
Always do a NULL check on the return value of malloc().

freeing allocated memory generates segmentation fault

I tried reading from text file, and then put every word in list node(and print it afterwards in reverse order).
The program works good, but when trying to free the allocated list nodes, the program crash.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <math.h>
typedef struct node{
char* word;
struct node* next;
}; typedef struct node* list;
void freeall(list lst){
list temp = NULL;
while (lst)
{
temp = lst->next;
free(lst);
lst = temp;
}
#if 0
if (lst == NULL){ return; }
freeall(lst->next);
free(lst->word);
free(lst);
#endif // 0
}
void deleteAllNodes(list start)
{
while (start != NULL)
{
list temp = start;
free(temp);
start = start->next;
}
}
list createNode(char* buff){
list newnode = (list)malloc(sizeof(list));
assert(newnode);
newnode->next = NULL;
newnode->word = (char*)calloc(strlen(buff), sizeof(char));
assert(newnode->word);
strcpy(newnode->word, buff);
return newnode;
}
void reverse(const char *str) //you don't need to modify your string
{
if (*str != '\0'){ //if the first character is not '\O'
reverse((str + 1)); // call again the function but with +1 in the pointer addr
printf("%c", *str); // then print the character
}
}
void print_reverse(list lst){
if (lst == NULL) return;
print_reverse(lst->next);
reverse(lst->word);
//free(lst->word);
}
list createList(FILE* ifp){
struct node *loop = NULL;
list curr = NULL;
list lst = NULL;
char *word = NULL;
size_t size = 2;
long fpos = 0;
char format[32];
if (ifp == NULL) // open file
perror("Failed to open file \n");
if ((word = malloc(size)) == NULL) // word memory
perror("Failed to allocate memory");
sprintf(format, "%%%us", (unsigned)size - 1); // format for fscanf
while (fscanf(ifp, format, word) == 1) {
while (strlen(word) >= size - 1) { // is buffer full?
size *= 2; // double buff size
printf("** doubling to %u **\n", (unsigned)size);
if ((word = realloc(word, size)) == NULL)
perror("Failed to reallocate memory");
sprintf(format, "%%%us", (unsigned)size - 1);// new format spec
fseek(ifp, fpos, SEEK_SET); // re-read the line
if (fscanf(ifp, format, word) == 0)
perror("Failed to re-read file");
}
curr = createNode(word);
if (lst == NULL){lst = curr;}
else{
loop = lst;
while (loop->next != NULL) {//loop to last structure
loop = loop->next;//add structure to end
}
loop->next = curr;
}
fpos = ftell(ifp); // mark file pos
}
free(word);
return lst;
}
int main(int argc, char* argv[]){
assert(argc == 2);
FILE *ifp = fopen(argv[1], "r");
assert(ifp);
list lst = NULL;
lst = (list)malloc(sizeof(list));
lst = createList(ifp);
print_reverse(lst);
fclose(ifp);
//freeall(lst);
//deleteAllNodes(lst);
return 1;
}
your delete all nodes has a bug in it. You freed a pointer and tried accessing it immediately. So the program crashes You can try this
void deleteAllNodes(list head)
{
list ptr = head;
while ((ptr = head) != NULL)
{
head = head->next;
free (ptr);
}
}
point the current ptr to the head and point head to next element. Delete the current pointer.
In your deleteAllNodes function you are free-ing a pointer and then accessing it. You could try deleting nodes in reverse order, starting from the last one, for instance with a recursive function.
void deleteAllNodes(list start)
{
if (start != NULL)
{
deleteAllNodes(start->next);
free(start);
}
}
Or you can stick to the iterative forward deletion with something like (untested):
void deleteAllNodes(list start)
{
list previous = NULL;
while (start != NULL)
{
if (previous != NULL)
free(previous);
previous = start;
start = start->next;
}
if (previous != NULL)
free(previous);
}
The problem , as I see it is with
list newnode = (list)malloc(sizeof(list));
your list is a typedef to struct node*, so this statement is essentially
list newnode = (list)malloc(sizeof(struct node*));
which is wrong. You're allocating memory for a pointer to structure variable, whereas, you should be allocating memory equal to the size of the structure variable itself.
Two things to mention here
Please see why not to cast the return value of malloc() and family in C.
Never use a typedef for a pointer type. It's not a "rule", but better to stick to it.
Your allocation statement, at least, shall look like
list = malloc(sizeof*list);
Apart from this, in your main() function,
First, you're allocating memory to lst using malloc() [Same issue with the allocation as above]
Then, you assign another pointer, the return value of createList() to lst.
This way, you're overwriting the allocated mekory through malloc(), creating memory leak. You don't need malloc() there, at all.

Resources