Linked list of chars in C - c

I'm trying to create a linked list holding char type data.
For some reason, the code does not work. The GCC compiler's warning for function "add_bottom_ListEl" is
"warning: passing argument 2 of 'add_bottom_listEl' makes integer from pointer without a cast"
and
"note: expected 'char' but argument is of type 'char * "
I suspect that there's something wrong about the way I use pointers, but I've tried many, many combinations, passing pointers to the function etc... But nothing seemed to work.
Here's main function and all the others used. MAX_CHAR is defined in all files (#define MAX_CHAR 30)
int main()
{
char name[MAX_CHAR];
scanf("%s", name);
ListEl *head = malloc(sizeof(ListEl));
strcpy(head->name, name);
head->next = NULL;
printf("%s", head->name);
add_bottom_listEl(head, name);
print_listEl(head);
return 0;
}
void add_bottom_listEl (ListEl *head, char name)
{
ListEl *newEl;
while(head->next!=NULL)
{
head=head->next;
}
newEl = (ListEl*) malloc(sizeof(ListEl));
strcpy(newEl->name, name);
newEl->next = NULL;
}
void print_listEl(ListEl* head)
{
puts("print");
ListEl* current = head;
while (current!=NULL)
{
int i=1;
printf("%d.%s\n", i, current->name);
++i;
current = current -> next;
}
}
The ListEl structure is just a regular element of a linked list
struct ListEl
{
char name[MAX_CHAR];
struct ListEl* next;
};
Obviously, I used
typedef struct ListEl ListEl;
Every linked list tutorial on the internet or this site is only showing how to handle lists with integers or numbers in general, but not arrays (chars). Can anyone help me out here?

Your function "add_bottom_listEl" takes one character called "name", not a character array (or a pointer to a character). My guess is you want it to be:
add_bottom_listEl(ListEl *head, char *name)

If your intention in add_bottom_listEl is to modify and pass back head, then head has to be passed as a pointer to a pointer:
void add_bottom_listEl(ListEl** head, char* name) {
if ( head == NULL ) {
//head is invalid, do nothing
return;
}
//Use calloc instead of malloc to initialise the memory area
ListEl* newEl = (ListEl*)calloc(1, sizeof(ListEl));
//Ensure only name of the permissible length is copied
strncpy(newEl->name, name, MAX_CHAR-1);
//No need to do this now...calloc will initialise it to NULL
//newEl->next = NULL;
if ( *head == NULL ) {
//No nodes in list yet, this is the first
*head = newEl;
} else if ( *head != NULL ) {
//Find the end of the list
while((*head)->next!=NULL) {
*head = (*head)->next;
}
}
//Add the new node to the list
*head = newel;
}
When you call this modified version of the function pass the address of the pointer:
add_bottom_listEl(&head, name);
You can make your typedef more readable by doing this:
typedef struct _listEl {
char name[MAX_CHAR];
struct _listEl* next;
} ListEl;

The line
void add_bottom_listEl (ListEl *head, char name)
should be
void add_bottom_listEl (ListEl *head, char* name)

Related

I cant find the error of my linked list( why is my head pointer moving?)

