Linked list trouble - c

Does anyone know what might be the problem with the following code? When I run it, I get the following output:
Insert a value in the list: 1
Do you want to continue? y/N:
1 ->
The fact is that the do-while loop executes until the scanf("%c", &ch) statement, and then it jumps out (so I cannot provide any input for the ch variable). I tried debugging with GDB and I got some weird messages:
GI___libc_malloc (bytes=16) at malloc.c:malloc.c: No such file or directory.
Also, it says that the compiler couldn't find the vscanf.c file. Does anyone have an explanation for this strange behavior? Thanks! (The intention was to print the values of a singly linked list in reverse order.)
#include <stdio.h>
#include <stdlib.h>
struct node{
int info;
struct node* next;
};
struct node* head = 0;
void add_node(int value){
struct node* current = malloc(sizeof(struct node));
current->info = value;
current->next = head;
head = current;
}
void print_node(struct node* head){
while(head){
printf(" %d -> ", head->info);
head = head->next;
}
printf("\n");
}
int main(void){
int val;
char ch;
do {
printf("Insert a value in the list: ");
scanf("%d", &val);
add_node(val);
printf("Do you want to continue? y/N: ");
scanf("%c", &ch);
} while(ch == 'y' || ch == 'Y');
printf("\n");
print_node(head);
return 0;
}

If you want the input to be separated by a new line (which it appears that you do) then change the format of how you are reading in your character. Change following:
scanf( "%c", &ch );
... to this:
scanf( "\n%c", &ch ); // << Note, \n to pickup newline before reading the value.

You can check for proper input in an if-else block, and execute your code accordingly.
For example, here is something I would do if I needed to check whether the user wants to continue or not:
char chTemp; //Declare a test variable to check for newline
printf("Do you want to continue? y/N: ");
if (scanf("%c%c",&ch,&chTemp) != 2 || chTemp != '\n')
{
printf("Error in input (Integer input provided)");
}
else
{
//Do stuff.
}
Not only will it solve your problem, but it will also check for careless integer inputs.

The problem you are encountering is because the once you type a value for val and then press enter , then \n still remains in the input buffer . Hence , the next scanf assumes that \n which is still in the input buffer is its input , and consumes it and then loop exits .
Other Solutions :-
1) scanf("%d%*c",&val);
This would assign the first input character to val and then anything after that would be eaten up . Hence , the \n would not go into the next scanf
2) scanf("%[^\n]%*c",&val);
This would assign the anything to the val except \n and then \n would be eaten up .

Related

How to optimize reading character from input so the user does not need to specify the number of characters beforehand

Current state of program
I am making a program which reads the users input of chars until a new line and prints them out in reverse order.
The output i get is correct but i want to optimize the code.
In main i have written code that executes my Insert function n times (n represents the number of chars the user wants to input). So right now the user first need to input the amout of chars they want to input and then they can input the chars.
How i actually want it
I want to make it so that the user can just input the chars without having to first specify the number of chars they want to enter.
My attempts
Tried using a while loop but got wrong result:
Entered "asdf" as input
and got "fs" as output
int main(){
struct Node* head = NULL;
printf("Enter the chars you want to type: ");
while (getchar() != '\n') {
head = Insert(head,getchar());
}
Print(head);
}
Tried using a if statement but got wrong result:
Entered "asdf" as input
and got "s" as output
int main(){
struct Node* head = NULL;
printf("Enter the chars you want to type: ");
if (getchar() != '\n') {
head = Insert(head,getchar());
}
Print(head);
}
My code
#include <stdio.h>
#include <stdlib.h>
struct Node {
char data;
struct Node* linkToNext;
};
void Print(struct Node* head){
while (head != NULL) {
printf("%c", head -> data);
head = head -> linkToNext;
}
}
struct Node* Insert(struct Node* head, char input){
struct Node* pointerToNode = (struct Node*)malloc(sizeof(struct Node));
pointerToNode -> data = input;
pointerToNode ->linkToNext = head;
head = pointerToNode;
return head;
}
int main(){
struct Node* head = NULL;
int i, n;
printf("Enter the amout of chars you want to type: ");
scanf("%d", &n);
for (i = 0; i <= n; i++) {
head = Insert(head,getchar());
}
Print(head);
}
Example result of running code
Enter the amout of chars you want to type: 4
asdf
fdsa
Every call to getchar() reads and returns another character from the standard input.
Consider what happens with code like
while (getchar() != '\n') {
// ^^^^^^^^^ #1
head = Insert(head,getchar());
// ^^^^^^^^^ #2
}
and a user input of asdf.
The call labeled #1 reads and returns 'a' (the first character of input), which is not '\n', so the loop body is executed.
Then the call labeled #2 reads and returns 's' (the next character), which is added to the list.
Then we go back to the loop condition. getchar() #1 reads and returns 'd', which is still not '\n' ...
... and getchar() #2 reads and returns 'f', which is also added to the list.
Finally getchar() #1 reads a newline, which terminates the loop.
Because of the two calls to getchar in every iteration, only every second character was added to the list.
Your second attempt is similar, but if is not a loop, so only the second character total ('s' in asdf) was added to the list.
To fix this, you need to store the return value of getchar in a variable so you can compare it and add it to the list without reading more characters:
int c;
while ((c = getchar()) != '\n' && c != EOF) {
head = Insert(head, c);
}
The additional check for EOF is to prevent your program from going into an infinite loop in case the input is not terminated by '\n'.
you can do this using recursion.Just call the following function in your code.
void printRev(){
char a;
a = getchar();
if(a == '\n'){
return;
}
printRev();
putchar(a);
}
here you don't need for specifying the size of the input. you just scan until you hit enter then print during return.

