Linked list doesn't work as expected - c

I implemented this code to add an item to the list (it must be a string) and remove a specific string. However it has two problems: FIRST, the order is wrong after insert the nodes to the list. SECOND, after removing a node, it remains a "blank" space, see below when I remove the Third node.
Initial list:
First
Fourth
Third
Second
After list_remove():
First
Fourth
Second
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct myStruct {
char str[20];
struct myStruct * pNext;
};
struct myStruct *list_create(const char *str)
{
struct myStruct *node;
if(!(node=malloc(sizeof(struct myStruct))))
return NULL;
strcpy(node->str, str);
node->pNext = NULL;
return node;
}
int add_to(struct myStruct * list, const char *str)
{
struct myStruct *newnode;
newnode = list_create(str);
newnode->pNext = list->pNext;
list->pNext = newnode;
return 1;
}
char * remove_to(struct myStruct * list, const char *str)
{
while(list->pNext && (strcmp(list->str, str)))
list = list->pNext;
free(list);
return 0;
}
int list_foreach(struct myStruct *node, int(*func)(void*))
{
while(node) {
if(func(node->str)!=0) return -1;
node=node->pNext;
}
return 0;
}
int printstring(void *s)
{
printf("%s\n", (char *)s);
return 0;
}
int main(void)
{
struct myStruct *list;
// Create initial elements of list
list = list_create("First");
add_to(list, "Second");
add_to(list, "Third");
add_to(list, "Fourth");
printf("Initial list:\n");
list_foreach(list, printstring);
putchar('\n');
remove_to(list, "Third");
printf("After list_remove():\n");
list_foreach(list, printstring);
putchar('\n');
return 0;
}

I think I see a few problems:
add_to() always operates on the current list's first item. So every time you add, the new node will be inserted between the first and second (if there is a second).
And the method remove_to does not check if a matching string was actually found. After exhausting the while loop, if not match was found, I think you will free the last item.
C++ has a whole suite of "Collections" and a built in linked list is one of them. Unless this is a homework exercise where you have to implement your own, consider using that.

Related

C/ why the List change

#include <stdio.h>
#include <string.h>
//struct definition
typedef struct ListElement
{
char *value;
struct ListElement *next;
}ListElement, *List;
List push_back_list(List li, char *x);
int main(int argc, char **argv)
{
char val[]= "12345678987456321069";
char dest[5];
//here the list is empty
List liste=new_list();
strncpy(dest, val, 4);
//push method
liste=push_back_list(liste,dest);
//modification of dest
strncpy(dest, val+4, 4);
//when i print list, the result were change without push method why??
print_list(liste);
return 0;
}
//push method description
List push_back_list(List li, char *x)
{
ListElement *element;
element = malloc(sizeof(*element));
element->value= x;
element->next = NULL
if(is_empty_list(li))
return element;
ListElement *temp;
temp = li;
while(temp->next != NULL)
temp = temp->next;
temp->next = element;
return li;
}
The list element doesn't store a copy of the string, it just stores a pointer to dest. When you change the contents of dest, that change is of course seen when you print it through the list element; it's the same buffer.
The fix is to create a copy in the list element, for instance by changing this:
element->value = x;
to:
element->value = strdup(x);
If you have strdup() (it's not standard, but common). Of course this opens you up to allocation failure. You can also make the list element contain a proper buffer, but that limits the size of the string you can support. Choices, choices. :)

Memory error when trying to implement my own list

I'm trying to implement my own linked-list like structure in C, however I'm failing even with easiest part of just adding new elements to the list. Adding one element to the list and printing it works fine, adding another and printing the one doesn't. After executing it the console simply outputs "memory error" - that's it. I'm pretty sure I've messed up with the iteration of the current-pointer in my insert_list function, but I can't find where.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 80
typedef struct list
{
struct list *next;
char value[MAXLEN];
} list;
void insert_list(list *lis, const char string[MAXLEN])
{
list *current = lis;
while(current->next)
{
current++;
}
current->next = malloc(sizeof(lis));
strcpy(current->next->value, string);
}
int main(void)
{
list lis =
{
NULL,
"Hello1"
};
insert_list(&lis, "Hello2");
insert_list(&lis, "Hello3");
/* This still works */
printf("%s %s", lis.value, lis.next->value);
/* This doesn't */
printf("%s", lis.next->next->value);
return 0;
}
current->next->next is never initialized in insert_list, so the second time you call insert_list it will probably iterate forever until a memory error.
void insert_list(list *lis, const char string[MAXLEN])
{
list *current = lis;
while(current->next)
{
current++;
}
current->next = malloc(sizeof(lis));
current->next->next = NULL;
strcpy(current->next->value, string);
}
Edit
Actually there are lots of other errors, not just the init:
advancing the list, should probably be current = current->next, not current++
malloc should be sizeof list not lis, first is the entry in a list size, but sizeof(lis) will be the size of a pointer on your machine
const char string[MAXLEN] as an argument does not mean what you think it means ;-) See Difference between passing array and array pointer into function in C

