C - While-Loop Duplicating Print Statements - c

When the while-loop runs after the first time, it prints my "Create new node" prompt twice before getting user input from stdin. Why is this? See linked image.
Code:
int main()
{
char userInput[2];
while(1)
{
printf("\nCreate new node? (y/n)\n");
printf(">>> ");
fgets(userInput, 2, stdin);
if(strcmp(userInput, "y") == 0)
{
printf("Yes\n");
}
else if(strcmp(userInput, "n") == 0)
{
printf("No\n");
exit(0);
}
}
}
Terminal Output:

fgets read string plus '\0' plus '\n'. Since userInput is of only 2 bytes, '\n' will not be read by fgets and will be there in the input buffer. On next iteration fgets will read '\n' left by the previous call of fgets.
Increase the buffer size and you will have no problem
char userInput[3];
or you can put
int ch;
while((ch = getchar()) != '\n' && ch != EOF);
just after fgets statement.

Related

Is there an elegant way to handle the '\n' that gets read by input functions (getchar(), fgets(), scanf()) in C?

I am trying a simple exercise from K&R to append string2 at the end of string1 using pointers. In case of overflow i.e. buffer of string1 can't contain all of string2 I want to prompt the user to re-enter string2 or exit.
I have written the following code:
#include<stdio.h>
#include<string.h>
#define MAXLINE 1000
int get_input(char *s);
int str_cat(char *s, char *t);
void main()
{
char input1[MAXLINE], input2[MAXLINE], c;
get_input(input1);
check:
get_input(input2);
if((strlen(input1) + strlen(input2) + 2) <= MAXLINE)
{
str_cat(input1, input2);
printf("%s\n", input1);
}
else
{
input2[0] = '\0';
printf("String overflow\n Press: \n 1: Re-enter string. \n 2: Exit.\n");
scanf(" %d", &c);
if(c == 1){
input2[0] = '\0';
get_input(input2);
goto check;
}
}
}
int get_input(char *arr)
{
int c;
printf("Enter the string: \n");
while(fgets(arr, MAXLINE, stdin))
{
break;
}
}
int str_cat(char *s, char *t)
{
while(*s != '\0')
{
s++;
}
while((*s++ = *t++) != '\0')
{
;
}
*s = '\0';
}
Initially, I was using the standard getchar() function mentioned in the book to read the input in get_input() which looked like this:
int get_input(char *arr)
{
int c;
printf("Enter the string: \n");
while((c = getchar()) != '\n' && c != EOF)
{
*arr++ = c;
}
*arr = '\0';
}
I am new and I read this and understood my mistake. I understand that one isn't supposed to use different input functions to read stdin and the '\n' is left in the input stream which is picked by the getchar() causing my condition to fail.
So, I decided to use fgets() to read the input and modified the scanf("%d", &c) as mentioned in the thread with scanf(" %d", c). This does work (kinda) but gives rise to behaviors that I do not want.
So, I have a few questions:
What's a better way to fgets() from reading the input on encountering '\n' than the one I have used?
while(fgets(arr, MAXLINE, stdin))
{
break;
}
fgets() stops reading the line and stores it as an input once it either encounters a '\n' or EOF. But, it ends up storing the '\n' at the end of the string. Is there a way to prevent this or do I have to over-write the '\n' manually?
Even though I used the modified version of scanf(" %d", &c), my output looks like
this: (https://imgur.com/a/RaC2Kc6). Despite that I get Enter the string: twice when prompted to re-enter the second string in case of an overflow situation. Is the modified scanf() messing with my input? And how do I correct it?
In general, do not mix fgets with scanf. Although it may be a bit bloaty, you will avoid many problems by being consistent with reading input with fgets and then parse it with sscanf. (Note the extra s)
A good way to remove the newline is buffer[strcspn(buffer, "\n")] = 0
Example:
// Read line and handle error if it occurs
if(!fgets(buffer, buffersize, stdin)) {
// Handle error
}
// Remove newline (if you want, not necessarily something you need)
buffer[strcspn(buffer, "\n")] = 0;
// Parse and handle error
int val;
if(sscanf(buffer, "%d", &val) != 1) {
// Handle error
}
// Now you can use the variable val
There is one thing here that might be dangerous in certain situations, and that is if buffer is not big enough to hold a complete line. fgets will not read more than buffersize characters. If the line is longer, the remaining part will be left in stdin.

How to detect last character in a C string when within a getchar() loop

Suppose I have the following which allows the entering in of text:
printf("Enter in your text\n");
while ((c=getchar()) != EOF) {
putchar(c);
if (last_char) // the last character before the user presses enter.
do_something();
}
Is there a way for me to detect if the character is the last one in the text input (without getting out of the loop)? Or is that not possible the current organization of things above?
Something list this?
printf("Enter in your text\n");
int c,last_char;
do
{
c = getchar();
if (c == '\n')
{
// it's the last char... do something with last_char
printf("\nThe last char was: %c\n", last_char);
}
last_char = c;
} while (c != EOF);
How about-
int c = 0;
while((c = getchar()) != EOF)
{
putchar(c);
// assuming that ';' is the character. you can change
// this to any acceptable character here
if(c == ';')
{
printf("\nYou entered ';' character\n");
// do something here
}
}
Is there a way for me to detect if the character is the last one in the text input (without getting out of the loop)?
No.
stdin is best thought of as a stream of data. Code cannot know beforehand if end-of-file or enter ('\n') will arrive
How to detect last character in a C string when within a getchar() loop
Instead detect when end-of-file occurs and operate on the previous character after the loop.
printf("Enter in your text\n");
int previous = EOF;
int c;
while ((c=getchar()) != EOF) {
previous = c;
}
do_something(previous);
If one needs the character before enter, while ((c=getchar()) != '\n' && c != EOF) { would suffice.

In C, why do I only need getchar() to remove characters sometimes?

I am trying to use getchar() to remove characters from the input buffer. In the following code, the user is asked to input a choice to select, and then depending on the choice, another input is required, either type int or type char (string).
In the int case, getcar() is not needed and scanf takes in input correctly. But in the char case, scanf fails to get input without using getchar() beforehand. Is there a reason why that is?
printf("Available Ciphers:\n1) Caesar Cipher\n2) Vigenere Cipher\nSelected Cipher: ");
if(scanf("%d", &choice) != 1){
printf("Error: Bad selection!\n");
exit(EXIT_SUCCESS);
} else if (choice != 1 && choice != 2){
printf("Error: Bad Selection!\n");
exit(EXIT_SUCCESS);
//If the choice entered is correct, then run the following.
} else {
if(choice == 1){
printf("Input key as nuumber: ");
if(scanf("%d", &caesarkey) != 1){ //Why is getchar() not needed here?
printf("Error: Bad Key!\n");
exit(EXIT_SUCCESS);
}
//morecode here
} else if (choice == 2){
printf("Input key as string: ");
while(getchar() != '\n'); //Why is this needed here?
/*Uses scanf and not fgets, since we do not want the
key to contain the newline character '\n'. This is
due to the fact that the newline character is not
considered in the function that encrypts and decrypts
plaintext and ciphertext.*/
if(scanf("%[^\n]s", vigencipherkey) != 1){
printf("Error, Cannot read inputted key!\n");
exit(EXIT_SUCCESS);
}
//More code here..
}
}
It seems that you are scanning for a string rather than an int, and as such, you are passing in an int rather than the address of an int.
Change this line
if(scanf("%[^\n]s", vigencipherkey) != 1){
To
if (scanf("%d", &vigencipherkey) != 1) {
In order to read the remainder of the line input by the user, you can use this function:
int flush_line(void) {
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
return c;
}
Notes:
c must be defined as int to accommodate for all values of the type unsigned char and the special negative value EOF.
you should test for '\n' and EOF otherwise you will have an endless loop on premature end of file without a trailing newline, such as would occur if you redirect the input of your program from an empty file.
you can test for end of file by comparing the return value of flush_line() with EOF.

want to insert multiple characters to a file in c(single at a time)

i have been trying to input characters and the character should be put in the file unless users change the value of opt to 'n'.
#include<stdio.h>
void main()
{
char ch,opt='y';
FILE *fp;
fp=fopen("myfile.txt","w");
while(opt=='y' || opt =='Y')
{ scanf("%c",&ch);
fputc(ch,fp);
printf("want to enter more characters(y or n):");
scanf("%c",&opt);
}
fclose(fp);
}
So I want to give the inputs until opt value changes to 'n'.
If you are using Windows OS then you can use following code to read characters without pressing Enter. See here and here to know about reading characters without pressing Enter on Linux plateforms.
#include<stdio.h>
#include<conio.h>
void main()
{
char ch,opt='y';
FILE *fp;
fp=fopen("myfile.txt","w");
while(opt=='y' || opt =='Y')
{
ch = getch();
fputc(ch,fp);
printf("%c\nWant to enter more characters(y or n):", ch);
opt = getch();
printf("%c\n", opt);
}
fclose(fp);
}
Note: You can modify the code if you don't need to print the last entered character. See here to know other variants of getch() function.
Let's say you type a and press Enter.
When you do that, there are two characters in the input stream: 'a' and '\n'. The first scanf reads the 'a' into ch and the second scanf reads the '\n' into opt. That is the source of your problem.
You'll have to write code to read and discard the newline character. Here's one way to do it.
while(opt=='y' || opt =='Y')
{
scanf("%c",&ch);
fputc(ch,fp);
// Assuming that no more than one characte is entered per line,
// read the discard the newline.
fgetc(stdin);
printf("want to enter more characters(y or n):");
scanf("%c", &opt);
// Read and discard the newline again.
fgetc(stdin);
}
If you want to be a bit more flexible about your input, you can use:
// Make it as large as you need it to be.
#define LINE_LENGTH 200
int main()
{
char line[LINE_LENGTH];
FILE *fp;
fp=fopen("myfile.txt","w");
// Read a line of text.
while( fgets(line, LINE_LENGTH, stdin) != NULL )
{
// Print the line to the output file
fputs(line, fp);
printf("want to enter more characters(y or n):");
// Read the entire line again.
if( fgets(line, LINE_LENGTH, stdin) != NULL )
{
// If the entire line is just "n" or "N", break from the loop.
if ( strcmp(line, "n\n") == 0 || strcmp(line, "N\n") == 0 )
{
break;
}
}
}
fclose(fp);
}

How can I catch an enter key ( '\n' )?

scanf("%s", input);
if (strlen(input) > 1) {
errorNet();
}
if (input[0] == '\n') {
errorNet();
}
if (input[0] == '\0') {
errorNet();
}
When I hit enter, scanf goes to the next line and continues searching for input. How can I set that if enter is hit, the function errorNet is called?
Ex. If enter/blank line is inputed, call errorNet function.
If you use fgetsyou specify the size of the string you are reading. fgets will stop reading the input when this size is reached or the user pressed \n. Notice that this size counts the \0 in the end of the string.
char input[10];
fgets(input, 10, stdin);
printf("%s\n", input);
To detect if a user just pressed \n without writing anything, just check if the first character is a \n, for example:
if (input[0] == '\n') {
printf("just '\\n'\n");
}

Resources