scanf char* word in struct shows only the last input - c

I am only allowed to use following headers
#include <stdio.h>
#include <stdlib.h>
and I defined my struct student as following:
struct dict
{
char* word;
struct dict* link;
};
There are many functions, but only one function that I have problem right now.
This function inserts a struct dict with certain name at the end of the link.
struct student *Linsert(struct dict *list, char *name)
{
struct student *pnew;
struct student *pn;
int exist = 1;
pnew = (struct dict *)malloc(sizeof(struct dict));
pnew -> next = NULL;
pnew -> name = name;
if (list != NULL)
{
for (pn = list; pn -> next != NULL; pn = pn -> next) ;
pn -> next = pnew;
}
else
list = pnew;
return list;
}
Using the following function,
//print all the values in the list
void printList(struct dict* list);
I did this:
int main(void)
{
struct dict *list = NULL;
char *name;
while (1) {
scanf("%s", name);
if (name == 'Q')
break;
list = Linsert(list, name);
printList(list);
}
return 0;
}
Lets say for input, I typed three
apple banana and orange, my result shows three of my last input.
What is the issue here?

I see two problems with your code:
You need to pass scanf a char array of size sufficient to store the input string, not simply a char pointer.
You need to copy strings passed into Linsert (use strdup).

Your main snippet alone has a whole bunch of problems:
name is an uninitialized pointer; it's pointing to some unknown location in memory that you haven't allocated and are allowed to use, therefore causing undefined behaviour. Perhaps you want char name[20] to allocate an array of 20 chars on the stack, and have scanf store the input in this buffer.
You're comparing a char* (a pointer to the start of a string) to a single char 'Q' - you're comparing a pointer and an integer value as your compiler warnings will tell you. You're not comparing the contents of the string for the value 'Q', you're comparing the memory address of name and the integer value for 'Q'. If you want to compare the string name with the string "Q", use strcmp and check for a return value of 0.
You also want to be making a copy of the variable passed to Linsert otherwise, as you've noticed, you'll be passing a pointer to the same location in memory every time, and a change to this block of memory will change each of your items.
If you turn your compiler warnings up you'll get even more warnings.

You are not allocating any memory for the name, so scanf is writing to some random location, and overwriting that every time through the loop.

One issue is that you've not allocated storage for the word member to point to. You have also not allocated space for name to point at. That is a principle cause of trouble.
You need to allocate space for name; the easiest way is:
char name[128];
You need to allocate space to store the word, and you need to copy the contents of name into the word so that when the next line overwrites name, it does not destroy the saved word.
Adapting your code, you might use:
struct student *Linsert(struct dict *list, char *name)
{
struct student *pnew;
struct student *pn;
pnew = (struct dict *)malloc(sizeof(struct dict));
if (pnew == 0)
...error...
pnew->next = NULL;
pnew->word = malloc(strlen(name) + 1);
if (pnew->word == 0)
...error...
strcpy(pnew->word, name);
if (list != NULL)
{
for (pn = list; pn->next != NULL; pn = pn->next)
;
pn->next = pnew;
}
else
list = pnew;
return list;
}
Do not omit the error checks on memory allocation - painful though it be. It will bite you when you forget.
Stylistically, do not use spaces around either -> or .; they are operators that bind very tightly, and they should not be spaced out like other binary operators.
There's a convenient function, strdup(), the duplicates a string, but it is not standard C (it is standard POSIX).

Since name is a char pointer, your assignment to the field of each dict struct will use the latest value it points to.

Related

C LinkedList storing the last value only