Premature exit of an input loop

In my program to sort a linked list using selection and bubble sort, getdata() is used to get data from the user.
getdata()
{
int val;
char c;
struct node *new;
new = NULL;
do {
printf("Enter a value:\n");
scanf("%d",&val);
append(&new,val);
printf("Any more nodes(y/n):\n");
c=getchar();
} while(c =='y' || c =='Y');
start = new;
}
But when I run my program the output is
Enter a value: 3
Any More Nodes (Y/N): Linked List Before Sorting: 3
Linked List After Selection Sorting: 3
Enter a value: 2
Any More Nodes (Y/N): Linked List Before Sorting: 2
Linked List After Bubble Sorting: 2
I'm not able to type "y/n" in it. Can someone tell me what is wrong?
The scanf("%d", &val); leaves the newline in the input buffer, so the getchar() reads the newline, which is neither y nor Y, so the loop terminates.
You should probably use:
if (scanf(" %c", &c) != 1)
break;
You should also test the result of scanf("%d", &val) to ensure you get a value.
Your function should also be declared with an explicit return type. For the code shown, that should be void. Note that your code is unnecessarily tied to the global variable start. If you changed the function to struct node *getdata(void) { …; return new; } then you could use it more generally.
instead of c=getchar(); try cin.get();

Segmentation Fault during linked list in c

