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.
Related
#include <stdio.h>
#include <stdlib.h>
struct node {
char *str;
struct node *next;
};
struct node *start = NULL;
struct node *temp = NULL;
struct node *q = NULL;
void sonaEkle(char *veri) {
struct node *eklenecek = (struct node *)malloc(sizeof(struct node));
eklenecek->str = veri;
eklenecek->next = NULL;
if (start == NULL) {
start = eklenecek;
} else {
q = start;
while (q->next != NULL) {
q = q->next;
}
}
}
void yazdir() {
q = start;
while (q->next != NULL) {
printf("%s", q->str);
q = q->next;
}
printf("%s", q->str);
}
int main() {
char *veri;
while (1 == 1) {
printf("enter string");
scanf("%s", veri);
sonaEkle(veri);
yazdir();
}
return 0;
}
I have created a Linked list.
This linked list adds the string it received from the user to the end. But my code is giving a loop error. How can I fix this?
for example: user input:abc bcd cde
output:abc => bcd => cde
This is an infinite loop
while(1 == 1) {
printf("enter string");
scanf("%s",veri);
sonaEkle(veri);
yazdir();
}
Rewrite it in this way
while( puts("enter string") && scanf("%s",veri) == 1 ) {
sonaEkle(veri);
yazdir();
}
And also you need to allocate memory for veri before you can use it in scanf. But you could as well just making it an array.
char veri[SIZE];
There are multiple problems with the code
char *veri;
while(1 == 1){
First statement veri needs memory, since it is a pointer, you need some thing like this veri = malloc(somesize);
Second statement is an infinite loop, you need some termination point, better use something like below to break the infinite loop.
while(1){
// after malloc
scanf("%s",veri);
//enter exit whenever you want to exit from program.
if(strcmp(veri,"exit") == 0)
break;
Function sonaEkle you are allocating memory for struct node* , but you are not returning updated nodes address start
you need to have sonaEkle like this struct node* sonaEkle(char *veri) and return start after every update and no need to cast malloc.
4)
else {
q=start;
while(q->next != NULL) {
q=q->next;
}
The above part just iterates list, you need to add new nodes to q->next when it reaches to NULL and return start afterwards in order to have next elements in the list.
Correct all those problems , to make you program work.
NOTE:
check the pointers for NULL after every malloc
free the malloc'ed memory once you are done with your program.
I am required to have a list of structs of sentence nodes that point to a struct of word nodes. I am trying to print the user's input.
I have a program that runs properly when I manually give it the input (see test section of the code). It does not, however, work when I use my input1() function.
I've tried debugging it, but I can't seem to find the problem.
I removed all printf lines that I used to debug. I also removed all the irrelevant code.
I am looking to know how to fix it and what is wrong so I can run it with no problems.
What I learned from debugging it is that (only when using input1() and not in the test) the head is overwritten every time and all the nodes as well.
I also tried using a double pointer instead of returning para but that didn't help.
any help will be appreciated,
thanks in advance
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct word
{
char * ch;//poiter to char
}
W;
typedef struct sentence
{
W * currentWord;//pointer to a word
int lineNumber;// holds the line number
int numbersOfWords;//holds the number of words
struct sentence* link;
}
sent;
typedef struct list
{
sent* head;
int count;
}
LISTS;
LISTS* createList()
{
LISTS* list;
list= (LISTS*) malloc (sizeof (LISTS));
if (list)
{
list-> head = NULL;
list-> count = 0;
}
return list;
} // createList
void printList(LISTS* list)
{
sent *temp = list -> head;
//iterate the entire linked list and print the data
while(temp != NULL)
{
printf("%s\n", temp->currentWord->ch);
temp = temp->link;
}
// printf("NULL\n");
}
void insertSentList (LISTS* list, W* itemPtr)
{
sent* newPtr; //new node
if (!(newPtr = (sent * ) malloc(sizeof(sent)))){
printf(" Memory can not be allocated.");
return;
}
newPtr->currentWord = itemPtr;
newPtr->link = NULL;
if(list->head == NULL)
{
list->head = newPtr;
}else{
sent* current = list->head;
while(current->link != NULL){
current = current->link;
}
current -> link = newPtr;
}
(list->count)++;
return;
} // insertList
LISTS * input1(LISTS *para)
{
char * line;
line = (char * ) malloc(1000 * sizeof(char));
line[0] = '\0';
while (line[0] != '\n')
{
W word;
word.ch = (char * ) malloc(100);
printf(" Please input a line : ");
fgets(line, 1000, stdin);
if(line[0] != '\n'){
strcpy(word.ch, line);
insertSentList(para,&word);
}
}
free(line);
return para;
}
int main()
{
///////////////////test////////////////
LISTS* list = createList();
W word;
word.ch= "word0 ";
W word1;
word1.ch= "word1 ";
W word2;
word2.ch= "word2";
insertSentList(list,&word);
insertSentList(list,&word1);
insertSentList(list,&word2);
insertSentList(list,&word);
insertSentList(list,&word1);
insertSentList(list,&word2);
printList(list);
///////////////////test////////////////
LISTS *para = createList();
para= input1(para);
printList(para);
return 0;
}
Main problem with the posted code is that "ownership" of the sent and W objects in a list is not well defined. For example word.ch= "word0 "; in main sets the ch pointer pointing to a string literal (which it does not own), but word.ch = malloc(100); in input1 points it to dynamically allocated memory (which it should own, and remember to free later). Because of this, memory allocations cannot be tracked reliably and, even in the cases where things appear to "work", there are multiple memory leaks. It also breaks when the inserted objects are local variables that do not live for the entire lifetime of the list object.
The simplest (if not necessarily the best or most efficient) solution would be to dynamically allocate all objects that go into the list, make the list own them all, and add a function to cleanup once done. To that end insertSentList could be modified as follows.
void insertSentList (LISTS* list, W* itemPtr)
{
sent* newPtr; //new node
if (!(newPtr = malloc(sizeof(sent)))){
printf(" Memory can not be allocated.\n");
return;
}
W *newItem = malloc(sizeof(W)); // <-- make a deep copy of the `itemPtr` argument
newItem->ch = strdup(itemPtr->ch); // including a copy of the string itself
newPtr->currentWord = newItem; // <-- save the copy in the list, not the argument
newPtr->link = NULL;
if(list->head == NULL)
{
list->head = newPtr;
}else{
sent* current = list->head;
while(current->link != NULL){
current = current->link;
}
current->link = newPtr;
}
list->count++;
} // insertList
For proper cleanup and to avoid memory leaks, the following freeList should be called for each list pointer returned by createList and filled by insertSentList.
void freeList(LISTS *list)
{
sent *temp = list->head;
while(temp != NULL)
{
sent *next = temp->link;
free(temp->currentWord->ch);
free(temp->currentWord);
free(temp);
temp = next;
}
free(list);
}
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.
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;
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.