I am having problem storing all the values into the Generic LinkedList, my linkedlist works totally works on a normal user Keyboard input but when I try to store values(strings) from a file, there is something weird happening, it only store the last value of the file.
I have checked my addToList() function but theres nothing wrong with it.
P.s But I am feeling its either I am printing wrong or my reading from the file into the linkedlist is wrong.
Thank you.
#include<stdio.h>
#include <stdlib.h>
#include<string.h>
#include "LinkedListItems.h"
#define MAX 10000
int main()
{
printf("Testing MissileFIle.txt");
void* secondStr;
//Had to malloc the thing
secondStr = (void*)malloc(1*sizeof(char));
FILE* missileFile;
missileFile = fopen("missiles.txt", "r");
if(missileFile == NULL)
{
printf("The file is empty");
}
number_list_t* missileList = calloc(1, sizeof(number_list_t));
void* input;
//Have to allocate the input
input = malloc(1*sizeof(void*));
//this is to read the data into the second Str
while(fgets(secondStr,MAX,missileFile) != NULL)
{
//Let just print out first just to test my memory
printf("%s\n",secondStr);
//Right now its only reading one string so far which is really weird AFFFFF
addTolist(missileList,secondStr);
}
//Gotta declare another list just to print out the list
number_node_t* current = missileList->head;
while(current != NULL)
{
//There is something wrong with this line
printf("%s\n",current-> number);
current = current-> next;
}
fclose(missileFile);
}
OUTPUT:
Testing MissileFile.txt
splash
single
V-line
h-line
Single
Single
Single
Single
Single
Single
typedef struct NumberNode
{
//It can store any data type
void* number;
struct NumberNode* next;
}number_node_t;
//List of Nodes
typedef struct NumberList
{
number_node_t* head;
int count; //This is not nesssary but it can be useful for counting how many variables
}number_list_t;
void addTolist(number_list_t* list, void* newNumber)
{
//tem[ = newNode]
number_node_t* newNode = calloc(1,sizeof(number_node_t));
newNode->number = newNumber;
newNode->next = list->head;
list->head = newNode;
}
INPUT DATA:
single
splash
single
V-Line
h-line
Single
The way you have implemented this, it cannot work.
The main problem, among many, is related to the void* pointers which cannot be dereferenced.
The size of elements should be given, either on creating the list in which case all elements are of the same type, or separately for each individual element. You can check out this question for an example of something that could work.
As far as the buffer thing is concerned, addToList should allocate new memory for each newNumber. What you are currently doing results in all data of the list pointing to a specific space in memory (the one allocated to secondStr). Each time you change the content of that memory space, all elements in the list are affected. This is why you print the same value for all elements and more specifically the last value in your file.
The way you allocate memory is also not really ok, same goes for the way you open your file, there is memory leaking etc. I am not going into details.
At least this issue:
Copy the string
OP's goal includes the need to copy the string from the read buffer to the list, not just copy the buffer pointer.
// void addTolist(number_list_t* list, void* newNumber) {
void addStringTolist(number_list_t* list, const char *s) {
// number_node_t* newNode = calloc(1,sizeof(number_node_t));
number_node_t* newNode = calloc(1, sizeof *newNode); // todo: add error check
size_t sz = strlen(s) + 1;
newNode->number = malloc(sz); // todo: add error check
strpy(newNode->number, s);
newNode->next = list->head;
list->head = newNode;
}
Note: When freeing the list, newNode->number also needs to be free'd.
regarding:
while(fgets(secondStr,MAX,missileFile) != NULL)
MAX is defined as 10000 but secondStr is defined as pointer to one byte. so when this is executed, a buffer overflow occurs.
This is undefined behavior and probably the root of the problem with reading from a file

I can't store a string of characters in a node of linked list

