Transfer char arrays into linked list - c

I have been hesitant to post a question about this because I'm worried about asking a stupid question, but here it goes:
I am currently trying to create a program that will take whole strings, put them into char arrays and transfer those char arrays to a linked list. I have everything working up to the point of actually putting the arrays into the linked list.
I initially tried to just create each node with the array itself, which was just giving me the first element of the array. Then I found that I need to use strcpy().
I'm not sure what is wrong at this point, but I think it's down to memory allocation because it's giving me a segfault. That is confusing however, because the memory allocation for rach node is already taken care of.
Thank you for any help, this part has been driving me crazy for a few hours now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
struct node {
char info;
struct node *link;
} *start;
void create(char[]);
void display();
void insert_end(char[]);
int main() {
int i;
start=NULL;
char data[SIZE];
printf("Please enter a word: ");
fgets(data, SIZE, stdin);
create(data);
for(i=0; i<5; i++)
{
printf("Please enter a word: ");
fgets(data, SIZE, stdin);
insert_end(data);
}
display();
return 0;
}
void create(char data[])
{
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
if (start == NULL)
{
strcpy(temp->info,data);
temp->link=NULL;
start=temp;
}
}
void display()
{
struct node *ptr;
ptr = start;
while (ptr!=NULL)
{
printf("%c", ptr->info);
ptr=ptr->link;
}
}
void insert_end(char data[])
{
struct node *ptr, *tempnode;
ptr = start;
while(1)
{
if(ptr->link != NULL)
{
ptr=ptr->link;
}
else
break;
}
tempnode=(struct node *)malloc(sizeof(struct node));
strcpy(tempnode->info,data);
tempnode->link=NULL;
ptr->link=tempnode;
}

As you stated you are using arrays, space needs to be reserved in the info member of the linked list structure. char type will only hold one character.
struct node {
char info[SIZE];
struct node *link;
} *start;
If info is an array, printf requires %s format modifier.
printf("%s\n", ptr->info);

info is a char not a char *.
Compile with -W -Wall, you'll see most of your mistakes.

Related

Ask data from user and store them inside a struct in C

In the code below I tried to use printf and scanf to get data from user and store them inside a struct i defined called node.
The programme works fine for the first prompt, but as soon as the user input name, the programme ends with printing Age:salary:
Can anyone help me with this?
On a side note, can anyone also help me to understand how to create a loop to store data in various nodes and store them together? (Not hard-code it one by one)
Thank you very much!!
typedef struct node
{
char *name;
int age;
int salary;
struct node * next;
}node;
int main(void)
{
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = NULL;
free(tmp);
}
Use a char[] for name,
for example:
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
char name[128];
int age;
int salary;
struct node * next;
}node;
int main(void)
{
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = NULL;
free(tmp);
}
If you want to get several users, loop for ever and ask if the user wants to add more data.
I have create a function to print the list
Console:
Name:Foo
Age:12
salary:12
Continue Y/N
Y
Name:Bar
Age:14
salary:14
Continue Y/N
Y
Name:John
Age:30
salary:45
Continue Y/N
N
John, 30, 45
Bar, 14, 14
Foo, 12, 12
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
char name[128];
int age;
int salary;
struct node * next;
}node;
static void printList(node *n)
{
while (n) {
printf("%s, %d, %d\n", n->name, n->age, n->salary);
n = n->next;
}
}
static node *get_nodes(void) {
node *list = NULL;
while (42) {
char c;
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = list;
list = tmp;
printf("Continue Y/N\n");
scanf(" %c", &c);
if (c == 'N')
break;
}
return list;
}
static void clearList(node *node) {
if (node->next) {
clearList(node->next);
}
free(node);
}
int main(void)
{
node *list = get_nodes();
printList(list);
clearList(list);
return 0;
}
You are trying to write to Uninitialized memory
This is a very common problem beginners face.
You are trying to store the name using char *name declaration.
Here name does not point to a valid memory location, that's why You program is not running as expected.
Even if name points to a valid memory address, you must have enough memory allocated to store the data.
You can use
#define BUFFER_SIZE 50
char name[BUFFER_SIZE];
You can use any buffer size as you like, and then store a string of that length - 1 in the name array. -1 is for the null termination character \0.
Using this declaration you are allocating memory of BUFFER_SIZE bytes and the name points to the first byte in that array.
This allocation happens on the stack not in the HEAP
For fix your bug, you should allocate memory of your char *.
First Way, when you create your struct.
typedef struct node
{
char name[200]; // You specify that your char * can save 200 char
int age;
int salary;
struct node * next;
}node;
or you can create init struct function
node *init_node()
{
node *test = null;
test->name = malloc(sizeof(char) * 200);
test->age = 0;
test->salary = 0;
test->node = null;
return test
}

get segmentation fault error when use strcpy function

