scanf and no switch case is executed - c

New bee in C. This is my code (It replaces a character from a string):
#include <stdio.h>
#include <string.h>
#include <conio.h>
void main()
{
char str[100], r, ra;
printf("enter string");
gets(str);
int length;
length= strlen(str);
printf("length of string is %d",length);
printf("\nenter the the character that will replace");
scanf("%c",&r);
printf("where to replace\n b...begning\ne....ending\np....position");
scanf("%c",&ra);
int pos;
switch(ra)
{
case 'b' : str[1]=r; break;
case 'e' : str[length-1] = r; break;
case 'p' : printf("enter position");
scanf("%d",pos);
if(pos<1 || pos>length-1)
printf("please enter a position between 1 and %d",length-1);
else
str[pos]= r;
break;
}
printf("\n after replacing string is %s", str);
getche();
}
The problem is that the IDE is not compiling this part of the program, I know that I am doing some thing wrong, but can't figure out what? Need help please.
scanf("%c",&ra);
int pos;
switch(ra)
{
case 'b' : str[1]=r; break;
case 'e' : str[length-1] = r; break;
case 'p' : printf("enter position");
scanf("%d",pos);
if(pos<1 || pos>length-1)
printf("please enter a position between 1 and %d",length-1);
else
str[pos]= r;
break;
}

use scanf(" %c",&ra) insted of "%c". Because reading with "%c" give you a garbage value in ra.And that value is new line.
When you enter value in a you press something like p and then Enter key. This Enter key still remains in stdin stream.
Next time when you read in ra then the Enter key in stdin stream is returned in ra.
So for removing that Enter key you need to read like " %c".

scanf(" %c", &ra); // space before %c
Unlike most conversions, %c does not skip whitespace before converting a character. After the user enters the number, a carriage return/new-line is left in the input buffer waiting to be read -- so that's what the %c reads.. SO POST
And for the same reason your switch case is not working, since ra does not have the expected value

the problem is that the ide is not compiling this part of the program
Well, that's a strong accusation. Rather than assume that the compiler does decide not to compile part of the code (on a whim), it's a safer bet that your program's execution flow just does not enter that part as you expected.
In particular, scanf does not behave as you think it does. It reads from stdin, which is a buffered input stream. "Buffered" means that it does not provide your program with input until a newline in read, i.e. until the user presses return. But the scanf family of functions doesn't look for new lines, it treats the new-line character as a normal character. In your case, scanning "%c" tries to read any character from the input. The subsequent "%c" then reads the new line, so &ra really is '\n' in your switch statement.
I usually find working with direct input from the user difficult in C, but if you must prompt the user interactively, I suggest that you read in a whole line of input first with fgets and then analyse that line with sscanf. That gets rid of the seemingly out-of-sync input and also allows you to scan a line several times, perhaps for alternative input syntaxes.
So, here's a version of your code that uses this technique:
#include <stdio.h>
#include <string.h>
int main()
{
char str[100], r, ra;
char line[20];
int length;
int pos;
printf("enter string");
fgets(str, 100, stdin); // note: str includes trailing newline
length = strlen(str);
printf("length of string is %d\n", length);
printf("enter the the character that will replace:\n");
fgets(line, 20, stdin);
sscanf(line, " %c ",&r);
printf("where to replace\n");
printf("b...begning\ne....ending\np....position\n");
fgets(line, 20, stdin);
sscanf(line, " %c ", &ra);
switch (ra)
{
case 'b': str[1] = r;
break;
case 'e': str[length - 1] = r;
break;
case 'p': printf("enter position");
fgets(line, 20, stdin);
sscanf(line, "%d ", &pos);
if(pos < 1 || pos > length-1)
printf("please enter a position between 1 and %d",
length-1);
else
str[pos]= r; break;
}
printf("after replacing string is %s", str);
return 0;
}
There are still problems with your code, mainly to do with zero-based array indexing in C. I leave it to you to sort those out. Also, prefer the safer fgets(buf, len, stdin) over gets(str), which does not prevent buffer overflow. And your query for a position should take a pointer to the address of pos, not just pos. And please make a habit of putting the new-line character last in your printf strings. It makes for cleaner reading and matches the way that the buffered output stream works.

