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);
}
Related
I am trying to implement a stack-esque structure using a linked list in C. Eventually it will read strings of varying length from an input file, thus the need for dynamic memory. I am getting a segmentation fault at the printf in printList and I cannot figure out why. I was also getting segmentation faults in push earlier, but I seem to have fixed them. In case it's not obvious, my intent is to add elements only to the "top" of the list.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void* emalloc(size_t n);
typedef struct node {
struct node* next;
char* word;
} node;
node* head = NULL;
void* emalloc(size_t n) {
void* p;
p = malloc(n);
if(p == NULL) {
fprintf(stderr, "Failed to allocate memory.");
exit(1);
}
return p;
}
void push(char* w) {
if(head == NULL) {
head = (node*) emalloc(sizeof(node));
head->word = (char*) emalloc(strlen(w) * sizeof(char) + 1);
strncpy(head->word, w, strlen(w) + 1);
printf("Pushed a word to head.");
return;
}
node* newnode = (node*) emalloc(sizeof(node));
newnode->word = (char*) emalloc(strlen(w) * sizeof(char) + 1);
strncpy(newnode->word, w, strlen(w) + 1);
newnode->next = head;
head = newnode;
}
void printList() {
node* cur = head;
if(cur == NULL || cur->word == NULL) printf("Whoops!");
while(cur != NULL) {
printf(cur->word);
cur = cur->next;
}
}
/*
* The encode() function may remain unchanged for A#4.
*/
void main() {
char word[20] = "Hello world";
//push("Hello",head);
//push("World",head);
//push("!",head);
push(word);
printList();
}
Why copy to 1 past end of string in push()? Also, if string is too long, strncpy won't NUL it for you.
The real crash though is in the "Head" creation, the first if statement when no entries exist. It does not NULL its next pointer so therefore list traversal will will blow up on last entry as it reads a garbage pointer at the end of the list.
it worked for me, as michael Dorgan ask why did you 1 byte past the end of the string.
I recomend to use something like :
int len =strlen(w)
before
node* newnode = (node*) emalloc(sizeof(node));
newnode->word = (char*) emalloc(len * sizeof(char));
strncpy(newnode->word, w, len)[len]=0;
newnode->next = head;
this temporal variable eliminate the need of use strlen on these locations.
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.
I'm trying to insert into my BST but I'm struggling with creating a loop out of it.
The code works when I insert one by one, but when I try to put it into a loop it doesn't insert correctly.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h> // for strcmp()
#include <ctype.h> // for toupper()
typedef struct BstNode{
//char name[20];
// int data;
struct BstNode* left;
struct BstNode* right;
char* name;
}BstNode;
typedef int (*Compare)(const char*, const char*); // makes comparisons easier
/* Returns pointer address to newly created node */
BstNode* createNode(char* name){
BstNode* newNode = (BstNode*)malloc(sizeof(BstNode)); // Allocates memory for the newNode
newNode->name = name; // newNode->data is like newNode.data
newNode->left= NULL;
newNode->right = NULL;
return newNode;
}
//insert node into Tree recursively
BstNode* insertNode(BstNode* node, char* name, Compare cmp){
int i;
/* char *s1 = node->name;
char *s2 = name;
printf("s1: %s, s2: %s\n", s1,s2);
i = strcmp(s1, s2); // if =1, s1 is greater
printf("i: %d\n", i); */
if(node == NULL){// if tree is empty
// printf("inside NULL\n");
node = createNode(name);
//return node;
}
else{
i = cmp (name, node->name); // sweet
if(i == -1){
// printf("inside left\n");
node->left = insertNode(node->left, name, cmp);
//return node;
}
else if(i == 1){
// printf("inside right\n");
node->right = insertNode(node->right, name, cmp);
//return node;
}
else if(i == 0 ){ //avoid duplicates for now
// printf("inside 0\n");
printf("Name is in BST\n");
return NULL;
}
}
return node;
}
BstNode* printTree(BstNode* node){
if(node == NULL){
return NULL;
}
printTree(node->left);
printf("%s\n",node->name);
printTree(node->right);
}
int CmpStr(const char* a, const char* b){
return (strcmp (a, b)); // string comparison instead of pointer comparison
}
//void Insert(Person *root, char name[20]);
int main(){
BstNode* root = NULL; // pointer to the root of the tree
char buf[100];
char option = 'a';
while(1) {
printf("Enter employee name");
scanf("%s",buf);
printf ("Inserting %s\n", buf);
root = insertNode(root, buf, (Compare)CmpStr);
printTree(root);
}
}
I can do root = insertNode(root, name, (Compare)CmpStr)
several times in code, but if I try to loop it with user input it won't insert correctly. I'm not sure if it has to do with the fact that I'm using scanf() or root not being set correctly. I've tried using fgets() as well but I'm not too sure how to use it and keep messing that up.
Any help is appreciated.
In your loop, you always pass the same buffer to your insert function; Your createNode does not copy the content of the buffer but rather stores a reference to the (always) same buffer; Hence, changing the buffer content after insert will also change the "content" of previously inserted nodes.
I'd suggest to replace newNode->name = name in createNode with newNode->name = strdup(name). This will actually copy the passed "contents" and gives your BST control over the memory to be kept. Thereby don't forget to free this memory when deleting nodes later on.
I'm a beginner in developing, so my sensei gave me a task to complete in which I need to enter a couple of strings in linked lists and after I enter print, they need to be printed in the correct order, from the first to last.
Here is what I got:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node {
char data;
struct Node *next;
}node;
char createlist(node *pointer, char data[100]) {
while (pointer->next != NULL) {
pointer = pointer->next;
}
pointer->next = (node*) malloc(sizeof(node));
pointer = pointer-> next;
pointer->data = *data;
pointer->next = NULL;
}
int main() {
node *first, *temp;
first = (node*) malloc(sizeof(node));
temp = first;
temp->next = NULL;
printf("Enter the lines\n");
while (1) {
char data[100];
gets(data);
createlist(first, data);
if (strcmp(data, "print") == 0)
printf("%s\n", first->data);
else if (strcmp(data, "quit") == 0)
return (0);
};
}
When I run it I get:
Enter the lines:
asdfasdf
print
(null)
Any help would be appreciated since this is my first time using linked lists.
You should format your code properly.
first->data is allocated via malloc() and isn't initialized, so using its value invokes undefined behavior.
In order not to deal the first element specially, you should use pointer to pointer to have createlist() modify first.
Since createlist() won't return anything, type of its return value should be void.
I guess you wanted to copy the strings instead of assigning the first character of each strings.
To print all of what you entered, code to do so have to be written.
You shouldn't use gets(), which has unavoidable risk of buffer overrun.
You should free() whatever you allocated via malloc().
improved code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node
{
char *data;
struct Node *next;
} node;
void createlist(node **pointer, char data[100])
{
while (*pointer != NULL)
{
pointer = &(*pointer)->next;
}
*pointer = malloc(sizeof(node));
if (*pointer == NULL)
{
perror("malloc 1");
exit(1);
}
(*pointer)->data = malloc(strlen(data) + 1);
if ((*pointer)->data == NULL)
{
perror("malloc 2");
exit(1);
}
strcpy((*pointer)->data, data);
(*pointer)->next = NULL;
}
int main(void)
{
node *first = NULL;
printf("Enter the lines\n");
while (1)
{
char data[100], *lf;
if (fgets(data, sizeof(data), stdin) == NULL) strcpy(data, "quit");
if ((lf = strchr(data, '\n')) != NULL) *lf = '\0'; /* remove newline character */
createlist(&first, data);
if (strcmp(data, "print") == 0)
{
node *elem = first;
while (elem != NULL)
{
printf("%s\n", elem -> data);
elem = elem->next;
}
}
else if (strcmp(data, "quit") == 0)
{
while (first != NULL)
{
node *next = first->next;
free(first->data);
free(first);
first = next;
}
return(0);
}
}
}
Inside createlist(), you are iterating to the end of the list. There, you are adding a new node and setting a new text entered. By doing so, you are missing that you have already a first node. Because you are iterating to the end in every call of createlist(), you are jumping over your first node every time, so it remains without text and delivers NULL.
In order not to jump over the first initial node, you could alter createlist() like this:
char createlist(node *pointer, char data[100])
{
while (pointer->data != NULL && pointer->next != NULL)
{
pointer = pointer->next;
}
...
...
}
Or you could create the first node not initially, but only after the first line of text was entered.
edit: Here are two additional style hints:
What happens if somebody enters 120 characters? The text will outrun your char[100] array and will fill RAM that is used otherwise. This is a buffer overflow. You could try to grab only the first 100 chars, get the substring. Alternatively, use the length argument of fgets()
Create a constant for 100, like #define MAX_BUFFER_LENGTH 100, and use it every time.
I'm trying to traverse a tree using the parent, in backwards. using the following code
FIXED CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node { struct node *parent; char *name; };
char *buildPath(node* node)
{
struct node *temp = node;
int length =0;
do{
length+=strlen(temp->name);
temp = temp->parent;
length++; // for a slash
} while(temp !=NULL);
char * buffer = malloc(length+1);
buffer[0] = '\0';
do {
char *name = strdup(node->name);
strrev(name);
strcat(buffer,name);
node = node->parent;
if(node!=NULL)
{
strcat(buffer,"/");
}
free(name);
} while (node != NULL);
strrev(buffer);
return buffer;
}
int main(void)
{
struct node node1 = { NULL, "root" };
struct node node2 = { &node1, "child" };
struct node node3 = { &node2, "grandchild" };
char * result = buildPath(&node3);
printf(result);
return EXIT_SUCCESS;
}
The problem now
I get a crash at free(name);
If I remove it, I get a buffer like "root/child/grandchildþ««««««««ýýýýÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ"with strange symbols
I don't know why it gets a segementation fault while trying to free(name) and to get a correct results, but with weird letters at the end.
I get the following image,
You need space in buffer for a string-terminating zero; malloc(length + 1).
(Never cast the result of malloc.)
You need space in buffer for the path separators.
Add them up as you compute length.
strcat expects a zero-terminated parameter to concatenate to; do buffer[0] = '\0'; first.