I am implementing the doubly linked list, in functions create_head_node, insert_head, insert_tail i have to copy the array name to node. Then I use function strcpy to copy it but I got segmentation fault error. I reimplement function strcpy by cpystr then I got segmentation fault error at dest[i]=source[i];. Can anybody explain to me why it is wrong and how to fix it. thanks for yor help.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct linked_list
{
char name[30];
float point;
struct linked_list *p_node;
struct linked_list *n_node;
}node;
node *create_head_node(node *,char *, float);
node *insert_head(node *, char*, float);
void insert_tail(node *, char*, float);
node *insert_after(node *, char*, float, int);
int count_node(node *);
void print_list(node *);
void cpystr(char*, char*);
int main(){
node *head=(node*)malloc(sizeof(node));
head=create_head_node(head, "asd fgh", 10);
head=insert_head(head, "abc def", 9.8);
insert_tail(head, "qwe rty", 8.98);
head=insert_after(head, "ui op", 8.7568, 1);
print_list(head);
free(head);
return 0;
}
node *create_head_node(node *head, char name[30], float point){
cpystr(head->name, name);
head->point=point;
head->p_node=NULL;
head->n_node=NULL;
return head;
}
node *insert_head(node *head, char name[30], float point){
node *temp=(node*)malloc(sizeof(node));
cpystr(temp->name, name);
temp->point=point;
temp->p_node=NULL;
temp->n_node=head;
head->p_node=temp;
head=temp;
return head;
}
void insert_tail(node *head, char name[30], float point){
node *p=head;
node *temp=(node*)malloc(sizeof(node));
cpystr(temp->name, name);
temp->point=point;
temp->n_node=NULL;
while (p!=NULL)
{
p=p->n_node;
}
p->n_node=temp;
temp->p_node=p;
}
node *insert_after(node *head, char name[30], float point, int index){
int count=count_node(head);
while (index>count)
{
printf("choose %d positions to add. choose again: ", count); scanf("%d", index);
}
if(index==0) head=insert_head(head, name, point);
else if(index==count) insert_tail(head, name, point);
else{
node *p=head;
for (int i = 0; i < index-1; i++)
{
p=p->n_node;
}
node *temp=(node*)malloc(sizeof(node));
temp->n_node=p->n_node;
p->n_node->p_node=temp;
p->n_node=temp;
temp->p_node=p;
}
return head;
}
int count_node(node *head){
node *p=head;
int count=0;
while (p!=NULL)
{
count++;
p=p->n_node;
}
free(p);
return count;
}
void print_list(node *head){
node *p=head;
while (p!=NULL)
{
printf("%s%10f", p->name, p->point);
p=p->n_node;
}
}
void cpystr(char* dest, char* source){
int i=0;
while (source[i]!='\0')
{
dest[i]=source[i];
i++;
}
*dest='\0';
}
Let's think about how pointers work in general. Pointers are variables whose value contain address of another variable. Thus, pointer must be initialized aka "assigned address of variable it should point to", before you can work with them. Now, when you do node* head. head has not been initialized yet, you must allocate memory for head and associate it's address with head, like this:
node *head = (node*)malloc( sizeof(node) );
Now you can access members of head like this:
head->point = 0.01;
Similarly, strcpy will work like this:
const char *dummy = "Sample";
strcpy(head->name , dummy);
Please note that strcpy doesn't check for destination's size. Thus, if destination pointer is not large enough to receive the "copy", Undefined behavior may happen and often but not always result in Segmentation fault.
regarding:
node *temp=(node*)malloc(sizeof(node));
cpystr(temp->name, name);
and
node *create_head_node(node *head, char name[30], float point){
cpystr(head->name, name);
and similar statements:
best to check (via strlen( name ) that the length is <= 29.
Then use: strncpy( head->name, name, sizeof( node.name )); To assure the name field in the struct is not overrun

Adding Characters into Struct

I am trying to read characters into a linked list (I made this simple test code just to try to read in the characters) for some reason I cannot get it to read in a character value.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char name[50];
struct node *next;
}*head;
void add(char AddName);
int main()
{
head = NULL;
char TempName[50];
printf("What Name");
scanf(" %s", TempName);
add(TempName);
printf("%s",head->name);
return 0;
}
void add(char AddName)
{
struct node *temp;
temp = (struct node*)malloc(sizeof(struct node));
strcpy(temp->name,AddName);
head = temp;
head->next = NULL;
}
I understand this is not how a linked list works I just made this to try to get to be able to run a single character name into the struct and print it back out. (I should be able to enter in the name Bob and it prints bob)
I think your function parameter definition is wrong. Try this:
void add(char *AddName)
{
....
}

Unable to Access Casted Void Pointer

I am creating a linked list that contains nodes with the "dataItem" of a void pointer. The purpose of this is in order to be able for the Node to contain any kind of data. However, I am unable to access the void pointer's data, even when that data is casted to the correct type.
My code looks like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Student
{
char stuName[51];
char stuMajor[5];
double GPA;
char stuID[10];
}student;
typedef struct Node
{
union{
void *dataPtr;
int countr;
}dataItem;
int link;
struct Node* next;
}node;
void readData(struct Node *);
void main(){
node head;
node temp;
readData(&temp);
student *ptr = (student *)(temp.dataItem.dataPtr);
printf("%s %d", ptr->stuName, ptr->GPA);//breaks here because unable to access memory
}
void readData(struct Node *link)
{
link = (node *)malloc(sizeof(node));
student *ptr = (student *)malloc(sizeof(struct Student));
printf("enter the student name : ");
fflush(stdin);
scanf("%[^\n]", ptr->stuName);
printf("enter the student's major : ");
fflush(stdin);
scanf("%[^\n]", ptr->stuMajor);
printf("enter the student GPA : ");
scanf("%lf", &(ptr->GPA));
printf("enter the student ID : ");
fflush(stdin);
scanf("%[^\n]", ptr->stuID);
link->dataItem.dataPtr = ptr;
}
I know I definitely have a pointer wrong somewhere I'm not unsure how. I also have the node within my readData function point to a new malloc of Node because I want a new node each time readData is called for when I implement the linked list further.
Your code is very broken,
You didn't include any header file, you need at least stdlib.h for malloc(), and stdio.h for printf() and scanf().
Your main() definition is wrong, because main() must return int.
You fflush(stdin) which is undefined behavior.
You ignore the return value from scanf().
You assume that malloc() always returns a valid pointer.
You called readData() which is not declared yet.
But the most important mistake, is that you passed node temp's address to readData() and you malloc()ed it, but you didn't return a pointer to it, thereby losing all the changes made inside readData() which will not work anyway because it's undeclared at the moment you called it.
I fixed your code, because I know that you didn't like my answer, but check out the fixes which are related to the answer, and now it works as I expected
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Student
{
char stuName[51];
char stuMajor[5];
double GPA;
char stuID[10];
} student;
typedef struct Node
{
union{
void *dataPtr;
int countr;
} dataItem;
int link;
struct Node* next;
} node;
void readData(struct Node **link);
int main()
{
node *head;
student *ptr;
readData(&head);
ptr = head->dataItem.dataPtr;
if (ptr != NULL)
printf("%s\t%g", ptr->stuName, ptr->GPA);
return 0;
}
void readData(struct Node **link)
{
student *ptr;
if (link == NULL)
return;
*link = malloc(sizeof(node));
if (*link == NULL)
return;
memset(*link, 0, sizeof(node));
ptr = malloc(sizeof(struct Student));
if (ptr == NULL)
return;
printf("enter the student name : ");
if (scanf("%50[^\n]%*c", ptr->stuName) != 1)
ptr->stuName[0] = '\0';
printf("enter the student's major : ");
if (scanf("%4[^\n]%*c", ptr->stuMajor) != 1)
ptr->stuMajor[0] = '\0';
printf("enter the student GPA : ");
if (scanf("%lf%*c", &(ptr->GPA)) != 1)
ptr->GPA = 0;
printf("enter the student ID : ");
if (scanf("%9[^\n]%*c", ptr->stuID) != 1)
ptr->stuID[0] = 0;
(*link)->dataItem.dataPtr = ptr;
}
I also added some safety fixes to scanf() adding the length modifier to prevent buffer overflow, and also remove the trailing '\n' with "%*c" specifier, it will not work if multiple spaces follow the value, but you can test it meanwhile just pressing Enter/Return, if you want more sofisticated input, you should use something else instead of scanf().
This:
void readData(struct Node *link)
{
link = (node *)malloc(sizeof(node));
You throw away the link parameter value that was passed in, instead assigning it a new allocation via malloc. This is your most significant problem, I think. A simple fix would be to delete the line performing the malloc.
You want to pass a pointer to a pointer (or address of a pointer) to a node to the readData() function. readData allocates a new node and fills it; what happens in your code is that readData() gets a copy of the address of temp, overwrites the copy of this address with a new address, the one obtained from malloc (which is invisible to the calling code in main()) and then fills that malloc'ed object. Upon return from readData the malloc'ed object is inaccessible.
What you wanted to do is this:
void main(){
node head;
node *tempAddr; // pointer
readData(&tempAddr); // pass address of that pointer
and then use *tempAddr in main instead of temp.
void readData(struct Node **linkAddr)
{
node *link = *linkAddr = (node *)malloc(sizeof(node));
[...]
unwind would complain that you should not cast the result of malloc, but I think it's fine. I also do not care about the return value of main, or its arguments.

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.

Resources