The program doesn't compile, the most likely reason is that you are using a compiler that supports C89 only (I guess it's Visual Studio), or you are using C89 mode.
In this code:
scanf("%c",&ra);
int pos;
switch(ra)
{
the variable pos is defined in the middle of a block, which is supported only since C99. The solution is to move all definitions up to the beginning of a block:
int main()
{
char str[100], r, ra;
int pos;
printf("enter string");
Use fgets() to replace gets(), use int main to replace void main. And fix the problem with using scanf that is covered by the other answers.

Related

C language - Menu issue with multiple void statements and do-switch-case

I am trying to make a menu with the options to compress a text inputted by the user and then store that value to be extracted in the extract menu option.
The issue lies in that it seems like the code isn't following the void statements, for example
case 1: compress();//compress statement
It seems to only get the printf statement in the void compress(void) and not the scanf, which it then follows with the loop of the menu.
Any solutions?
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
void menu(void);
void compress(void);
void extract(void);
int main(void)
{
menu();
return 0;
}
void menu(void)
{
int choice;
do
{
printf("Menu\n\n");
printf("1. Compress Text\n");
printf("2. Extract Text\n");
printf("3. Exit\n");
scanf_s("%d", &choice);
switch (choice)
{
case 1: compress();//compress statement
break;
case 2: extract();//extract statement
break;
case 3: printf("Ciao\n");
exit(0);
break;
default: printf("Invalid Entry. Try again\n");
break;
}
} while (choice != 3);
}
void compress(void) {
printf("\n-------------------------\n");
printf(" COMPRESS ");
printf("\n-------------------------\n");
printf("\nPlease enter a word/sentence to be compressed:\n");
char txt[200];
scanf_s("%c", &txt);
printf("\nYour word/sentence is %c", txt, "\n");
char comp = strlen(txt);
int mask[200]{};
for (int i = 0; i < comp; ++i) //loop until all leters are masked
{
mask[i] = i + 127;
printf("\nYour compressed word/sentence is %c ", mask[i]);
}
return;
}
void extract(void) {
printf("\n-------------------------\n");
printf(" EXTRACT ");
printf("\n-------------------------\n");
return;
}
You are scanning only one single character, and as "%c" doesn't skip white-space this is the newline character terminating the previous input.
You instead want to read in a string, and to be on the safe side you should add the maximum length to read to: "%199s" (note: one less than array size to leave space for the terminating null character):
scanf_s("%199s", txt);
Note, too, that as txt is an array it decays to a pointer automatically when being passed to a function (see above); taking the address of (&txt) produces a pointer with the same value, but of a different type: char(*)[200]. This pointer is not compatible to neither %c nor %s format specifier, thus you actually produce *undefined behaviour!
Note, too, that scanf_s (any function from scanf family) will stop reading at the first whitespace – a sentence might, though contain multiple words separated by whitespace. You'd just read the first one of them, though. So you might want to drop scanf for this input entirely in favour of e.g. fgets:
fgets(txt, sizeof(txt), stdin);
Note, here, too, that the previous scanf("%d", ...) did not consume the terminating newline, so you'll need to ignore that, e.g. by a preceding call to getchar.
Crediting this last point to Jonathan Leffler who hinted to in his comment to the question)

Issues with scanf() and accepting user input

I am trying to take in user input with spaces and store it in an array of characters.
After, I want to take in a single character value and store it as a char.
However, when I run my code, the prompt for the character gets ignored and a space is populated instead. How can I take in an array of chars and still be allowed to prompt for a single character after?
void main()
{
char userIn[30];
char findChar;
printf("Please enter a string: ");
scanf("%[^\n]s", userIn);
printf("Please enter a character to search for: ");
scanf("%c", &findChar);
//this was put here to see why my single char wasnt working in a function I had
printf("%c", findChar);
}
scanf("%c", &findChar); reads the next character pending in the input stream. This character will be the newline entered by the user that stopped the previous conversion, so findChar will be set to the value '\n', without waiting for any user input and printf will output this newline without any other visible effect.
Modify the call as scanf(" %c", &findChar) to ignore pending white space and get the next character from the user, or more reliably write a loop to read the read and ignore of the input line.
Note also that scanf("%[^\n]s", userIn); is incorrect:
scanf() may store bytes beyond the end of userIn if the user types more than 29 bytes of input.
the s after the ] is a bug, the conversion format for character classes is not a variation of the %s conversion.
Other problems:
void is not a proper type for the return value of the main() function.
the <stdio.h> header is required for this code.
Here is a modified version:
#include <stdio.h>
int main() {
char userIn[30];
int c;
char findChar;
int i, found;
printf("Please enter a string: ");
if (scanf("%29[^\n]", userIn) != 1) {
fprintf(stderr, "Input failure\n");
return 1;
}
/* read and ignore the rest of input line */
while ((c = getchar()) != EOF && c != '\n')
continue;
printf("Please enter a character to search for: ");
if (scanf("%c", &findChar) != 1) {
fprintf(stderr, "Input failure\n");
return 1;
}
printf("Searching for '%c'\n", findChar);
found = 0;
for (i = 0; userIn[i] != '\0'; i++) {
if (userIn[i] == findChar) {
found++;
printf("found '%c' at offset %d\n", c, i);
}
}
if (!found) {
printf("character '%c' not found\n", c);
}
return 0;
}
scanf("%[^\n]s", userIn); is a bit weird. The s is guaranteed not to match, since that character will always be \n. Also, you should use a width modifier to avoid a buffer overflow. Use scanf("%29[^\n]", userIn); That alone will not solve the problem, since the next scanf is going to consume the newline. There are a few options. You could consume the newline in the first scanf with:
scanf("%29[^\n]%*c", userIn);
or discard all whitespace in the next call with
scanf(" %c", &findChar);
The behavior will differ on lines of input that exceed 29 characters in length or when the user attempts to assign whitespace to findChar, so which solution you use will depend on how you want to handle those situations.