I am getting a segfault when I try and print out my linked list. Can anyone explain why? I am aware a segfault means that I am accessing memory I am not supposed to. I am assuming this means I am not setting up my pointers right. Any help would be great. My code...
#include <stdio.h>
#include <stdlib.h>
struct node
{
int val;
struct node *next;
}*head;
typedef struct node item;
int main() {
item *curr, *head;
head = NULL;
char word = 'y';
//int num[10];
//int i = 0;
while (word == 'y'){
printf("Would you like to enter an integer? (y/n) ");
scanf("%s", &word);
if(word == 'y'){
int temp = 0;
printf("Enter an integer: ");
scanf("%d", &temp);
curr = (item *)malloc(sizeof(item));
curr->val = temp;
if (head == NULL){
head = curr;
head->next = NULL;
}
else {
curr->next = head;
head = curr;
}
}
}
curr = head;
while(curr != NULL) {
printf("%d\n", curr->val); //seg fault happens here
curr = curr->next ;
}
return 0;
}
This:
scanf("%s", &word);
is a buffer overflow, since %s will read a string, but you only have a single character. This invokes undefined behavior; even if you enter just a single character, scanf() will add 0-termination after that character to make a proper string.
Change the declaration of word:
char word[32];
And scan with an explicit size, to prevent scanf() from writing outside the buffer:
scanf("%30s", word);
Also check the return values of all I/O and memory allocation calls, since they can fail.
Finally, don't cast the return value of malloc(), in C.
Regarding the memory leaks, can I suggest you fix them with the following code:
while(curr != NULL) {
item* temp = curr; // store the current pointer
printf("%d\n", curr->val);
curr = curr->next ;
free(temp); //free the current one now that curr points to the next
}
This frees the already printed head in each iteration of the loop.
The other issues are already addressed by other posters.
Initialize the *head pointer as
item *curr=NULL, *head = NULL;
without this, the if will not execute and you would access some random memory for head node. The while loop for printing the linked list may not terminate and keep accessing invalid memory.
if (head == NULL){
...
}
You have been caught out by scanf. First you wish to read a single character and the format for that is %c - %s reads the next non-blank sequence of characters after skipping any leading whitespace. Using %s causes the error, as it overwrites memory.
However if you change the format to %c your code still won't work, and it's scanf again. For most formats scanf will skip leading whitespace, but it does not do this when reading characters. So if you run your code you will see this:
Would you like to enter an integer? (y/n) y
Enter an integer: 10
Would you like to enter an integer? (y/n) 10
The second time around scanf has read the newline after the 10 into word, that is not a y, and then moved on to print out your list - the 10 at the end.
To skip whitespace before a character you add a space into the format string, so the line becomes:
scanf(" %c", &word);
That one change will allow your code to work but you should really do more checking. scanf will return the number of items it successfully found, you should check that to make sure the user really did enter a number etc., etc. As an example here is what happens if the user accidentally enters y twice:
Would you like to enter an integer? (y/n) y
Enter an integer: y
Would you like to enter an integer? (y/n) Enter an integer:
What has happened here is scanf("%d", &temp) failed, returned 0, and stored nothing into temp. However as you did not check the result your program continues and then the second y is consumed by the next scanf(" %c", &word).
Also look at your if (head == NULL) statement - this is not really necessary at all, you can replace the whole if/else with just two lines... that is left as an exercise.
HTH

gets() does not read user input

I am new to linked list, now I have little problems in population of nodes.
Here I could populate first node of linked list but the gets() function doesn't seems to pause the execution to fill the next node.
Output is like:
Var name : var
Do you want to continue ?y
Var name : Do you want to continue ? // Here I cannot input second data
Here is my code:
struct data
{
char name[50];
struct data* next;
};
struct data* head=NULL;
struct data* current=NULL;
void CreateConfig()
{
head = malloc(sizeof(struct data));
head->next=NULL;
current = head;
char ch;
while(1)
{
printf("Var name : ");
gets(current->name); //Here is the problem,
printf("Do you want to continue ?");
ch=getchar();
if(ch=='n')
{
current->next=NULL;
break;
}
current->next= malloc(sizeof(struct data));
current=current->next;
}
}
This happens because:
ch=getchar();
read either y or n from the input and assigns to ch but there a newline in the input buffer which gets read by the gets in the next iteration.
To fix that you need to consume the newline following the y/n the user enters. To do that you can add another call to getchar() as:
ch=getchar(); // read user input
getchar(); // consume newline
Also the function fgets should be used in place of gets. Why?
It's exactly what #codaddict said. You need to clean the buffer.
void fflushstdin( void )
{
int c;
while( (c = fgetc( stdin )) != EOF && c != '\n' );
}
You can read this links that explains it very well:
c-faq
And this mdsn if you are on windows.
One more thing, try to always use fgets -instead of gets-, as it is impossible to prevent buffer overflows if you are using gets.
You could read the section "Use of safe libraries" at this link
you should also add a line like
current->next = 0;
after
current=current->next;
to ensure that the last element's next is not dangling.

Array of pointers implementation in C

