Problems with character input using scanf() - c

I'm trying to input a character into a linked list, where the character can be 'A','a','G','g','T','t','C' or 'c'.
I'm not yet familiar with C and I know I've screwed something up here:
do{
printf ("\nEnter a new nucleotide: \n");
scanf("%c",&newChar);
/* Checking */
if(newChar == 'A' ||
newChar == 'a' ||
newChar == 'G' ||
newChar == 'g' ||
newChar == 'T' ||
newChar == 't' ||
newChar == 'C' ||
newChar == 'c' )
{
AddToSequence(newChar);
size++;
} else {
printf ("\nBad Element");
}
}while(newChar != 'x');
newChar is initialized with a junk value, in this case 'q'.
Entering 'x' exits the loop, entering any acceptable value calls AddToSequence(), and any unacceptable value gets a warning.
For some reason, no matter what value is in newChar, it will jump to the else. It will also jump straight past the scanf without waiting for entry from the user and do two loops every time it loops. Can anyone tell me where I'm going wrong?
Full program:
#include<stdio.h>
#include<stdlib.h>
/*Structure declaration for the node*/
struct node{
char nucleotide;
struct node *point;
}*start;
/* Adds a nucleotide to the chain. Creates a new linked list if no chain exists exists.*/
void AddToSequence(char nucleotide){
struct node *loc, *first;
//Dynamic memory is been allocated for a node
first=(struct node*)malloc(sizeof(struct node));
first->nucleotide=nucleotide;
first->point=NULL;
if(start==NULL){
/*If list is empty*/
start=first;
}else{
/*Element inserted at the end*/
loc=start;
while(loc->point!=NULL){
loc=loc->point;
loc->point=first;
}
}
}
/* Display elements */
void Display(){
struct node *loc;
if(start == NULL){
printf ("\n\nList is empty");
return;
}
loc=start;
printf("\n\nList is : ");
while(loc!=NULL){
printf ("%c", loc->nucleotide);
loc=loc->point;
}
printf ("\n");
}
/* Finds and displays percentage of the chain made up of each nucleotide. */
void Percentage(int size){
struct node *loc;
if(start == NULL){
printf ("\n\nList is empty");
return;
}
loc=start;
printf("\n\nList is : ");
int A = 0, G =0, T =0, C = 0;
double Adouble = 0, Gdouble =0, Tdouble=0, Cdouble=0;
while(loc!=NULL){
if(loc->nucleotide=='A' || 'a'){A++;}
if(loc->nucleotide=='G' || 'g'){G++;}
if(loc->nucleotide=='T' || 't'){T++;}
if(loc->nucleotide=='C' || 'c'){C++;}
loc=loc->point;
}
printf ("\n");
/* Convert to double for percentages as int loses precision */
Adouble =A;
Gdouble =G;
Tdouble =T;
Cdouble =C;
Adouble =(Adouble/size)*100;
Gdouble =(Gdouble/size)*100;
Tdouble =(Tdouble/size)*100;
Cdouble =(Cdouble/size)*100;
printf("\nA: %f", Adouble);
printf("\nG: %f", Gdouble);
printf("\nT: %f", Tdouble);
printf("\nC: %f", Cdouble);
}
/* There be dragons beyond here */
int main(){
int navigate, size =0;
char newChar = 'q';
do{ /* Menu */
printf("\n 1. Create / Extend Sequence\n");
printf("\n 2. Display Sequence\n");
printf("\n 3. Count \n");
printf("\n 0. Exit \n");
printf("\nPlease select an option (0 to 3)\n");
scanf("%d",&navigate);
switch (navigate){
case 0: /* Exit */
break;
case 1: /* Add nucleotides */
do{
printf ("\nEnter a new nucleotide: \n");
scanf("%c",&newChar);
/* Some error checking */
if(newChar == 'A' || newChar == 'a' || newChar == 'G' || newChar == 'g' || newChar == 'T' || newChar == 't' || newChar == 'C' || newChar == 'c' ){
AddToSequence(newChar);
size++;
} else {
printf ("\nBad Element");
}
}while(newChar != 'x');
break;
case 2:
Display();
break;
case 3:
Percentage(size);
break;
default:
printf ("\n\nBad choice. Please select another.\n");
}
} while (navigate !=0);
return 0 ;
}

You don't handle the newline. The %c specifier doesn't skip blanks. Try:
scanf(" %c", &newChar);
/* ^ <-- Makes `scanf` eat the newline. */
Or maybe add an explicit test.
scanf(...);
if (newChar == '\n')
continue;