I have tried so many times to set my head pointer pointing to the first node. At first(in the empty list) it correctly points the first node. But after the first loop, the head pointer points to the newnode linked. Actually now Im quite unsure about my whole code as well.
int main(void){
struct library *head = NULL; //set the head pointer to NULL
int option;
printf("Enter the number:");
while((option = getchar())!= 9){
switch(option){
case '1':
{
char title[1000];
char author[1000];
char subject[1000];
printf("Enter title of the book you want to add:");
scanf("%s",title);
printf("Enter author of the book you want to add:");
scanf("%s",author);
printf("Enter subject of the book you want to add:");
scanf("%s",subject);
add_book(title,author,subject,&head);
printf("successful! and head pointer is pointing to %s\n",head->collection.title);
break;
}
}
}
void add_book(char title[],char author[],char subject[], struct library ** head){
struct library *current;
struct library *newnode = malloc(sizeof(struct library));
newnode->collection.title = title;
newnode->collection.author = author;
newnode->collection.subject = subject; // assigning value inside newnode
newnode->num_books = 0;
newnode->next = NULL; // assign NULL value to the end of newnod
//when the head is NULL which means when the list is empty
if(*head == NULL)
{
current = newnode;
*head = current;
return;
}
else
{
current = *head; //assign the first node to current pointer
//find the last node of the list
while(current->next != NULL)
{
current = current->next;
}
current->next = newnode; // link the last node to new node
return;
}
}
This is struct for this
struct book {
char* title;
char* author;
char* subject;
};
struct library {
struct book collection;
int num_books;
struct library* next;
};
The lifetime of char title[1000];, char author[1000];, and char subject[1000]; ends when execution reaches the end of the block inside case '1': { /* ... */ }. Once this happens, the pointers that were assigned in add_book become dangling pointers - pointing to invalid memory.
To remedy this, you must ensure the lifetime of your strings matches the lifetime of the structures that contain them. This can be done either by allocating enough space in the structure itself
struct book {
char title[1000];
/* etc. */
};
or by dynamically allocating enough space for a copy of each string. In any case you must copy the string to this memory (man 3 strcpy).
If it is available on your system, man 3 strdup does both steps of the second form at once. Otherwise, it is roughly the same as strcpy(malloc(strlen(source_string) + 1), source_string);.
Also note that the scanf specifier %s is as dangerous as gets when used without a field-width specifier (e.g., char buffer[1000]; scanf("%999s", buffer);), as it can potentially overflow your buffer.
An example program. Enter strings one-by-one, and terminate with EOF CTRL+D (Windows: CTRL+Z, RETURN).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct link {
char *string;
/* alternatively: char string[512]; */
struct link *next;
};
void add_link(struct link **root, const char *string) {
struct link *node = calloc(1, sizeof *node);
node->string = strdup(string);
/* alternatively: strcpy(node->string, string) */
if (*root) {
struct link *tail = *root;
while (tail->next)
tail = tail->next;
tail->next = node;
} else
*root = node;
}
int main(void) {
struct link *head = NULL;
while (1) {
char buffer[512];
if (!fgets(buffer, sizeof buffer, stdin))
break;
/* remove newline */
buffer[strcspn(buffer, "\n")] = '\0';
add_link(&head, buffer);
}
for (struct link *node = head, *next; node; node = next) {
next = node->next;
printf("STRING: %s\n", node->string);
free(node->string);
free(node);
}
}
Note: in a real program you should always check the return values of your memory allocating functions (malloc, calloc, strdup, etc.) as they can fail.

C Linked list, printf and "assignment makes integer from pointer without a cast" problem

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).

C - Printing the head of a linked list

I am trying to build a linked list from a string of integers separated by spaces. Each integer in the string will be added to the linked list except for -1. However, when I try to print the data in the head node of the list, I get the error Member reference base type 'Node *' (aka 'struct node *') is not a structure or union. Why can't I print head_ptr's data in that line?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node Node;
struct node {
int data;
Node *next;
};
void build_linked_list(Node **head_ptr) {
char *string = malloc(1028);
char *p = string, *found = string;
Node *nextNode = NULL;
if (fgets(string, 1028, stdin) != NULL) {
while ((found = strsep(&p, " \n")) != NULL) {
if (strcmp(found, "-1") == 1) {
Node node = {atoi(found), nextNode};
nextNode = &node;
}
}
}
*head_ptr = nextNode;
printf("%i\n", *head_ptr->data); // can't print data in head node
free(string);
}
int main() {
Node *head = NULL;
build_linked_list(&head);
return EXIT_SUCCESS;
}
you need to put parentheses around the head_ptr to make it work, like this: (*head_ptr)->data)
the problem arises since the compiler evaluates the expression as a dereference of a double pointer with a member of int, so first it tries to get the int member from the double pointer, which doesn't exist.
so that's why you need to put the parenthesis, so it will evaluate the head_ptr as a dereference of the double pointer, and will use the int member of that struct.

doublepointed list C