Hii ,
I have been trying to write a program... We have a structure which has a rank field and the name field.The pointer to this structure is stored in an array of fixed size. I have implemented it as follows and i have certain problems...
The code i have written is :
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct
{
int rank;
char *name;
}node;
int insert(node **a , char name[] , int *rank)
{
if(*rank >= 5)
{
printf("\n Overflow ");
return 0;
}
(*rank)++;
node *new = (node *)malloc(sizeof(node));
new->name = name;
new->rank = *rank;
a[*rank] = new;
return 0;
}
int delete(node **a , int *rank)
{
int i = *rank;
if(*rank<0)
{
printf("\n No elements");
return 0;
}
printf("\n Deleting %d , %s ",((a[*rank]))->rank,((a[*rank]))->name);
printf("\n Reordering the elements ");
while(i<5)
{
a[i] = a[i+1];
}
return 0;
}
int display(node **a , int rank)
{
while(rank>0 && (a[rank])>0)
{
printf(" rank = %d name = %s \n",((a[rank])->rank),((a[rank])->name));
rank--;
}
return 0;
}
int main()
{
node *a[5] = {NULL};
char ch = 'y';
int choice,rank = -1;
char name[10];
while(ch!='n' || ch!= 'N')
{
printf("\n Enter 1 to insert , 2 to delete , 3 to display and 4 to exit \n");
scanf("%d",&choice);
switch(choice)
{
case 1:
printf("\n Enter name to insert");
gets(name);
insert(a,name,&rank);
break;
case 2:
printf("\n Enter rank to delete ");
scanf("%d",&rank);
delete(a,&rank);
break;
case 3:
display(a,rank);
break;
case 4:
exit(0);
default:
printf("\n Invalid choice...please enter again ");
break;
}
ch = getchar();
}
return 0;
}
First thing is the system automatically takes the choice except for the first time...(i couldn't find the fault there...) and i am a bit confused about this pointer stuff...Please see if its alright...Any corrections are welcome and please give me some explanation as to why it is wrong and how we shd do it...
Thank You
First of all, all your functions always return 0 -- even for an error condition. Life would be so much easier, if you passed rank in as an int, and returned it's new value.
rank = insert(a, name, rank);
/* : */
/* : */
int insert(node **a , char name[] , int rank)
{
if(rank >= 5)
{
printf("\n Overflow ");
return 0;
}
rank++;
node *new = (node *)malloc(sizeof(node));
new->name = name;
new->rank = rank;
a[rank] = new;
return rank;
}
It's been many years since I last used scanf, but as I recall, you must account for every character in the stream, meaning,"Don't forget the Enter".
scanf("%d\n",&choice);
Also with gets(name);, if you type more tha 9 characters, you are quite screwed, as it will overwrite the stack of your program.
UPDATE:
Also, you have two ways to exit this program, except one will never work. You could choose option "4" which will call exit(0). Alternately, at the end of each command, you wait for a character before stepping over. It appears you want to be able to enter "N" ther and exit, except that won't work:
while(ch!='n' || ch!= 'N')
for that to evaluate to false, ch must be both "n" & "N" at the same time. You really want
while(ch!='n' && ch!= 'N')
UPDATE2:
I just noticed the biggest problem in you code. name everywhere in your code only ever points to the single array defined in main(). Everytime you enter a new name, it overwrites that array, and since every node points to that one array, the name changes everywhere. You need to make a copy.
in insert():
node *new = (node *)malloc(sizeof(node));
new->name = strdup(name); // use malloc internally.
Then in delete() you'll have to free that memory (speaking of which, you need to free node there too...)
printf("\n Deleting %d , %s ",((a[*rank]))->rank,((a[*rank]))->name);
free(a[*rank]->name);
free(a[*rank]);
printf("\n Reordering the elements ");
Remember, Whenever you call malloc, you will eventually have to call free.
I'm confused as to the use of the "rank" variable. Main uses it as an index to the last node in the array, and the nodes use it as a ranking. Adding nodes increases it, but deleting nodes doesn't decrease it.
In the very least, I'd suggest separate the index variable from the ranking variable to make the logic easier to follow.
Personally, I'd write a structure to encapsulate the array with its own index tracking and add/delete functions. That way Main is free to read in user options and manipulate rank of new nodes without worrying about data structure details.
while(ch!='n' || ch!= 'N')
{
printf("\n Enter 1 to insert , 2 to delete , 3 to display and 4 to exit \n");
scanf("%d",&choice); getchar();
.
.
.
//ch = getchar();
}
Using getchar() along with scanf() causes this problem. Since '\n' after reading a character into 'ch' goes as an input to scanf. One way to resolve your problem is read that '\n' with an extra getchar() before it is read by gets().
Also you should modify while loop in delete.

Resources