Why am I not able to display strings with the following code?

If I put an "&" in the printf, it will at-least print the names of the countries and it will crash. Otherwise, it crashes immediately. My guess is, there is something wrong with the for loop. Let me know, if I am wrong.
//Implementation file//
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct list
{
char *item;
int length;
};
typedef struct list LIST; //aliasing the structure//
LIST *create() //constrcutor//
{
LIST *L = (LIST*)malloc(sizeof (LIST));
L->length=0;
return L;
}
void insert(LIST* L, char *newitem)
{
L->item=(char*)malloc(sizeof(char));
strcpy(L->item, newitem);
(L->length)++;
}
void display(LIST *L)
{
int i;
for(i=0;i<(L->length);i++)
{
printf("Elements are: %s\n", L->item[i]);
}
}
int main ()
{
LIST *L;
L=create();
insert(L, "America");
insert(L, "Brazil");
display(L);
free(L->item);
free(L);
return 0;
}
L->item=(char*)malloc(sizeof(char));
strcpy(L->item, newitem);
You are allocating only one byte, but you try to copy a whole string into L->item, resulting in undefined behaviour. This should be:
L->item=malloc(sizeof(char)*(strlen(newitem)+1));
strcpy(L->item, newitem);
You are also calling the function insert twice, which will allocate new memory for L->item and loose the pointer to the previous allocated space -> Memory leak. You should add list elements instead of overwriting the first one all the time, see #DavidKernin's answer.
There's a gigantic error in your code: when inserting new elements you're supposed to create a new list element and initialize it..
With the function
void insert(LIST* L, char *newitem)
{
L->item=(char*)malloc(sizeof(char));
strcpy(L->item, newitem);
(L->length)++;
}
called like this:
insert(L, "America");
insert(L, "Brazil");
you're always writing the same element for length and allocating new memory (without even using/storing a pointer to the old allocated one.. which is lost!).
You should rather do something like:
//Implementation file//
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct list
{
char *item;
struct list* next;
};
typedef struct list LIST; //aliasing the structure//
LIST *create() //constrcutor//
{
LIST *L = (LIST*)malloc(sizeof (LIST));
L->next = 0;
return L;
}
LIST* insert(LIST* L, char *newitem)
{
L->item=(char*)malloc(sizeof(char)*strlen(newitem));
strcpy(L->item, newitem);
LIST *newL = (LIST*)malloc(sizeof (LIST));
newL->next = 0;
L->next = newL;
return newL;
}
void display(LIST *L)
{
int i;
for(i=0; L->next != 0;L = L->next) // Assumes there's at least 1 item
{
printf("Elements are: %s\n", L->item);
}
}
int main ()
{
LIST *startElement;
startElement=create();
LIST *lastElement = insert(startElement, "America");
lastElement = insert(lastElement, "Brazil");
display(startElement);
// Free all memory.. exercise :)
return 0;
}
Try it out interactively: http://ideone.com/n8tRtv
Otherwise the purpose of linked lists would be entirely defeated.. who wants a list which loses the previous elements when you insert new ones?
Notice that the above code
Doesn't free memory
Always assumes there's at least an item in the list
If you want a complete code, well.. fix it. If you understand how it works it should be rather feasible to fix it entirely. Good luck!
The following modification of your code will allow you to insert strings and print them. Since that is what you asked for, that is what you shall get. If you had some sort of specific data structure in mind (perhaps a linked list etc.) when coding this up, please specify.
struct list
{
char **item;
int length;
};
struct list now holds an array of pointers to char *.
LIST *create()
{
LIST *L = (LIST*)malloc(sizeof (LIST));
L->item = (char **)malloc(sizeof(char *));
L->length=0;
return L;
}
This would be the proper way to malloc for your list.
void insert(LIST* L, char *newitem)
{
L->item[L->length] = (char *)malloc(sizeof(char *));
strcpy(L->item[L->length++], newitem);
}
To insert you malloc for a new char pointer, which is placed in the end of your array of char pointers. The inserted string is copied and length is incremented.
And don't forget to free()!
L->item=(char*)malloc(sizeof(char));
is one problem in the code
The specifier in the printf statement is incorrect. You are using %s which expects a char* but you are passing a char. As a result the printf implementation is treating the character value as an address and promptly running off into invalid memory and crashing
To fix this you need to switch to using %c
printf("Elements are: %c\n", L->item[i]);
Note that this will cause every char to be printed out on a different line. Most likely you want something like the following
printf("Elements are: %s\n", L->item[i]);
int i;
for(i=0;i<(L->length);i++)
{
printf("%c", L->item[i]);
}
printf("\n");
Note that if your intent is to have the item member be a null terminated char* then the simplest fix is to do the following
printf("Elements are: %s\n", L->item);

