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);
Related
I try to create a library program with a linked list in C. I get an "assignment makes integer from pointer without a cast" error and when I try to print screen the list print_list function not working; only printf "H->" doesn't print in the while loop.
#include<stdio.h>
#include<stdlib.h>
struct node
{
char bookname[40];
char writer[50];
int available;
int memberid;
struct node *next;
};
void AddBook(struct node **head, char bookname[50], char writer[50], int available, int memberid)
{
struct node * new_node = NULL;
struct node * last = NULL;
new_node = (struct node *)malloc(sizeof(struct node));
if (new_node == NULL)
{
printf("Failed to insert element. Out of memory");
return;
}
new_node->bookname[50]= bookname;
new_node->writer[50]= writer;
new_node->available= available;
new_node->memberid= memberid;
new_node->next = NULL;
At this point, I get an "assignment makes integer from pointer without a cast" problem on these two;
new_node->bookname[50]= bookname;
new_node->writer[50]= writer;
if( *head == NULL)
{
*head = new_node;
return;
}
last = *head;
while(last->next) last = last->next;
last->next = new_node;
}
void print_list(struct node *head)
{
printf("H->");
while(head)
{
printf("%s %s %d %d ->", head->bookname[50],head->writer[50],head->available,head->memberid);
head = head->next;
}
printf("|||\n\n");
}
int main()
{
struct node * head = NULL;
AddBook(&head,"Hamlet","William_Shakespeare",1,1);
AddBook(&head,"The Odyssey","Homer",1,1);
AddBook(&head,"The Great Gatsby","F. Scott Fitzgerald",1,1);
print_list(head);
return 0;
}
What can I do to get book name and writer get with scanf? I tried to do it this way but it didn't work;
int main()
{
struct node * head = NULL;
struct node book;
prinft("please enter the bookname:");
scanf("%s", book.bookname);
prinft("\n please enter the writer name:"); scanf("%s",book.bookname);
book.available=1;
book.memberid=1;
AddBook(&head,*book.bookname,*book.writer,book.available,book.memberid);
print_list(head);
return 0;
}
On these lines:
new_node->bookname[50]= bookname;
new_node->writer[50]= writer;
You think you're copying the contents of one array to another. What you're actually doing is attempting to copy a pointer (since arrays as function arguments decay to pointers) to a single element of the array (i.e. a char), and to an element past the end of the array at that.
Even if you removed the index from the destination, this wouldn't work because arrays are not assignable.
To copy one string to another, use strcpy:
strcpy(new_node->bookname, bookname);
strcpy(new_node->writer, writer);
Although arrays and pointers to arrays can be treated as interchangeable in some cases, this is not one of them. Since bookname and writer are declared as char arrays and not char pointers, you won't be able to accomplish what you're trying to do by assigning a char * to either of them. Instead, you should use strncpy() (assuming these are null-terminated strings) to copy them over.
You should also double-check the array indices--you're trying to copy to bookname[50] (which would be the 51st element, because of zero-based numbering) while bookname[]'s declaration is only for 40 elements (for the same reason of zero-based index numbering, there is no writer[50] even though it is declared as char writer[50] -- the declaration creates a 50-element array, whose first element is at index 0 and fiftieth at 49).
This is a code from my programming with C course that prints a list, using ADT structs.
typedef struct list{
int data;
struct list *next;
}list;
int is_empty(const list *l){
return(l==NULL);
}
void print_list(list *h, char *title){
printf("%s\n", title);
while(h!=NULL){
printf("%d :", h -> data);
h = h -> next;
}
}
int main()
{
list list_of_int;
list* head = NULL;
head = malloc(sizeof(list));
printf("size of the list = %lu\n",sizeof(list)); //this has to be an unsigned long
head -> data = 5;
head -> next = NULL;
print_list(head,"single element list");
printf("\n\n");
return 0;
}
My question is, how we used malloc() and the memory it created to create the list pointer head?
The purpose of malloc is "making" legal space and providing a pointer to it.
The following lines in your code make sure that legal space contains values which make a node.
This might seem short, but that's it.
(And I think you confirmed that you now understand. Otherwise I would consider it too short to be polite myself.)
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
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.
I have an issue when using pointer parameters in a function to return values. The function correctly loads all values inside the function, but then somehow fails to pass the pointer value to the variable in the arguments.
In my case, i wrote a function witch returns 1 or 0 depending on whether allocation of memory in question failed or not, and as one of the parameters, takes a pointer to a list that needs to be entered. The structure of the list looks like this:
typedef struct sList {
int id;
char first_name[30];
char last_name[30];
struct sList *next;
} tList;
The function looks like this:
int readList(tList *start, int n){
tList *head = NULL;
tList *tail = NULL;
int i;
for (i = 0; i < n; i++){
tList *tmp = malloc(sizeof(tList));
if (tmp == NULL) return 0;
scanf("%d %s %s", &tmp->id, &tmp->first_name, &tmp->last_name);
tmp->next = NULL;
if (!head) head = tmp;
else tail->next = tmp;
tail = tmp;
}
start = head;
return 1;
}
And the main method:
void main(){
tList *start = NULL;
int n;
scanf("%d", &n);
readList(start, n);
tList *tmp = start;
while (tmp){
printf("%d %s %s\n", tmp->id, tmp->first_name, tmp->last_name);
tmp = tmp->next;
}
system("PAUSE");
return;
}
During debugging, i have concluded that the list head and start inside the function have all the entered values, but as soon as I leave the function and return to the main program the start list goes bananas. So, my question is, am I doing something wrong, because, to my knowledge, this should work in theory. Thanks in advance.
If you want to change a variable from within a function, you need to pass a pointer to it and dereference that pointer within said function. That's how C emulates pass-by-reference.
When that variable is itself a pointer, that means you need to pass a pointer to the pointer, such as with:
int readList(tList **pStart, int n){
// blah blah blah, setting up head.
*pStart = head;
return 1;
}
int main(void){
tList *start = NULL;
int n;
scanf("%d", &n);
readList(&start, n); // Note this, using address-of
// more blah
return 0;
}
The text below is an aside to your specific problem but I thought I'd mention it for completeness.
Your main function doesn't conform to the canonical ones allowed by the standard - I've changed it to make that more acceptable but it may not be necessary for your particular implementation, depending on how lax it is. It's still a good idea to follow the standard.
It's also dangerous to assume (in robust code) that scanf() always works. If it returns zero (number of items successfully scanned), n will almost certainly not be what you expect.
You make the same mistake with readList() in that you don't check its return value either. It also has the annoying aspect of causing memory leaks if an allocation fails.