You are absolutely going to pull your hair out mixing numeric and character input with scanf
. getch
is a non-portable bandaid that puts the keyboard in raw unbuffered mode that helps mask the problem, so you will do yourself a BIG favor if you simply learn how to handle user input correctly from the beginning.
The major drawback with scanf
in taking mixed input is it leaves the '\n'
in the input buffer. If you are only scanning numeric input, no problem because the numeric conversions skip leading whitespace (including the '\n'
). However, the first time your ask for a character (e.g. 'y'
or 'Y'
) BAM, scanf
happily takes the '\n'
waiting in the input buffer as your input. Further, you can't tell if a number or character has been correctly read throughout your code because you never check the return for scanf
.
Rather than trying to duct-tape and bailing-wire your scanf
input routine together into a working form, just do user input right. Read each input with fgets
(which reads the '\n'
and solves the problem) and use sscanf
to parse the input. [1], e.g.
if (a == NULL) {
temp = malloc (sizeof *temp);
temp->next = NULL;
printf (" Enter Data: ");
/* do NOT mix character and numeric input with scanf UNLESS
* you know EXACTLY what your are doing.
*/
if (!fgets (buf, MAXC, stdin)) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
if (sscanf (buf, "%d", &temp->data) != 1) {
fprintf (stderr, "error: invalid conversion.\n");
return 1;
}
a = temp;
} ...
After your input is straightened out, you can concentrate on your logic errors with adding a value at the beginning of the list. As I pointed out in the comment, all that is needed is to create the new node, and set the ->next
pointer to the existing list, and then set the list-address to that of the new node, e.g.:
temp->next = a;
a = temp;
Putting all those pieces together, and remembering to track and free
the memory you have allocated, you could do something like the following with your code:
#include <stdio.h>
#include <stdlib.h>
#define MAXC 64 /* constant (macro define) to use for buffer length */
struct node {
int data;
struct node *next;
};
int main (void) /* main is type 'int' and returns a value */
{
char buf[MAXC] = ""; /* if taking numeric & char input use fgets */
struct node *a = NULL, *temp, *temp1;
// clrscr (); /* clrscr is non portable, only win has conio.h */
do {
if (a == NULL) {
temp = malloc (sizeof *temp);
temp->next = NULL;
printf (" Enter Data: ");
/* do NOT mix character and numeric input with scanf UNLESS
* you know EXACTLY what your are doing.
*/
if (!fgets (buf, MAXC, stdin)) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
if (sscanf (buf, "%d", &temp->data) != 1) {
fprintf (stderr, "error: invalid conversion.\n");
return 1;
}
a = temp;
} else {
temp = malloc (sizeof *temp);
temp->next = NULL;
printf (" Enter data element: ");
if (!fgets (buf, MAXC, stdin)) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
if (sscanf (buf, "%d", &temp->data) != 1) {
fprintf (stderr, "error: invalid conversion.\n");
return 1;
}
temp1 = a;
while (temp1->next != NULL) {
temp1 = temp1->next;
}
temp1->next = temp;
}
printf (" Do You Wish to continue (y/n)?: ");
if (!fgets (buf, MAXC, stdin)) {
fprintf (stderr, "error: invalid entry.\n");
return 1;
}
// ch = getch (); /* getch is non-portable */
} while (*buf == 'y' || *buf == 'Y');
printf (" Do You Wish To See More Link List Operations (y/n)? ");
if (!fgets (buf, MAXC, stdin)) {
fprintf (stderr, "error: invalid entry.\n");
return 1;
}
if (*buf == 'y' || *buf != 'Y') {
printf (" Press 1 For inserting node at the beginning of the list: ");
if (!fgets (buf, MAXC, stdin)) {
fprintf (stderr, "error: invalid entry.\n");
return 1;
}
switch (*buf) {
case '1' : temp = malloc (sizeof *temp);
printf (" Enter first data element: ");
if (!fgets (buf, MAXC, stdin)) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
if (sscanf (buf, "%d", &temp->data) != 1) {
fprintf (stderr, "error: invalid conversion.\n");
return 1;
}
temp->next = a;
a = temp;
break;
default : fprintf (stderr, "error: invalid selection.\n");
}
}
printf ("\nStatus of the link list\n");
temp1 = a;
while (temp1 != NULL) {
printf (" %d ", temp1->data);
temp1 = temp1->next;
}
putchar ('\n');
// getch (); /* use getchar, getch is non-portable */
temp = a;
while (temp) { /* free the memory you have allocated */
struct node *victim = temp;
temp = temp->next;
free (victim);
}
return 0;
}
Example Use/Output
$ ./bin/lldisplay
Enter Data: 2
Do You Wish to continue (y/n)?: y
Enter data element: 3
Do You Wish to continue (y/n)?: y
Enter data element: 4
Do You Wish to continue (y/n)?: y
Enter data element: 5
Do You Wish to continue (y/n)?: n
Do You Wish To See More Link List Operations (y/n)? y
Press 1 For inserting node at the beginning of the list: 1
Enter first data element: 1
Status of the link list
1 2 3 4 5
Look things over and make sure you understand it, and let me know if you have any questions.
footnotes:
1. you are not limited to only sscanf
when parsing the line of text read as user-input, you can simply walk a pointer (or pair of pointers) down the string manually testing/parsing any combination of values you need. You can also use a pointer and walk the strtoX
(e.g. strtol
, strtoul
, ...) functions down the line parsing numeric input as well (see man strtol and pay attention to the **endptr
parameter). The key in the fgets
/(then parse) approach is you decouple your read of input from the parsing of data allowing you to both (1) validate your read, and then also (2) validate your data rather than trying to do it all in one scanf
call. There are uses for scanf
, but taking alternating mixed character and numeric user-input isn't one of the recommended ones.