Why aren't the elements of my Doubly Linked List displayed properly?

The following program receives input strings of the form ins "name_to_insert" birthdate and should insert this information in a doubly linked list. The contents of the list are displayed after each insertion, along with the number of elements. The number of elements is being displayed correctly, but instead of the names and birth dates, 2686707 is being displayed n times (n=number of elements in the list).
I suspect something is wrong with my print function, printList(), but I couldn't figure out what.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DLList.h"
typedef struct dataStructure
{
int birthday;
char *name;
} dataStructure;
int main()
{
ListT *l=createList();
char op[4], nameTemp[30], *name, s[50];
int date;
while (scanf("%[^\n]%*c", s)==1)
{
sscanf(s, "%s", op);
if (strcmp(op, "ins")==0)
{
sscanf(s, "%*s %[^0-9]%d", nameTemp, &date);
name=nameTemp+1; // Remove opening quotation mark
name[strlen(name)-2]='\0'; // Remove closing quotation mark
NodeT *p=createNode();
p->data=(dataStructure*)malloc(sizeof(dataStructure));
((dataStructure*)p->data)->birthday=date;
((dataStructure*)p->data)->name=name;
insertLastNode(l, p);
printf("List length: %d\n", l->length);
printList(l);
}
}
return 0;
}
void printList(ListT *l)
{
NodeT *p=l->first;
while (p)
{
printf("%d %s\n", (((dataStructure*)p->data)->birthday, (dataStructure*)p->data)->name);
p=p->next;
}
printf("--\n");
}
Contents of DLList.h:
#include <stdio.h>
#include <stdlib.h>
typedef struct nodetype
{
struct nodetype *prev, *next;
void *data;
} NodeT;
typedef struct
{
int length;
NodeT *first, *last;
} ListT;
NodeT *createNode();
ListT *createList();
void insertLastNode(ListT *l, NodeT *p);
Contents of DLList.c:
#include "DLList.h"
NodeT *createNode()
{
NodeT *p=(NodeT*)malloc(sizeof(NodeT));
p->next=p->prev=NULL;
return p;
}
ListT *createList()
{
ListT *l=(ListT*)malloc(sizeof(ListT));
l->first=l->last=NULL;
l->length=0;
return l;
}
void insertLastNode(ListT *l, NodeT *p)
{
if (l->first==NULL)
{
l->first=l->last=p;
p->prev=p->next=NULL;
l->length++;
}
else
{
p->prev=l->last;
p->next=NULL;
l->last->next=p;
l->last=p;
l->length++;
}
}
Two errors in the code.
First:
Instead of
((dataStructure*)p->data)->name=name;
do
((dataStructure*)p->data)->name = (char*)malloc(strlen(name)+1);
strcpy(((dataStructure*)p->data)->name, name);
to avoid memory leakage.
Second
In printList function there was a mistake with parentheses. Do as below:
printf("%d %s\n", ((dataStructure*)p->data)->birthday, ((dataStructure*)p->data)->name);
Everything else works. Here is output I got when tested the program.
In your program, you are assigning the pointer to name as below:
((dataStructure*)p->data)->name=name;
This name is derived from the sscanf as below:
sscanf(s, "%*s %[^0-9]%d", nameTemp, &date);
name=nameTemp+1; // Remove opening quotation mark
name[strlen(name)-2]='\0'; // Remove closing quotation mark
This means that for every run of the loop, you are reading into the same nameTemp or name array and storing the same into the linked list. For every run of the loop, you may have to allocate a separate space for storing the name and assign the same to your node.
EDIT 1:
When you create a new node, there is also one type-casting issue. p->data is of void * type, in the code, I believe, the newly allocated memory is type-casted as dataStructure * as below
p->data=(dataStructure*)malloc(sizeof(dataStructure));
You could also change your data structure definition as below
typedef struct dataStructure
{
int birthday;
char name[64]; // Change from pointer to an array
} dataStructure;
And modify the logic in the loop to copy the name as below:
p->data=(dataStructure*)malloc(sizeof(dataStructure));
((dataStructure*)p->data)->birthday=date;
strcpy(((dataStructure*)p->data)->name, name); // Modified from pointer assignment to strcpy
Run this in a debugger to see exactly what your function is doing. For example if you're running from a Unix command line, compile with the -g flag, then run in gdb. Set a breakpoint at the beginning of the function that is troubling you. Google something like "gdb cheat sheet" for details, it's easy.