2D character array in C [duplicate]

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 3 years ago.
In C:
I'm trying to get char from the user with scanf and when I run it the program don't wait for the user to type anything...
This is the code:
char ch;
printf("Enter one char");
scanf("%c", &ch);
printf("%c\n",ch);
Why is not working?
The %c conversion specifier won't automatically skip any leading whitespace, so if there's a stray newline in the input stream (from a previous entry, for example) the scanf call will consume it immediately.
One way around the problem is to put a blank space before the conversion specifier in the format string:
scanf(" %c", &c);
The blank in the format string tells scanf to skip leading whitespace, and the first non-whitespace character will be read with the %c conversion specifier.
First of all, avoid scanf(). Using it is not worth the pain.
See: Why does everyone say not to use scanf? What should I use instead?
Using a whitespace character in scanf() would ignore any number of whitespace characters left in the input stream, what if you need to read more inputs? Consider:
#include <stdio.h>
int main(void)
{
char ch1, ch2;
scanf("%c", &ch1); /* Leaves the newline in the input */
scanf(" %c", &ch2); /* The leading whitespace ensures it's the
previous newline is ignored */
printf("ch1: %c, ch2: %c\n", ch1, ch2);
/* All good so far */
char ch3;
scanf("%c", &ch3); /* Doesn't read input due to the same problem */
printf("ch3: %c\n", ch3);
return 0;
}
While the 3rd scanf() can be fixed in the same way using a leading whitespace, it's not always going to that simple as above.
Another major problem is, scanf() will not discard any input in the input stream if it doesn't match the format. For example, if you input abc for an int such as: scanf("%d", &int_var); then abc will have to read and discarded. Consider:
#include <stdio.h>
int main(void)
{
int i;
while(1) {
if (scanf("%d", &i) != 1) { /* Input "abc" */
printf("Invalid input. Try again\n");
} else {
break;
}
}
printf("Int read: %d\n", i);
return 0;
}
Another common problem is mixing scanf() and fgets(). Consider:
#include <stdio.h>
int main(void)
{
int age;
char name[256];
printf("Input your age:");
scanf("%d", &age); /* Input 10 */
printf("Input your full name [firstname lastname]");
fgets(name, sizeof name, stdin); /* Doesn't read! */
return 0;
}
The call to fgets() doesn't wait for input because the newline left by the previous scanf() call is read and fgets() terminates input reading when it encounters a newline.
There are many other similar problems associated with scanf(). That's why it's generally recommended to avoid it.
So, what's the alternative? Use fgets() function instead in the following fashion to read a single character:
#include <stdio.h>
int main(void)
{
char line[256];
char ch;
if (fgets(line, sizeof line, stdin) == NULL) {
printf("Input error.\n");
exit(1);
}
ch = line[0];
printf("Character read: %c\n", ch);
return 0;
}
One detail to be aware of when using fgets() will read in the newline character if there's enough room in the inut buffer. If it's not desirable then you can remove it:
char line[256];
if (fgets(line, sizeof line, stdin) == NULL) {
printf("Input error.\n");
exit(1);
}
line[strcpsn(line, "\n")] = 0; /* removes the trailing newline, if present */
This works for me try it out
int main(){
char c;
scanf(" %c",&c);
printf("%c",c);
return 0;
}
Here is a similiar thing that I would like to share,
while you're working on Visual Studio you could get an error like:
'scanf': function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS
To prevent this, you should write it in the following format
A single character may be read as follows:
char c;
scanf_s("%c", &c, 1);
When multiple characters for non-null terminated strings are read, integers are used as the width specification and the buffer size.
char c[4];
scanf_s("%4c", &c, _countof(c));
neither fgets nor getchar works to solve the problem.
the only workaround is keeping a space before %c while using scanf
scanf(" %c",ch); // will only work
In the follwing fgets also not work..
char line[256];
char ch;
int i;
printf("Enter a num : ");
scanf("%d",&i);
printf("Enter a char : ");
if (fgets(line, sizeof line, stdin) == NULL) {
printf("Input error.\n");
exit(1);
}
ch = line[0];
printf("Character read: %c\n", ch);
try using getchar(); instead
syntax:
void main() {
char ch;
ch = getchar();
}
Before the scanf put fflush(stdin); to clear buffer.
The only code that worked for me is:
scanf(" %c",&c);
I was having the same problem, and only with single characters. After an hour of random testing I can not report an issue yet. One would think that C would have by now a bullet-proof function to retrieve single characters from the keyboard, and not an array of possible hackarounds... Just saying...
Use string instead of char
like
char c[10];
scanf ("%s", c);
I belive it works nice.
Provides a space before %c conversion specifier so that compiler will ignore white spaces. The program may be written as below:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ch;
printf("Enter one char");
scanf(" %c", &ch); /*Space is given before %c*/
printf("%c\n",ch);
return 0;
}
You have to use a valid variable. ch is not a valid variable for this program. Use char Aaa;
char aaa;
scanf("%c",&Aaa);
Tested and it works.