I'm doing my coursework regarding airport simulation and I'm having some troubles trying to store information in the character array part.
I am supposed to type in a string of character and it will store in the planeName part of the node but it can't seem to work. My int main() is pretty much empty now because I didn't want to continue coding with incorrect functions.
Below are my codes:
struct node {
char planeName[5];
int planeNumber;
struct node* next;
};
struct node* front = NULL;
struct node* rear = NULL;
void Enqueue(char name[5], int x);
int main() {
}
void Enqueue(char name[5], int x){
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp -> planeName = name;
temp -> planeNumber = x;
temp -> next = NULL;
if (front == NULL && rear == NULL)
front = rear = temp;
rear -> next = temp; //set address of rear to address of temp
rear = temp; //set rear to point to temp
return;
}
This is the error message in the line containing: temp -> planeName = name
This is the part where error message pops up and I have no clue why is this happening.
Can someone please help and ask more questions me if my question is not clear enough?
temp -> planeName = name;
You can't assign to an array. Array cannot be used as lvalue. Use strcpy instead-
strcpy(temp -> planeName,name);
Note- But make sure your char arrays are nul terminated before passing them to strcpy.
Your strings are arrays of characters, so you have to copy the individual elements. Fortunately, there are functions (like strcpy) written to do just that.
The error comes from the fact that you are performing a shallow copy by copying the name of your array planeName.
If you want to copy your array you need to copy each and every element of it, this is done easier if the last element of your array contains a special character indicating its end, for example the character \0.
An array containing as its last character, the \0 is called: null terminated. There are a lot of functions that perform operations on null terminated arrays. The one that you need is:
char * strcpy ( char * destination, const char * source );
which will copy all of the element of the null terminated array passed as source to destination. In your case it will look like this:
strcpy(temp -> planeName,name);
Here is a brief info about strcpy().

How do you store string type data in a linked list in C?

So I'm trying to understand how a linked list works with storing string type pieces of data. As far as I know, a linked list uses a data structure to store data in a somewhat fashionable way so you can easily enter new pieces of data inside, remove them, and rearrange them as you please. My problem is, I need to take a string in from the user, assign it a spot in the linked list and move on to the next node in the list and do the same thing again. At this point however, I'm simply trying to take one string from the user, store it in the new_node value, (or (*new_node).value for those of you thinking in terms of pointers and not linked lists) and print it out. The main just asks the user for a string input, the add_to_list func takes the input and adds it to the beginning of the linked list, and the print func simply prints what ever is in the linked list. Where the problem lies in my understanding (at least what I think is the problem) is the point at which I assign the data structure the value of the input, new_node->value=*n should just make the value contain the input string as it would just giving another array the value of whatever the pointer *n is containing, unfortunately that's not the case and I'm not sure why that is. Here's the code for simplicity's sake.
EDIT: Thanks everyone for the responses and the explanation behind why strcpy is necessary when dealing with assigning the value of an array of characters to another array ie: strings!
#include <stdio.h>
#include <stdlib.h>
#define LARGE 10
struct node *add_to_list(struct node *list, char *n);
struct node{
char value[LARGE+1];
struct node *next;
};
struct node *first = NULL;
void print(void);
int main(void) {
char job[LARGE],*p;
printf("Please enter printing jobs\n");
scanf ("%s", job);
p=&job[0];
first = add_to_list(first, p);
print();
return 0;
}
struct node *add_to_list(struct node *list, char *n)
{
struct node *new_node;
new_node = malloc(sizeof(struct node));
if (new_node == NULL) {
printf("Error: malloc failed in add_to_list\n");
exit(EXIT_FAILURE);
}
new_node->value = *n;
new_node->next = list;
return new_node;
}
void print(void){
struct node *new_node;
for(new_node=first;new_node!= NULL; new_node=new_node->next){
printf("%s\n",new_node->value);
}
}
Use strcpy instead of assigning a char to an array, which doesn't compile. Arrays are not lvalues, and cannot be assigned to without subscripting, so any assignment with an array name by itself on the left will not compile. Change
new_node->value = *n;
to
#include <string.h>
...
strcpy(new_node->value, n);
you cannot assign string as normal integer assignment.
whenever you want to copy a array you have to use library functions like memcpy or strcpy. In your case its array of characters i.e string you have to use strcpy.
usage char *strcpy(char *dest, const char *src);
so in your code it has to be like strcpy(new_node->value,n); instead of new_node->value=*n;
Reason for using strcpy is mentioned in the link below
why strcpy function

How to initialize a Linked List with a struct with many variables

