I'm trying to implement my own malloc and then test it by dumping the heap to see what I've managed to accomplish. It compiles fine but when I run it, I get the output of
head->[1:0:8]->NULL
this is a test program
after which it promptly crashes. It looks like the way I implemented my malloc, it is able to allocate the space for *this and *is, but that's all. Anyone have any ideas why this might be?
My main.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#define MALLOC(n) my_malloc(n)
#define DUMP_HEAP() dump_heap()
void* my_malloc(int);
int main()
{
char *this = MALLOC(5);
char *is = MALLOC(3);
char *a = MALLOC(2);
char *test = MALLOC(5);
DUMP_HEAP();
strcpy(this, "this");
strcpy(is, "is");
strcpy(a, "a");
strcpy(test, "test");
strcpy(program, "program");
printf("%s %s %s %s %s\n", this, is, a, test, program);
DUMP_HEAP();
return 0;
}
My malloc.c
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
struct Block
{
int occ;
int size;
struct Block *prev;
struct Block *next;
};
static struct Block *head = NULL;
void *my_malloc(int size)
{
void *pointer;
pointer = (void*)sbrk(size);
if(head == NULL)
{
head = pointer;
head->occ = 1;
head->prev=NULL;
head->next=NULL;
head->size = size;
return (void*)head+sizeof(struct Block);
}
else
{
struct Block* new ;
new = pointer;
head->next = new;
new->size = size;
new->occ = 1;
new->prev = head;
new->next = NULL;
head = new;
return (void*)new+sizeof(struct Block);
}
}
void dump_heap()
{
struct Block *cur;
printf("head->");
for(cur = head; cur != NULL; cur = cur->next)
{
printf("[%d:%d:%d]->", cur->occ, (char*)cur - (char*)head, cur->size);
assert((char*)cur >= (char*)head && (char*)cur + cur->size < (char*)sbrk(0));
if(cur->next != NULL) assert(cur->next->prev == cur);
}
printf("NULL\n");
}
You aren't accounting for the size of the Block struct when asking the system for memory.
Compare this line:
pointer = (void*)sbrk(size);
to how you're attempting to account for the struct later:
return (void*)head+sizeof(struct Block);
You should be accounting for the size of the Block in the sbrk call:
pointer = (void*)sbrk(size + sizeof(struct Block));
Also, as has been pointed out, you should not do pointer arithmetic on void*. So your return statements should leave the head pointer uncasted and just add 1 to account for the block size:
return (void*)(head + 1);
Also also, upon further discussion it is clear that head is being used as the tail of the linked list. This introduces a bug in dump_heap. You may want to rename head to tail and maintain a proper head, one which only ever changes in malloc when it was previously NULL.
Related
Recently started to practice linked lists. I am aware of the basic algorithm and concept and thought of implementing LL to store a bunch of strings which are input by the user.
But apparently I keep getting Segmentation fault.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _node{
char *s;
struct _node *next;
}
node;
int main()
{
node *head = NULL;
int a = 0;
char ch;
char *str = malloc(10);
do
{
printf("\nDude %i:", a);
fgets(str, 10, stdin);
node *n = malloc(sizeof(node));
if(n == NULL)
{
printf("\ninsufficient memory");
return 1;
}
if(a == 0)
{
strcpy(n->s, str);
n->next = NULL;
head = n;
}
else
{
strcpy(n->s, str);
n->next = head;
head = n;
}
a++;
printf("\n continue?(y/n): ");
scanf("\n%c", &ch);
}while(ch == 'y');
for(node *temp = head; temp != NULL; temp = temp -> next)
{
printf("\n%s", temp->s);
}
return 0;
}
I do understand that my logic/code is flawed somewhere since I am touching memory I should not touch but cannot seem to point out where since it is my first time dealing with linked lists.
When you are malloc'ing space for the struct, you are only allocating space for the pointer to the string in your _node struct. You need to allocate some memory where you store the string and point the pointer s to it, before you do the strcpy.
i.e.
n->s = malloc(sizeof(char)*100);
Remember that you also need to have a strategy to de-allocate this memory.
As the others hinted, these sort of errors are usually easily caught by looking/debugging with gdb. Remember that it's useful to compile with the -g flag to get useful debugging info.
The reason you catch a ''Segmentation fault' is because you don't allocate memory for s variable of struct node before copying actual string: strcpy(n->s, str).
So, allocate memory for s:
n->s = (char *) malloc(10 * sizeof(char));
Note that you cannot write anything into an unallocated space, so you need to call malloc for the string in each node.
If the string lengths are fixed, then you can specify the length in the definition of struct node to avoid the malloc problem.
Also, it is suggested to always free the objects that will no longer be referenced.
With a few revisions, the codes below may be helpful:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 10
typedef struct node {
char str[LEN];
struct node *next;
} Node;
int main() {
Node *head = NULL;
int n = 0;
char c = 'y';
while (c == 'y') {
Node *node = malloc(sizeof(Node));
printf("Node #%d: ", n);
scanf(" ");
/* Store the string directly into the node. */
fgets(node->str, 10, stdin);
/* Remove the newline character. */
node->str[strcspn(node->str, "\n")] = 0;
node->next = head;
head = node;
++n;
printf("Continue? (y/N): ");
scanf("%c", &c);
};
Node *curr = head;
while (curr != NULL) {
printf("%s\n", curr->str);
Node *temp = curr;
curr = curr->next;
/* Remember to free the memory. */
free(temp);
}
return 0;
}
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;
}
I want to hash small dictionary ("dictionaries/small"). Main file compiles correctly, but at runtime it produces "Segmentation fault" message with function insert() (specifically something wrong with malloc(), but I don`t know what).
HASH.c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
typedef struct node
{
char* name;
struct node* next;
}
node;
node* first[26] = {NULL};
int hash(const char* buffer)
{
return tolower(buffer[0]) - 'a';
}
void insert(int key, const char* buffer)
{
node* newptr = malloc(sizeof(node));
if (newptr == NULL)
{
return;
}
strcpy(newptr->name, buffer);
newptr->next = NULL;
if (first[key] == NULL)
{
first[key] = newptr;
}
else
{
node* predptr = first[key];
while (true)
{
if (predptr->next == NULL)
{
predptr->next = newptr;
break;
}
predptr = predptr->next;
}
}
}
In function insert() you correctly allocate the new node:
node* newptr = malloc(sizeof(node));
In this way you make room for a full struct node: a pointer to node and a pointer to char. But you don't allocate the space where those pointer are supposed to point.
So, when you copy the input buffer within name field, you are performing an illegal attempt to write to a char * pointer that has not been allocated and not even initialized:
strcpy(newptr->name, buffer);
All pointers need to be allocated (or at least initialized to a valid memory location) before writing in them. In your case:
newptr->name = malloc( strlen( buffer ) + 1 );
if( newptr->name )
{
strcpy(newptr->name, buffer);
}
I am not sure why I am getting these errors, but the weirdest thing, I am still able to run the program and produce the results I want.
The compiler error I get is
IntelliSense: a value of type "MyStruct *" cannot be assigned to an entity of type "Mystuct_struct *"
There are 4 instances of this, but as I stated in my title, the program still seems to run fine, and displays the bin file as I want it to. And yes, I know the name of my structure is bad.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
typedef struct MyStruct_struct
{
char FlightNum[7];
char OriginAirportCode[5];
char DestAirportCode[5];
int timeStamp;
struct Mystruct_struct* next;
} MyStruct;
int main()
{
time_t time;
MyStruct * ptr;
MyStruct * head;
MyStruct * tail;
MyStruct * temp;
FILE * bin;
MyStruct myStruct;
bin = fopen("acars.bin", "rb");
ptr= (struct MyStruct_struct *) malloc (sizeof(MyStruct) );
fread(ptr,sizeof(MyStruct)-sizeof(MyStruct*),1,bin);
head = ptr; // make head point to that struct
tail = ptr; // make tail point to that struct
while (1)
{
ptr = (struct MyStruct_struct *) malloc(sizeof(MyStruct));
fread(ptr, sizeof(MyStruct) - sizeof(MyStruct*), 1, bin);
tail->next = ptr; // error here
tail = tail->next; //error here
if (feof(bin) != 0)
break;
}
tail->next = NULL;
ptr = head;
while (ptr->next != NULL)
{
printf("%s ", ptr->FlightNum);
printf("%s ", ptr->OriginAirportCode);
printf("%s ", ptr->DestAirportCode);
time = ptr->timeStamp;
printf("%s",ctime( &time));
ptr = ptr->next; // here
}
ptr = head;
while (ptr->next != NULL)
{
temp = ptr;
ptr = ptr->next; //error here
free(temp);
}
fclose(bin);
system("pause");
return 0;
}
You have a typo in your struct definition. The type for your variable next is MyStuct_Struct. Check your spelling on MyStuct_Struct. It still works because C is joiously not type safe. A pointer is a pointer is a pointer so you don't end up with memory errors.
I created a linked list program it works perfect with ints in c.
but if change the parameter to char array, and try to do a strcpy it causes a core dump.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char mac[25];
struct node * next;
};
typedef struct node *list;
int main(void) {
lista c;
c = creoLista();
c = insert_start(c, "aa:bb:cc:dd:e1");
c = insert_start(c, "aa:bb:cc:dd:e2");
c = insert_start(c, "aa:bb:cc:dd:e3");
showList(c);
return 0;
}
list createList() {
return NULL;
}
list insert_start(list l1, char val[]) {
list n;
n =(list )malloc(sizeof(list));
strcpy(n->mac,val);
printf("ADDED: %s en ADDRESS:%p NEXT ADDRESS: %p\n", n->mac,(void *)(&n), (void *) (&n->next));
n -> next = l1;
return n;
}
void showList(list l1) {
while (l1 != NULL){
printf("Value: %s Address: %p\n",l1 -> mac,(void *) (&l1 -> next) );
l1 = l1 -> next;
}
}
Any hint on what im doing wrong and why it works with ints and not a char array
thanks
The problem is this allocation:
malloc(sizeof(list))
It shows the problem with making type-aliases of pointers as you here only allocate the size of a pointer and not the whole structure.
Your allocation is wrong, because you made it confusing by typedefing a pointer, don't do that
n = malloc(sizeof(*n));
is less error prone.
Check the return value of malloc() and there is no need for the cast, so
n = malloc(sizeof(*n));
if (n == NULL)
return NULL;
You are printing the n->next pointer's address before initializing it, change this
printf("ADDED: %s en ADDRESS:%p NEXT ADDRESS: %p\n", n->mac,(void *) (&n), (void *) (&n->next));
n->next = l1;
to
n->next = l1;
printf("ADDED: %s en ADDRESS:%p NEXT ADDRESS: %p\n", n->mac, (void *)n, (void *)n->next);
You have no function prototypes, so your compiler is using implicit function declaration, which is bad, because it will assume that all the functions return int, so you need to add these before the definition of main()
list createList();
list insert_start(list l1, char val[]);
void showList(list l1);
specially the first 2 are very important, enable compiler warnings to prevent this.
This is your code fixed:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char mac[25];
struct node * next;
};
typedef struct node *list;
list insert_start(list l1, char val[]);
void showList(list l1);
int main(void) {
lista c;
c = insert_start(NULL, "aa:bb:cc:dd:e1");
c = insert_start(c, "aa:bb:cc:dd:e2");
c = insert_start(c, "aa:bb:cc:dd:e3");
showList(c);
return 0;
}
list insert_start(list l1, char val[]) {
list n;
n = malloc(sizeof(*n));
if (n == NULL)
return NULL;
strcpy(n->mac, val);
n->next = l1;
printf("ADDED: %s en ADDRESS:%p NEXT ADDRESS: %p\n", n->mac, (void *)n, (void *)n->next);
return n;
}
void showList(list l1) {
while (l1 != NULL) {
printf("Value: %s Address: %p\n", l1->mac, (void *)l1->next);
l1 = l1->next;
}
}
and you need a freeList() function too.
typedef struct node *list;
n =(list )malloc(sizeof(list));
list is pointer to struct node, malloc() should be passed the size of valid bytes to perform strcpy and list could be just 8 bytes if you are working on 64 but machine. Change malloc() allocation to size of pointer points to.