Im trying to write a program that reads each word inputted by user and then sticks that word into a linked list. This is what I have tried so far but got seg faults but not too sure where I went wrong with mallocing/pointers. (Havent implemented printList yet).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 20
typedef struct node{
char *word;
struct node *next;
}node_t;
node_t *read(node_t *node);
void printList(node_t *node);
node_t *insertNode(char *word, node_t *node, int size);
int main(int argc, char *argv[]) {
node_t *start = NULL;
printf("Enter a sentence:\n");
read(start);
return 0;
}
void *read(node_t *node){
int i, size = MAX_LEN;
char c, *word;
if(!(word=malloc(size))){
printf("Out of memory!\n");
exit(EXIT_FAILURE);
}
while((c=getchar())!='\n'){
for(i=0;c!=' ';i++){
word[i]=c;
if(i>size){
size=size*2;
if(!realloc(word, size)){
printf("Out of memory\n");
exit(EXIT_FAILURE);
}
}
}
node = insertNode(word,node,size);
}
return node;
}
node_t *insertNode(char *word, node_t *node, int size){
node_t *new_node, *current;
new_node = (node_t*)malloc(sizeof(node_t));
new_node->next = NULL;
if(!(new_node->word = malloc(size))){
printf("Out of memory\n");
exit(EXIT_FAILURE);
}
strcpy(new_node->word,word);
if (node == NULL){
node = new_node;
current = new_node;
}
else{
current->next = new_node;
current = new_node;
}
return node;
}
There are several issues:
Your prototype and the implementation of read don't match; make both return a node_t *.
You have two nested loops for input, one reading from stdinand another one cycling through the characters. The inner loop never updated its condition, because c can only be changed by the outer loop. There should be just one loop, which takes care of reading from the stream and writing to the string.
You don't keep tzhe result of realloc, which means that you don't reflect updates when the handle to the allocated memory changes. In these cases, you will access the old handle, which has become invalid.
You don't terminate your string with a null character.
You should reallocate before you access memory out of bounds. That usually means to check whether to enlarge the array before writing to it. Note that for an array of length n, n itself is already an illegal index.
The result of getchar should be an int, ot a char so that all valid input is distinct from EOF, for which you don't check.
Therer are probably more issues, the ones listed are the ones concerned with read. I haven't looked into the linked list insertion.
In order to properly terminate the string with a zero, I recommend to write an infinite loop and postpone the break condition after possible reallocation. Foe example:
node_t *read(node_t *node)
{
int size = MAX_LEN;
int i = 0;
char *word = malloc(size);
if(word == NULL) {
printf("Out of memory!\n");
exit(EXIT_FAILURE);
}
while (1) {
int c = getchar();
if(i >= size) {
size = size*2;
word = realloc(word, size);
if (word == NULL) {
printf("Out of memory\n");
exit(EXIT_FAILURE);
}
}
if (c == '\n' || c == EOF) {
word[i] = '\0';
break;
}
word[i++] = c;
}
node = insertNode(word, node, size);
return node;
}
I think the error is caused by the line
return node;
in insertNode. That should be
return new_node;
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 am building a program for a project. One of the requirements for the project is a function that selects a random node from my linked list of 3000 words.
I tried to do this by creating a function that generates a random number from 0 to 2999. After this, I created another function that follows a for loop starting from the head and moving to the next node (random number) times.
My random number generator is working fine, but my chooseRand() function is not.
Please help, the random number generator and the chooseRand() function are the last two functions above main. Also, my code is a bit messy, sorry.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int nodeNum;
int chances;
char* secret;
/*Node of linked list*/
typedef struct node {
char *data;
struct node *next;
} node;
node *start = NULL;
node *current;
/*Void function to print list*/
void printList(struct node *node)
{
while (node != NULL) {
printf("%s ", node->data);
node = node->next;
}
}
/*Appending nodes to linked list*/
void add(char *line) {
node *temp = 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;
}
}
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);
}
node *listSearch(node* start, char *nodeSearched){
node *p;
for (p = start; p != NULL; p = p->next)
if (strcmp(p->data, nodeSearched) == 0)
printf("%s", p->data);
return NULL;
}
node *letterSearch(node* start, int i){
node *p;
for (p = start; p != NULL; p = p->next)
if (strlen(p->data) == i)
{
printf("\n %s", p->data);
free(p);
p = NULL;
}
return NULL;
}
void chooseRand(struct node* start)
{
node* p;
int n;
p = start;
for(n = 0; n != nodeNum; n++)
{
p = p->next;
}
printf("%s", p->data);
}
void randNum(int lower, int upper)
{
srand(time(0));
nodeNum = (rand() % (upper - lower + 1)) + lower;
}
int main(){
randNum(0, 2999);
chooseRand(start);
return 0;
}
As others has said, the problem is that you don't have initialized the linked list yet, because of what your are getting a segmentation fault. So, in addition to initializing the list first, you must also introduce checks in the implementation of the chooseRand function, to check that if you reach the end of the list, without reaching the desired index, you stop executing the foor loop, otherwise you will be potentially exposed to segmentation faults.
Improve chooseRand implementation, to prevent segmentation fault either, when the linked list is empty, or when the randomly generated nodeNum is grater than the the index of the list's last item:
void chooseRand(struct node* start)
{
node* p;
int n;
p = start;
if(p == NULL){
printf("The list is empty!");
return;
}
// Also, we must stop the iteration, if we are going to pass the end of the list, you don't want a segmentation fault because trying to access a NULL pointer:
for(n = 0; n != nodeNum && p->next != NULL; n++)
{
p = p->next;
}
// If p == NULL, the list was not big enough to grab an item in the `nodeNum` index:
printf("%s", (n != nodeNum) ? "Not found!" : p->data);
}
Initialize the linked list, with the content of some file on disk:
int main(){
randNum(0, 2999);
// Fill the linked list with the content of a file in disk, calling your method:
char fileName[] = "PutYourFileNameHere.txt";
readfile(fileName);
chooseRand(start);
return 0;
}
There is another fix that you must do, and it is free the memory being hold by the pointer field data of your structure, in the implementation of your method letterSearch. Inside the if statement, you're de-allocating the memory hold by the p pointer, but you aren't de-allocating the memory assigned to the pointer p->data, this will cause a memory leak. When you in the function add, initialized p->data with the result of the call to the function strdup(line), what this function does is allocate enough memory in the heap, copies to it the buffer pointed by the line argument, and give to you back a pointer to the new allocated memory, that you're storing in the p.data field; a pointer that you should free when you're done with it, otherwise your program will have potential memory leaks. So I will modify your function letterSearch as folollows:
node *letterSearch(node* start, int i){
node *p;
for (p = start; p != NULL; p = p->next)
if (strlen(p->data) == i)
{
printf("\n %s", p->data);
// Free p->data before free p:
free(p->data);
free(p);
p = NULL;
}
return NULL;
}
References:
strdup
I am having some issues with dynamically allocating a string for a node in a tree. I have included my node structure below for reference.
struct node
{
char *string;
struct node *left;
struct node *right;
};
typedef struct node node;
I am supposed to read words from a text file and then store those words into a tree. I am able to store char arrays that have been defined, such as char string[20] without problems, but not strings that are supposed to be dynamically allocated.
I am only going to post the code I am using to read my file and try to create the dynamically allocated array. I have already created the file pointer and checked that it is not NULL. Every time I try to run the program, it simply crashes, do I need to try and read the words character by character?
//IN MAIN
node *p, *root ;
int i;
int u;
root = NULL;
char input[100];
while(fscanf(fp, "%s", &input) != EOF)
{
//Create the node to insert into the tree
p = (node *)malloc(sizeof(node));
p->left = p->right = NULL;
int p = strlen(input); //get the length of the read string
char *temp = (char*) malloc(sizeof(char)*p);
//malloc a dynamic string of only the length needed
strcpy(local, input);
strcpy(p->word,local);
insert(&root, p);
}
To be completely clear, I only want advice regarding the logic of my code, and only would like someone to help point me in the right direction.
You are invoking many undefined behaviors by
passing pointer to object having wrong type to scanf(). i.e. In fscanf(ifp, "%s", &input), char(*)[100] is passed where char* is expected
accessing out-of-range of allocated buffer when storeing terminating null-character in strcpy(local, input);
using value of buffer allocated via malloc() and not initialized in strcpy(curr->word,local);
Your code should be like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct node_t {
struct node_t* left, *right;
int count;
char* word;
} node;
void insert(node ** tree, node * item);
int main(void) {
FILE* ifp = stdin;
node * curr, * root;
int i;
int u;
root = NULL;
char input[100];
/* you should specify the maximum length to read in order to avoid buffer overrun */
while(fscanf(ifp, "%99s", input) != EOF)
{
//Create the node to insert into the tree
curr = malloc(sizeof(node));
if(curr == NULL) /* add error check */
{
perror("malloc 1");
return 1;
}
curr->left = curr->right = NULL;
curr->count = 1;
int p = strlen(input); //get the length of the read string
char *local = malloc(sizeof(char)*(p + 1)); /* make room for terminating null-character */
if (local == NULL) /* add error check again */
{
perror("malloc 2");
return 1;
}
//malloc a dynamic string of only the length needed
//To lowercase, so Job and job is considered the same word
/* using strlen() in loop condition is not a good idea.
* you have already calculated it, so use it. */
for(u = 0; u < p; u++)
{
/* cast to unsigned char in order to avoid undefined behavior
* for passing out-of-range value */
input[u] = tolower((unsigned char)input[u]);
}
strcpy(local, input);
curr->word = local; /* do not use strcpy, just assign */
insert(&root, curr);
}
/* code to free what is allocated will be here */
return 0;
}
//Separate insert function
void insert(node ** tree, node * item)
{
if(!(*tree))
{
*tree = item;
return;
}
if(strcmp(item->word,(*tree)->word) < 0)
insert(&(*tree)->left, item);
else if(strcmp(item->word,(*tree)->word) > 0)
insert(&(*tree)->right, item);
/* note: memory leak may occur if the word read is same as what is previously read */
}
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 coded a simple source. It contains a queue and some of the function a queue needs but for some reason malloc() only works once.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define QUEUE sizeof(Queue)
Definition of the Node, which is an element of the list, and the queue.
typedef struct node {
char * value;
struct node * next;
} Node;
typedef struct queue {
Node * head;
Node * tail;
} Queue;
int initialization(void ** list, int type){
int code = -1;
//create an empty list.
//if queue dynamically allocate memory and assign NULL to both properties head and tail.
return code;
}
enqueue() add one element in the queue at a time. but for some reason it can only add one element then the program crashes.
int enqueue(Queue * q, char * instruction){
int code = -1;
if(q != NULL){
printf("Prepare to enqueue!\n");
Node * n = NULL;
n = (Node*)malloc(sizeof(Node));
if(n != NULL){
printf("Node created!\n");
strcpy(n->value, instruction);
n->next = NULL;
//if first value
if(q->head == NULL){
q->head = n;
q->tail = n;
printf("Enqueue first Node\n");
}
else {
q->tail->next = n;
q->tail = n;
printf("Enqueue another Node\n");
}
code = 0;
printf("Node \"%s\" Enqueued\n", instruction);
}
}
return code;
}
int dequeue(Queue * q){
int code = -1;
//dequeuing code here.
return code;
}
int isEmpty(void * list, int type){
int code = 0;
//check if the list is empty
return code;
}
the for loop in the main() function never reaches 3
int main(int argc, char * argv[]){
Queue * queue = NULL;
initialization((void*)&queue, QUEUE);
int i = 0;
for(i = 0; i < 3; i++){
if(enqueue(queue, "some value") != 0){
printf("couldn't add more Node\n");
break;
}
}
while(!isEmpty(queue, QUEUE)){
dequeue(queue);
}
return 0;
}
The initialization function is written this way because it should also be able to initialize stacks (I removed the stack code to reduce the source but even without it the bug persist). I also put printfs to debug the code. And I have more than enough memory to make this simple code run how it should.
Thanks in Advance!
Running this, I crash with a segmentation fault, as I'd expect:
n = (Node*)malloc(sizeof(Node));
n is allocated, it's contents uninitialized and effectively random
if(n != NULL){
n is not NULL, so...
strcpy(n->value, instruction);
And we crash.
See the problem? n->value is a pointer to nowhere. Or, to somewhere, but nowhere known. Nowhere good. And we're just dumping a string into that space.
Either change the Node struct so that value is a char [SOME_SIZE], or use strdup() instead of strcpy(), to actually allocate some memory for the poor thing.
n->value = strdup(instruction);