I still have troubles with the relations between the linked lists and the structures.
See, my objectif is to create a list where each node contains 2 characters strings. So, I tried something like this : first, I create a structure that represent an element with my 2 char ; second, a control structure for my list, thath will point at the beginning of my list. Which, in my .h, gives something like this :
typedef struct s_def { char *first_word; char *second_word; struct s-def *next; } t_def
typedef struct s_type { t_def *first; } t_list;
Next, I try to initialize my list. I make a function that work like this :
t_list *list;
t_def *words;
list = malloc(sizeof(*list));
words = malloc(sizeof(*words));
if (list == 0 || words == 0)
return (NULL);
words = NULL;
words->next = NULL;
list->first = words;
return (list);
Precision : I try to make an empty list for now, so that the user can add some elements later.
And that's where it block : when I run the program, it gives the typical Segmentation Fault. But it don't see what's wrong with what I made ! I put some write in my function to retrace the process : the malloc are working ok, as well as the words = NULL, but then the segment fault seems to run at the line
words->next = NULL;
What do I make wrong ? Why can't I give a NULL value at the next of my words ?
You first initialize the word pointer with allocated memory
words = malloc(sizeof(*words));
Then 3 lines down you set that pointer to NULL again, creating a memory leak
words = NULL;
And then you try to dereference the pointer that you just set to NULL:
words->next = NULL;
So, just remove the words = NULL;
The problem is most likely this part:
words = NULL;
words->next = NULL;
Here you reassign the pointer words to be a null pointer, and directly afterwards you dereference this null pointer, leading to undefined behavior.
When you set words to NULL, you have made a null pointer. Trying to access it immediately afterwards by words->next is effectively doing NULL->next which will cause an error.
Your code looks a little more complex than it needs to be for a simple linked list implementation, you might try something like:
typedef struct s_element
{
char* firstWord;
char* secondWord;
s_element* next;
} t_element;
t_element* list = NULL;
t_element* addFront(t_element* list, char* word1, char* word2)
{
t_element* next = list;
list = malloc(sizeof(t_element));
if (!list) return NULL;
list->firstWord = word1;
list->secondWord = word2;
list->next = next;
return list;
}
Assuming I haven't made any bone-headed syntax mistakes, this should be about as clear as a linked list can get. Notice that it doesn't need to check if the list is empty, the only conditional is in case malloc has failed.

Adding Nodes in Linked List

I am trying to add users to a linked list. I have two structs and a method to add called add_friend that sets up the addition of the node. The program does not ask for user input but passes the info through parameters in the add_friend method: In addition to adding the node (user) to the list I have to check if user already exists. I am getting an error when I try to compare string to see if the user exists. Any help? Unfortunately C is my weakest programming language, Im having a hard time understanding the pointers
struct UserAccountNode {
struct UserAccount* content;
char circle;
struct UserAccountNode* next;
} *head = NULL;
struct UserAccount {
char username[255];
char lastnm [256];
char firstnm[256];
char password[256];
char gender;
int phone;
struct Post* post_list;
struct UserAccountNode* friend_list;
};
int add_friend(UserAccount* user, char Circle, UserAccount* Friend) {
struct UserAccountNode* friend_list;
friend_list = (struct UserAccountNode* ) malloc (sizeof(struct UserAccountNode));
while (friend_list != NULL)
if (stricmp(Circle, head->friend_list) == 0) {
friend_list -> next = head;
head = friend_list;
} else {
printf("%d, User Already Exists", Friend);
}
return 0;
}
The code does not compare strings. It compares char - Circle - with UserAccountNode* friend_list. But stricmp requires both arguments to be const char *. You have to do a loop through all items in friend_list and compare every username with a given one.
Another issue: you allocate memory for UserAccountNode but do not allocate memory for its internal field UserAccount* content. It may crash the application when you try to read the data.
type of Circle is char not char*,
type of head->friend_list is UserAccountNode*.
So, you try to compare non-string objects as strings here:
if (stricmp(Circle, head->friend_list) == 0)
I think your program can't be compiled.

Resources