want to call fgets() multiple times based on users need

User enters '1' or '0' choice to continue getting string using fgets(). So when the user enters the choice, fgets reads it from console. I am storing it in another variable. But fgets gets the choice and stores it in messages. I have tried using fflush(stdin) after receiving the choice. Please help me out.
int main() {
int choice=1;
char *message;
int i=0;
while (choice == 1) {
fflush(stdout);
printf("Enter the message: ");
fflush(stdout);
message = fgets(message,200,stdin);
while (message[i]!='\n') {
i++;
}
message[i] = '\0';
send_message(message);
printf("\nType '1' to continue or '0' to quit: ");
scanf("%d",&choice);
fflush(stdin);
}
}
It looks like you're trying to scanf() to read the user's input -- this is inherently dangerous. (See https://www.reddit.com/r/learnprogramming/comments/1d0w4x/c_scanf_d_but_error_if_user_enters_a_character/).
I'd recommend either using %s for your format string, or better yet, build a subroutine to do safe input and parse it the old-fashioned way, such as something along these lines:
/* getsafe() - Generic input using the preferred input method rather than gets() */
#include <stdio.h>
#include <string.h>
char *getsafe(char *inpstr,int inpsiz) {
char *seachr; /* Result of search via strchr() */
if (inpstr==NULL) {
return(NULL);
}
if (fgets(inpstr,inpsiz,stdin)==NULL) {
return(NULL);
}
seachr=strchr(inpstr,'\n');
if (seachr!=NULL) *seachr=0;
return(inpstr);
}
That way you can specify the buffer length and provide a string (array of characters) of sufficient length as to prevent buffer overruns (security issue), and then parse the [0] position in that array for your answer.
#define ANSSIZ 80 /* Maximum allowed size of user answer */
char usrans[ANSSIZ]; /* User Answer */
printf("Enter 'y' or 'n': ");
getsafe(usrans, ANSSIZ-1);
There's a lot of problems with this - It probably belongs on Code Review
However, here is a critique on some of the major problems
int main() {
int choice=1;
char *message; // This is a pointer, but is not malloc'ed. You might want "char message[200]" instead?
int i=0; // This is the only time "i" is set to 0. It needs to be reset at the start of the loop
while (choice == 1) {
fflush(stdout); // No need for this
printf("Enter the message: ");
fflush(stdout);
message = fgets(message,200,stdin);
while (message[i]!='\n') { // Why not use strlen?
i++; // "i" can keep growing forever if there is no newline (if someone entered 199 characters before pressing enter)
}
message[i] = '\0'; // fgets does this for you - The past loop was pointless
send_message(message);
printf("\nType 'y' to continue or 'n' to quit: "); // You forgot to flush here!
scanf("%d",&choice); // I don't think this will result in a 0 or 1 output... %d is for a digit, and you're asking the user for y or n.
fflush(stdin); // This is invalid and unneeded - You can't flush stdin
}
}

Calling scanf() after another string input function creates phantom input

Here's a small program:
#include <stdio.h>
int main() {
char str[21], choice[21]; int size;
while(1){
printf("$ ");
fgets(str, 20, stdin);
printf("Entered string: %s", str);
if(str[0] == 'q') {
printf("You sure? (y/n) ");
scanf("%s", choice);
if(choice[0] == 'y' || choice[0] == 'Y')
break;
}
}
return 0;
}
It reads a string using fgets(). If the string starts with a q, it confirms if the user wants to quit, and exits if the user types y.
When I run it and type q, this happens:
$ q
Entered string: q
You sure? (y/n) n
$ Entered string:
$
Note the $ Entered string:. Clearly, fgets() got an empty character or something as input, even though I didn't type anything.
What's going on?
As described in other answer scanf call leaves the newline in the input buffer you can also use getchar() after scanf like this :
scanf("%20s", choice);// always remember( & good) to include field width
// in scanf while reading
Strings otherwise it will overwrite buffer in case of large strings `
getchar(); //this will eat up the newline
Besides , you should also use fgets like this :
fgets(str,sizeof str, stdin); //Its better
It because the scanf call reads a character, but leaves the newline in the buffer. So when you next time call fgets is finds that one newline character and reads it resulting in an empty line being read.
The solution is deceptively simple: Put a space after the format in the scanf call:
scanf("%s ", choice);
/* ^ */
/* | */
/* Note space */
This will cause scanf to read and discard all training whitespace, including newlines.
Use a 'char' of a specific size char choice [1]
OR
char c[1];
c = getchar();
if(c[0] == 'y' || c[1] == 'y'){
// DO SOMETHING
}

Resources