Compare using strcmp on linked-list

I'm not a great understanding on linked-list, i don't know if it's possible, but i need to do it :) I have a linked list that are load to the struct, and i need to compare a all the chars on the struct....It's better with an example:
This is without linked lists
struct
typedef struct x{
char name[100];
}x;
typedef x Info;
typdef struct Elem{
Info node;
struct Elem*next;
}Element;
for(i=0;i<100;i++){
if(strcmp(a.name[i],a.name[i+1])==0){
printf("Same name\n");
}
}
else
printf("Diff name\n");
Now i need to do something like this but with linked-list
First of all: int strcmp ( const char * str1, const char * str2 ) compares two C-strings (char pointers). This means that a.name[i] should be a char pointer and not a char! Make sure this is the case (i.e. make sure a.name is an array of c-string arrays, and not an array of chars).
Secondly, if the previous is the case, your code will only compare string i with string i+1. It will not compare all strings with each other.
In any case, it looks like you are not doing whatever it is you want to do the right way. I'm guessing you want a struct that is defined like this:
struct example {
char * name;
// other members of choice
example * next;
}
A placeholder for a name, other members, and a next pointer to enable the linked list data type. That way you can compare names with:
while (list->next != 0 && list->next->next != 0) {
if (strcmp(list->name, list->next->name) == 0) // do something;
else // do something else;
}
or with a double loop if you want to compare all strings with each other.
So the first thing you need to do is understand the fundamentals of linked-list. You can read in detail here: http://www.codeproject.com/KB/cpp/linked_list.aspx
NOTE: You really can't undersand linked lists until you understand pointers. http://www.cplusplus.com/doc/tutorial/pointers/
Essentially a linked-list is composed of numerous "nodes" that link to each other. At a minimum each node will have two pieces of data, one being the data (in your case a character) and the other being a pointer to the next node in the list.
Defining a struct would look like (in pseudocode):
LinkedList nodeT {
char *c; //NOTE: strcmp only compares pointers to chars
nodeT *nextNode;
}
You would have a pointer to the first node of the linked list. Something like:
nodeT *firstElement;
Then cycling through the entire list is a piece of cake:
nodeT *curElement = firstElement;
while(curElement->next != NULL) { //assuming the last node's next pointer is NULL
if(strcmp(curElement->c,curElement->next->c)==0){
printf("Same name\n");
} else {
printf("Diff name\n");
}
curElement = curElement->nextNode;
}
But again, to understand this you need to understand the fundamentals of pointers.
Here is a program that traverses the linked list and compares the names of adjacent elements. I have taken the liberty of renaming a couple of things, but otherwise the code for the data structures is the same as yours.
#include <string.h>
#include <stdio.h>
#include <assert.h>
typedef struct Info_ {
char name[100];
} Info;
typedef struct Element_ {
Info info;
struct Element_* next;
} Element;
void print_comparisons(Element* elm)
{
assert(elm);
Element* cur = elm;
Element* next = cur->next;
for (; next; cur = next, next = next->next) {
if (strcmp(cur->info.name, next->info.name) == 0)
printf("Same name\n");
else
printf("Diff name\n");
}
}
int main()
{
Info a; a.name[0] = 'A'; a.name[1] = '\0';
Info b; b.name[0] = 'B'; b.name[1] = '\0';
Info c; c.name[0] = 'B'; c.name[1] = '\0';
Info d; d.name[0] = 'D'; d.name[1] = '\0';
Element na; na.info = a;
Element nb; nb.info = b;
Element nc; nc.info = c;
Element nd; nd.info = d;
na.next = &nb;
nb.next = &nc;
nc.next = &nd;
nd.next = NULL;
print_comparisons(&na);
}
The output of the program:
Diff name
Same name
Diff name

Resources