I wanted to make a list using double pointer and using void as return.
#include<stdio.h>
#include<stdlib.h>
typedef struct list{
int value;
struct list *next;
}*list;
void addnode(struct list **List, int number) {
if(*List == NULL) {
*List = (struct list*)malloc(sizeof(struct list*));
(*List)->value = number;
(*List)->next = NULL;
} else {
while((*List)->next != NULL) {
(*List) = (*List)->next;
}
*List = (struct list*)malloc(sizeof(struct list*));
(*List)->value = number;
(*List)->next = NULL;
}
}
int main() {
list List1 = NULL;
addnode(&List1, 20);
printf("%d \n", List1->value);
addnode(&List1, 30);
printf("%d \n", List1->value);
printf("%d \n", List1->next->value);
return 0;
}
The first if in addnode is always executed but i want to append the list if its not empty but it seems like it never work. Ill also get segmenation fault because in the last printf it tries to take the next element in the list but its never initialized like i want.
If everthing worked as i wanted i should have printed out
printf("%d\n", List1->value)
20
printf("%d\n", List1->value)
20
printf("%d\n", List1->next->value)
30
The size you are passing to malloc is wrong.
You are allocating a struct list, not a struct list *.
If you are trying to append a new list item, remember (*List)->next will already be NULL on the second call. The malloc following that uses the pointer before the NULL list item (*List) when it should be assigned to the next list item, the one that is NULL, to make it non-NULL ((*List)->next=malloc(struct list);).
Also, your malloc should be using sizeof(struct list), without the *. If you add the *, you're allocating a struct list **. A rule you can use is use one * fewer than the destination type as the sizeof operand. Since your destination is *List, which is of type struct list *, use sizeof(struct list). Alternatively, because your destination is *List, use sizeof **List (use one more * than the destination variable has). This avoids you needing to know the type. It won't matter if List or *List is NULL because the sizeof operation is executed first; pointer dereferencing never occurs since sizeof works on the type of the variable.
Modify your program like this
int addNode(struct list **List, int number)
{
struct list *new, *tmp; // new = create new node, tmp = navigate to last
new = malloc(sizeof(struct list));
if(!new) { //always validate "malloc"
perror("malloc");
exit(1);
}
new -> value = value; // assigning values to new node
new -> next = NULL;
if(!(*list)) { //Check if list is empty or not, plz initialize *list#main() with NULL as like your program. or write seperate function to initialize
*list = new;
return 0; //no need write else condition, bcoz its the first node. and u can directly return
}
tmp = *list;
while(tmp -> next) // To navigate to last node
tmp = tmp -> next;
tmp -> next = new; //creating link to new node
return 0;
}
It's better to write print function seperatly.
int print(struct list **list)
{
struct *current; //current is your current node position
current = *list;
while(current) { //loop till current node addr == NULL
printf("%d\t", current -> value);
current = current -> next;
}
printf("\n");
return 0;
}

Troubleshooting compile time circular linked list errors