add space to "%c" to catch the newline character. the space charcter is used to catch space characters, tabulations, newline
scanf("%c ",&newChar);

You're leaving the '\n' on stdin:
scanf("%d",&navigate);
getchar(); // consume the newline character
...
scanf("%c",&newChar);
getchar(); // consume the newline character
Or since you're already using scanf() you can tell scanf itself to take care of the newline character:
scanf("%d\n", &navigate);
....
scanf("%c\n",&newChar);
Even better you can leave it open by adding a space after the format specificer:
scanf("%d ", &navigate);
....
scanf("%c ",&newChar);
Just in case the user wants to do something like: 2<tab key><enter key>
Regardless of how you handle it, the point is you need to consume the newline character.

Use
newChar=getche();
This is a nonstandard function that gets a character from the keyboard, echoes to screen.

Related

Switch case inside loop (for or while) in C [duplicate]

I'm trying to input a character into a linked list, where the character can be 'A','a','G','g','T','t','C' or 'c'.
I'm not yet familiar with C and I know I've screwed something up here:
do{
printf ("\nEnter a new nucleotide: \n");
scanf("%c",&newChar);
/* Checking */
if(newChar == 'A' ||
newChar == 'a' ||
newChar == 'G' ||
newChar == 'g' ||
newChar == 'T' ||
newChar == 't' ||
newChar == 'C' ||
newChar == 'c' )
{
AddToSequence(newChar);
size++;
} else {
printf ("\nBad Element");
}
}while(newChar != 'x');
newChar is initialized with a junk value, in this case 'q'.
Entering 'x' exits the loop, entering any acceptable value calls AddToSequence(), and any unacceptable value gets a warning.
For some reason, no matter what value is in newChar, it will jump to the else. It will also jump straight past the scanf without waiting for entry from the user and do two loops every time it loops. Can anyone tell me where I'm going wrong?
Full program:
#include<stdio.h>
#include<stdlib.h>
/*Structure declaration for the node*/
struct node{
char nucleotide;
struct node *point;
}*start;
/* Adds a nucleotide to the chain. Creates a new linked list if no chain exists exists.*/
void AddToSequence(char nucleotide){
struct node *loc, *first;
//Dynamic memory is been allocated for a node
first=(struct node*)malloc(sizeof(struct node));
first->nucleotide=nucleotide;
first->point=NULL;
if(start==NULL){
/*If list is empty*/
start=first;
}else{
/*Element inserted at the end*/
loc=start;
while(loc->point!=NULL){
loc=loc->point;
loc->point=first;
}
}
}
/* Display elements */
void Display(){
struct node *loc;
if(start == NULL){
printf ("\n\nList is empty");
return;
}
loc=start;
printf("\n\nList is : ");
while(loc!=NULL){
printf ("%c", loc->nucleotide);
loc=loc->point;
}
printf ("\n");
}
/* Finds and displays percentage of the chain made up of each nucleotide. */
void Percentage(int size){
struct node *loc;
if(start == NULL){
printf ("\n\nList is empty");
return;
}
loc=start;
printf("\n\nList is : ");
int A = 0, G =0, T =0, C = 0;
double Adouble = 0, Gdouble =0, Tdouble=0, Cdouble=0;
while(loc!=NULL){
if(loc->nucleotide=='A' || 'a'){A++;}
if(loc->nucleotide=='G' || 'g'){G++;}
if(loc->nucleotide=='T' || 't'){T++;}
if(loc->nucleotide=='C' || 'c'){C++;}
loc=loc->point;
}
printf ("\n");
/* Convert to double for percentages as int loses precision */
Adouble =A;
Gdouble =G;
Tdouble =T;
Cdouble =C;
Adouble =(Adouble/size)*100;
Gdouble =(Gdouble/size)*100;
Tdouble =(Tdouble/size)*100;
Cdouble =(Cdouble/size)*100;
printf("\nA: %f", Adouble);
printf("\nG: %f", Gdouble);
printf("\nT: %f", Tdouble);
printf("\nC: %f", Cdouble);
}
/* There be dragons beyond here */
int main(){
int navigate, size =0;
char newChar = 'q';
do{ /* Menu */
printf("\n 1. Create / Extend Sequence\n");
printf("\n 2. Display Sequence\n");
printf("\n 3. Count \n");
printf("\n 0. Exit \n");
printf("\nPlease select an option (0 to 3)\n");
scanf("%d",&navigate);
switch (navigate){
case 0: /* Exit */
break;
case 1: /* Add nucleotides */
do{
printf ("\nEnter a new nucleotide: \n");
scanf("%c",&newChar);
/* Some error checking */
if(newChar == 'A' || newChar == 'a' || newChar == 'G' || newChar == 'g' || newChar == 'T' || newChar == 't' || newChar == 'C' || newChar == 'c' ){
AddToSequence(newChar);
size++;
} else {
printf ("\nBad Element");
}
}while(newChar != 'x');
break;
case 2:
Display();
break;
case 3:
Percentage(size);
break;
default:
printf ("\n\nBad choice. Please select another.\n");
}
} while (navigate !=0);
return 0 ;
}
You don't handle the newline. The %c specifier doesn't skip blanks. Try:
scanf(" %c", &newChar);
/* ^ <-- Makes `scanf` eat the newline. */
Or maybe add an explicit test.
scanf(...);
if (newChar == '\n')
continue;
add space to "%c" to catch the newline character. the space charcter is used to catch space characters, tabulations, newline
scanf("%c ",&newChar);
You're leaving the '\n' on stdin:
scanf("%d",&navigate);
getchar(); // consume the newline character
...
scanf("%c",&newChar);
getchar(); // consume the newline character
Or since you're already using scanf() you can tell scanf itself to take care of the newline character:
scanf("%d\n", &navigate);
....
scanf("%c\n",&newChar);
Even better you can leave it open by adding a space after the format specificer:
scanf("%d ", &navigate);
....
scanf("%c ",&newChar);
Just in case the user wants to do something like: 2<tab key><enter key>
Regardless of how you handle it, the point is you need to consume the newline character.
Use
newChar=getche();
This is a nonstandard function that gets a character from the keyboard, echoes to screen.

Is there a way of limiting scanf in C?

I am trying to write a correct console application for linked list usage, so i need to scan a number of a command in a infinite loop and do something due to switch case option. So i am using scanf for this but the problem is when the next line doesnt contain number it loops and starts printing not even default value.
`while(1)
{
printf("Enter a number of a command.\n");
scanf("%d",&command);
switch(command)
{
case -1:
....
default:
printf("Reenter command.\n");
break;
}
}
It seems like when i am reading the infinite amount of data stack gets rewrited. I know i have to limit the amount of symbols reading, but dont understand how to do this in right way.
Using gcc version 5.4.0 (GCC), c99 on Ubuntu 18.04.2 LTS
I don't have enough reputation to comment, but this might be what you are looking for. Also try to be more descriptive. I have pasted your code and the only problem I could find is that when you press enter without inserting a number(i.e. a letter) it skips. This should fix it:
int readInt(const char *message, int min, int max){
int num, control;
do{
printf("%s (%d a %d) :", message, min, max);
control = scanf ("%d", &num);
cleanBufferStdin();
if (control == 0)
{
printf("You should enter a number \n");
}
else{
if(num<min || num>max)
{
printf("Number is invalid.\n");
}
}
}
while(num<min || num>max || control ==0);
return num;
}
void cleanBufferStdin(void)
{
char chr;
do
{
chr = getchar();
}
while (chr != '\n' && chr != EOF);
}
I coded for a bit more, and in another interpretation of your question(this one not only detects if you just pressed enter but if you didnt place an integer i didnt check if negative numbers work) I used this function:
//DONT FORGET TO #DEFINE WRONG_REQUEST_MACRO "SOME MESSAGE"
void readString(const char message*, char arrayChars *, int maxChars){
int stringSize;
unsigned char flag=0;
do{
flag =0;
printf("%s", message);
fgets(arrayChars, maxChars, stdin);
stringSize = strlen(arrayChars);
if (stringSize == 1){
printf("[INFO]Empty request. You just pressed ENTER.\n");
flag=1;
}
if (atoi(arrayChars)==0&&arrayChars[0]!=0){
printf("[INFO]You didn't enter a number.\n");
flag=1;
}
} while (flag == 1);
if (arrayChars[stringSize - 1] != '\n'){
clearBuffer();
}else{
arrayChars[stringSize - 1] = '\0';
}
while (strchr(arrayChars, '\'') != NULL || strchr(arrayChars, '?') != NULL || strchr(arrayChars, '*') != NULL || strchr(arrayChars, '\"') != NULL){
printf("%s ' %s '", WRONG_REQUEST_MACRO, arrayChars);
break;
}
}
this should be used like
int command;
char message[20];//yes this could be used with a char pointer but lets assume op doesnt know how to allocate memory or work with char pointers it wouldn't change that much but if he does know how to do it he will promptly change
readString("something something i suppose\n",message,20);
command=atoi(message);
Welp the last although its filled with debugging "duplicates" should work

Missed scanf and function goes on without it. If I add a space still doesn't work

#include <stdio.h>
struct mychar {
char value;
struct mychar *nextPtr;
};
typedef struct mychar Mychar;
void instructions();
void append(Mychar **, char );
void printlist(Mychar *);
int main(){
instructions();
Mychar *startPtr = NULL;
unsigned int choice;
char newchar;
do {
scanf("%d",&choice);
switch (choice) {
case 1:
printf("\nWrite the character you want to add.");
printf("\n> ");
scanf(" %c", &newchar);
append(&startPtr, newchar);
printlist(startPtr);
break;
case 2:
break;
default:
printf("\nError, try again.\n");
//main();
instructions();
break;
}
} while (choice!=3);
printf("\n\nEnd of run.\n");
}
void instructions(){
printf("\nSelect operation. 1 to add, 2 to remove, 3 to exit.");
printf("\n> ");
}
void append(Mychar **sPtr, char newvalue){
Mychar *newlinkPtr = calloc (1, sizeof(Mychar));
newlinkPtr->value = newvalue;
newlinkPtr->nextPtr = NULL;
Mychar *previousPtr = NULL;
Mychar *currentPtr = *sPtr;
while(currentPtr!=NULL && newvalue > currentPtr->value){
previousPtr = currentPtr;
currentPtr = currentPtr->nextPtr;
}
if (previousPtr){
previousPtr->nextPtr = newlinkPtr;
newlinkPtr->nextPtr = currentPtr;
} else {
*sPtr = newlinkPtr;
}
}
void printlist(Mychar *currentPtr){
printf("\n\nCurrent list:\n");
while (currentPtr!=NULL){
printf("%c", currentPtr->value);
currentPtr = currentPtr->nextPtr;
}
}
Why do I have this behaviour? If I run the program, after I enter 1, it prints the "current list" and leave the scanf input opened, so I can enter the value only after "current list" printed. Also, "current list" should be called only after I enter the character with scanf, since the function printlist is AFTER the scanf... but actually this is what happens:
Select operation. 1 to add, 2 to remove, 3 to exit.
> 1
Write the character you want to add.
> a
Current list:
ab
Write the character you want to add.
>
Current list:
abc
Write the character you want to add.
>
Current list:
abcd
Write the character you want to add.
>
Current list:
abcd
The lesson to take form this is to always check scanf for 0 return, at the very least, EOF check is also advised, and act accordingly, as for the order of events of your code, it's not quite there, with some tweaks you can have a nice, bad input proof, I/O sequence:
void clear_stdin() { //stdin buffer clearing function
int c;
while ((c = getchar()) != '\n' && c != EOF){}
}
do {
instructions(); //move inside the loop, user will be prompted in each cycle
while (scanf("%d", &choice) == 0) {
printf("\nError, try again.\n");
instructions();
clear_stdin(); // if input fails clear the buffer
}
clear_stdin(); // clear the buffer for 1hjh type input
switch (choice) {
case 1:
printf("\nWrite the character you want to add.");
printf("\n> ");
while (scanf(" %c", &newchar) == 0) { //this can be a pattern
clear_stdin(); //see #ismick comment
} //
clear_stdin(); //
append(&startPtr, newchar);
printlist(startPtr);
break;
case 2:
break;
case 3:
printf("\n\nEnd of run.\n"); //if you dont have a case default will catch 3
break;
default:
printf("\nError, try again.\n");
break;
}
} while (choice != 3);

loop not working in my c code

Below is my c code and the forever for(;;) loop is not breaking out base on the condition i have given it using an if statement. Is there something am doing wrong? my codes are as below:
#include <stdio.h>
main()
{
/*
* Program starts
*/
int tracks; /* tracks is declared as a variable for the number of tracks */
float price; /* Price is declared as variable for number of tracks */
char title[100]; /* title is declared as a varibel for the title of thr CD*/
char album_single[2]; /* album_single is a variable declared for either the CD is a single or an album */
char artiste[50];
printf("Welcome to the CD database\n\n");
printf("Please enter the details of the CD below...\n");
/*
* First, title
*/
printf("Title? ");
scanf("%[^\n]", title);
/*
* Next, Artiste
*/
printf("Artiste? ");
fflush(stdin);
scanf("%[^\n]", artiste);
/*
* Next, number of tracks
*/
printf("Number of Tracks? ");
fflush(stdin);
scanf("%d",&tracks);
/*
* Next, Type(album or single)
*/
for(; ;)
{
printf("ALbum or a single (Enter 'a' for an album and 's' for a single): ");
fflush(stdin);
scanf("%c", &album_single);
if(album_single == "a" || album_single == "s")
break;
printf("Error!\n");
}
/*
* Conditions to assign the right type(album/single) to the variable album_single
*/
if(strcmp(album_single, "a") == 0)
{
strcpy(album_single,"Album");
}
else
{
if(strcmp(album_single, "s") == 0)
strcpy(album_single, "single");
}
/*
* Finally, Price
*/
printf("Retail Price(e.g $4.66)? ");
fflush(stdin);
scanf("%f", &price);
/*
* Details, finallly output
*/
printf("\n\nDetails of %s's CD\n", title);
printf("========================\n");
printf("Title: %s\n",title);
printf("Artiste: %s\n", artiste);
printf("Number of tracks: %d\n",tracks);
printf("Album/Single: %s\n", album_single);
printf("Price:$ %.2f\n", price);
printf("========================\n");
/*
* User Friendly exit of the program
*/
printf("\n Press ENTER to exit the program.");
/*
* Program end
*/
fflush(stdin);
getchar();
}
Below is the part of the forever for(;;) loop which is not breaking out:
for(; ;)
{
printf("ALbum or a single (Enter 'a' for an album and 's' for a single): ");
fflush(stdin);
scanf("%c", &album_single);
if(album_single == "a" || album_single == "s")
break;
printf("Error!\n");
}
This loop keep on looping even if the input is 'a' or 's'. what am i doing wrong in this codes ?
Try this:
char album_single;
while (album_single != 'a' && album_single != 's')
{
printf("Album or a single (Enter 'a' for an album and 's' for a single): ");
scanf("%c", &album_single);
scanf("%c"); // discard carriage return
}
Experiment commenting out the last scanf() statement, see what happens.
this code solved the question using the strcmp() function in the comparison instead of the ==.
correct code
if(strcmp(album_single, "a") == 0 || strcmp(album_single, "s") == 0 )
wrong code
if(album_single == "a" || album_single == "s")
thanks for ur contribution guys .!!
You can not compare strings using == operator. Either declare album_single as a character, or use strcmp() function.
if(strcmp(album_single, "a")==0||strcmp(album_single, "s")==0) break;
Remember to include the correct header file.

Can't detect the end of input strings

This is to perform function of a phone book getting names and their phone number. For requested names it must print their phone number. The last out line prints infinitely for I cannot detect the end of input. I have used \n, ' ' and, " ", but nothing works. HELP!
#include <stdio.h>
struct ph_book{
char name[100000];
double ph;
}p[20];
int main() {
char temp[100000],ex[100000];
int n,i,flag=0;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%s",p[i].name) ;
scanf("%lf",&p[i].ph);
}
scanf("%s",temp);
while(temp[0]!='\n'){
flag=0;
for(i=0;i<n;i++){
if(strcmp(temp,p[i].name)==0){
printf("%s=%.lf\n",p[i].name,p[i].ph);
flag=1;
break;
}
}
if (flag==0){
printf("Not found\n");
}
strcpy(ex,temp);
scanf("%s",temp);
if (strcmp (temp, "\n") == 0)
break;
}
return 0;
}/* Enter your code here. Read input from STDIN. Print output to STDOUT */
The "\n" is not part of the input string of scanf function.
The following code will not enter the break (conditions is always be FALSE).
if (strcmp (temp, "\n") == 0)
break;
If you wish to terminate input by empty string (when user press enter),
The following should work:
Replace scanf with gets (or better use the safe version: gets_s).
Compare temp[0] to zero, for detecting end of input sequence.
Sample code:
gets_s(temp, sizeof(temp)); //Instead of scanf("%s",temp);
while (temp[0] != 0)
{
strcpy(ex, temp);
gets_s(temp, sizeof(temp)); //Instead of scanf("%s",temp);
if (temp[0] == 0)
break;
}

Resources