Okay, so I'm getting these errors upon compile with gcc:
prelab6.h: In function âinsertHeadCircularâ:
prelab6.h:45: error: incompatible types in assignment
prelab6.h:46: error: incompatible types in assignment
prelab6.c: At top level:
prelab6.c:41: warning: data definition has no type or storage class
prelab6.c:41: warning: parameter names (without types) in function declaration
prelab6.c:41: error: conflicting types for âprintInOrderâ
prelab6.h:81: error: previous definition of âprintInOrderâ was here
prelab6.c:42: warning: data definition has no type or storage class
prelab6.c:42: warning: parameter names (without types) in function declaration
prelab6.c:42: error: conflicting types for âprintReverseâ
prelab6.h:112: error: previous definition of âprintReverseâ was here
I've tried and tried, but to no avail to fix these errors. Thanks for any and all help.
Here's my .c file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "my.h"
int main ( int argc, char **argv )
{
char firstname[100];
char lastname[100];
int monthsEmployed;
FILE *fptr;
fptr = fopen(argv[1], "r");
if (fptr == NULL)
printf ("Incorrect file reading!");
if (argc != 2)
printf ("Incorrect number of arguments!");
employeeInfo *insert;
insert = malloc(sizeof(employeeInfo));
employeeList *head;
head = NULL;
while(!feof(fptr))
{
fscanf (fptr, "%100s %100s %d", firstname, lastname, &monthsEmployed);
strcpy(insert->firstname, firstname);
strcpy(insert->lastname, lastname);
insert->monthsEmployed = monthsEmployed;
head = insertHeadCircular(head, insert);
}
}
printInOrder(head); // display the linked list
printReverse(head); // display the linked list in reverse
And my .h file (note things are commented out because I tried things differently with no results):
typedef struct employeeInfo{
char firstname[100];
char lastname[100];
int monthsEmployed;
}employeeInfo;
//Struct containing pointers to the next and previous used to make a circular linked list
typedef struct list{
employeeInfo emp;
struct list *next;
struct list *previous;
}employeeList;
employeeList *insertHeadCircular(employeeList *head, employeeInfo *emp);
void printInOrder(employeeList head);
void printReverse(employeeList head);
employeeList *insertHeadCircular(employeeList *head, employeeInfo *emp)
{
employeeList *theprevious = head;
employeeList *current;
employeeList *thenext = head;
current = malloc(sizeof(employeeList));
employeeInfo *employee;
if(thenext==NULL)
{
current->next = current;
current->previous = current;
}
else
{
current->next = thenext;
thenext->previous = current;
while(theprevious->next != thenext)
{
theprevious = theprevious->next;
}
current->previous = theprevious;
theprevious->next = current;
}
current->emp = (employeeInfo *)malloc(sizeof(employeeInfo));
employee = current->emp;
employee = malloc(sizeof(employeeInfo));
strcpy(employee->firstname, emp->firstname);
strcpy(employee->lastname, emp->lastname);
employee->monthsEmployed = emp->monthsEmployed;
/*
employeeList *newcell, *first = head;
if(head == NULL)
{
newcell = (struct list *)malloc(sizeof(struct list));
strcpy(newcell->firstname, emp->firstname);
strcpy(newcell->lastname, emp->lastname);
newcell->monthsEmployed = emp->monthsEmployed;
return newcell;
}
while(head->next != first)
{
head = head->next;
}
newcell = (struct list *)malloc(sizeof(struct list));
head->next = newcell;
strcpy(newcell->firstname, emp->firstname);
strcpy(newcell->lastname, emp->lastname);
newcell->monthsEmployed = emp->monthsEmployed;
newcell->next = first;
*/
return current;
}
void printInOrder(employeeList head)
{
/*employeeInfo *first = head;
if (head == NULL)
{
printf("The circularly linked list is empty!\n");
return;
}
do
{
printf("%s %s %d\n", emp.firstname, emp.lastname, head.monthsEmployed);
head = head->next;
} while(head != first);
*/
/*employeeInfo current = head;
employeeInfo start = head;
int loop = 0;
printf("--------------\n");
while(current != start || loop==0)
{
loop++;
printf("Employee: %s %s\nMonths Employed: %d", current->firstname, current->lastname, current->monthsEmployed);
printf("--------------\n");
current=current->next;
}*/
}
void printReverse(employeeList head)
{/*
employeeList current = head
employeeInfo start = head
int theloop=0;
printf("--------------\n");
while(current! = start || loop==0)
{
loop++;
printf("Employee: %s %s\nMonths Employed: %d", current->firstname, current->lastname, current->monthsEmployed);
printf("--------------\n");
current=current->previous;
}*/
}
EDITED PROGRAM
Error:
file.c: In function âmainâ:
file.c:37: error: incompatible type for argument 2 of âinsertHeadCircularâ
The .c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "file.h"
int main ( int argc, char **argv )
{
char firstname[100];
char lastname[100];
int monthsEmployed;
FILE *fptr;
fptr = fopen(argv[1], "r");
if (fptr == NULL)
printf ("Incorrect file reading!");
if (argc != 2)
printf ("Incorrect number of arguments!");
employeeInfo *insert;
insert = malloc(sizeof(employeeInfo));
employeeList *head;
head = NULL;
while(!feof(fptr))
{
fscanf (fptr, "%100s %100s %d", firstname, lastname, &monthsEmployed);
strcpy(insert->firstname, firstname);
strcpy(insert->lastname, lastname);
insert->monthsEmployed = monthsEmployed;
head = insertHeadCircular(head, insert);
}
printInOrder(head); // display the linked list
printReverse(head); // display the linked list in reverse
}
The .h:
typedef struct employeeInfo{
char firstname[100];
char lastname[100];
int monthsEmployed;
}employeeInfo;
typedef struct list{
employeeInfo emp;
struct list *next;
struct list *previous;
}employeeList;
typedef employeeList *listnode;
employeeList *insertHeadCircular(employeeList *head, employeeInfo emp);
void printInOrder(employeeList *head);
void printReverse(employeeList *head);
employeeList *insertHeadCircular(employeeList *head, employeeInfo emp)
{
listnode newPtr;
listnode firstPtr;
listnode tempPtr;
newPtr = (employeeList *)malloc(sizeof(employeeList));
strcpy(newPtr->emp.firstname, emp.firstname);
strcpy(newPtr->emp.lastname, emp.lastname);
newPtr->emp.monthsEmployed = emp.monthsEmployed;
if(head == NULL)
{
newPtr->next = newPtr;
newPtr->previous = newPtr;
head = newPtr;
firstPtr = newPtr;
}
else
{
tempPtr = firstPtr;
newPtr->next = tempPtr;
tempPtr->previous = newPtr;
newPtr->previous = head;
head->next = newPtr;
firstPtr = newPtr;
}
return head;
}
void printInOrder(employeeList *head)
{
listnode currentPtr = head;
do
{
printf("%s %s %d\n",currentPtr->emp.firstname, currentPtr->emp.lastname, currentPtr->emp.monthsEmployed);
currentPtr= currentPtr->previous;
}
while(currentPtr !=head);
}
void printReverse(employeeList *head)
{
listnode currentPtr = head->next;
do
{
printf("%s %s %d\n",currentPtr->emp.firstname, currentPtr->emp.lastname, currentPtr->emp.monthsEmployed);
currentPtr = currentPtr->next;
}
while(currentPtr != head->next);
}
In your insertHeadCircular() function, you treat the emp member of employeeList as though it were an employeeInfo *. For example, you declare:
employeeInfo *employee;
but then later do this:
employee = current->emp;
However, your employeeList type contains an instance of employeeInfo, not a pointer to one:
typedef struct employeeInfo{
char firstname[100];
char lastname[100];
int monthsEmployed;
}employeeInfo;
/* ... */
typedef struct list{
employeeInfo emp; /* see? Not a pointer. */
struct list *next;
struct list *previous;
}employeeList;
So basically you need to correct your code so that you stop assigning a structure to a pointer, and instead assign the address of the structure to the pointer.
Most likely your printInOrder() and printReverse() functions should take employeeList * arguments, rather than employeeList ones, as well... and you should check the code you use for them to make sure you don't confuse the two anywhere.
It's also a good idea to define your functions somewhere other than the header file, such as in a separate .c source file. The header file should just contain function prototypes, macros, and other declarations that may be needed for other source files; you don't need the function bodies in there, since the linker can find them in the object files created from your other sources. Defining functions in header files like that will cause endless headaches when the header file is #includeed by more than one file.
The error you get with your updated code, file.c:37: error: incompatible type for argument 2 of âinsertHeadCircularâ is pointing out that the type of argument you're passing to insertHeadCircular() isn't the type you gave in its declaration -- which is true. You've declared and defined that function to take an employeeInfo as its second argument:
employeeList *insertHeadCircular(employeeList *head, employeeInfo emp)
...but in main() you pass it a pointer instead:
employeeInfo *insert;
...
head = insertHeadCircular(head, insert);
So you need to change one or the other. Either dereference insert when you call the function from main, or change insertHeadCircular() to take a pointer instead (and update the body accordingly). The latter is probably better, since it avoids copying the entire structure onto the stack when you call the function.
Some other things to point out:
You should really check the return from scanf() in your loop in main(). It would let you know whether all the fields were actually read; right now, if they weren't, your program just proceeds with whatever junk the variables already had (like whatever was read on the previous iteration, possibly). Checking other return values (like the return from malloc()) is a good idea too, but in this case the scanf() return is particularly important.
You also don't free insert at the end of your program; the OS will (almost certainly) clean it up when your program exits, but it's good practice to do it yourself when you're done with it. The way you use it, though, you didn't really need to dynamically allocate it anyway; you could have just declared an employeeInfo and taken its address (works either way, though).

Resources