scanf skipped (tried adding space and \n) - c

I am trying to file redirection a text document and have my code read it and output the number of characters present in the code and allowing the user to input a letter non-case sensitive that instructs the program to look through the text and return with the number of times the letter appeared.
The scanf is not working correctly and does not get user input.
I've tried to add a space like this: " %c" and "%c\n".
Tried removing & and using getchar();
#include <stdio.h>
// Defining variables
#define SIZE 8000
int main(void)
{
char case1 = 'a', case2 = 'b', data[SIZE];
int i, count;
// Reading in the .txt file into a 8000 sized array and removing any other unnecessary portions from the array.
for (i = 0; i < 8000; i++)
{
fscanf(stdin, "%c", &data[i]);
}
printf("The text from the file: \n\n");
for (i = 0; data[i] != '\0'; i++)
{
printf("%c", data[i]);
}
// Printing out the .txt document and counts the number of characters
printf("\n");
printf("There are a total of %i characters in that text.\n ", i+1);
printf("Enter a character to search for in the text:\n ");
// Exiting from stdin.
if (!freopen("/dev/tty", "r", stdin))
{
perror("/dev/tty");
exit(1);
}
// Asking for user input.
scanf("%c", &case1);
// Converting user input into different lettercase.
if (case1 == toupper(case1))
{
case1 = tolower(case1);
} else
{
case2 = toupper(case2);
}
printf("This is your input: %c. Also searching for: %c.\n", case1,case2);
// Searching the text for user-inputted letter.
for (i = 0; data[i] != '\0'; i++)
{
if (data[i] == case1)
{
count++;
}
else if (data[i] == case2)
{
count++;
}
}
printf("That letter %c appears a total of %i times.\n", case1, count);
return 0;
}

You are using fscanf() on stdin which is equivalent to scanf(). If your 8000 character input does not end in a newline, fscanf() will not return until there is a newline, and whatever has been input after the 8000 characters will be accepted into case1 in the final scanf() call.
That is the scanf() call is not "skipped", rather it reads a character already in the buffer. If that character is not whitespace, the "fixes" you tried will be inadequate.
for (i = 0; i < SIZE; i++)
{
fscanf(stdin, "%c", &data[i]);
}
// Flush all remaining input up-to next newline
int c ;
do {} while( data[SIZE-1] != `\n` &&
(c = getchar()) != `\n` &&
c != EOF ) ;

Related

How to make "overloaded" scanf in C?

Friends how can I make Scanf to take 1 or 2 or 3 numbers depending on input data I give?
sample data 1: "1 2 5"
sample data 2: "1 4"
sample data 3: "4"
if(scanf("%lf",&a)==1 )
{
printf("1 input num\n");
}
else if(scanf(" %lf %lf",&a, &b)==2 )
{
printf("2 input num\n");
}
else if(scanf("%lf %lf %lf",&a, &b, &c)==3 )
{
printf("3 input num\n");
}else
{
printf("Error message.\n");
return 1;
}
You might consider this an answer:
int InputNums=0;
InputNums = scanf("%lf %lf %lf",&a, &b, &c);
if(InputNums!=0)
printf("%d input num\n");
else
printf("Error message.\n");
It works by NOT eating one number and then trying whether instead more numbers could have been read, like your shown code does.
Instead try to read three numbers and then let scanf() tell you how many worked.
But actually I am with the commenters. If you do not have guaranteed syntax in your input (which scanf() is for) then use something else.
This is nicely describing which alternative in which situation AND how to get scanf to work in the same situation:
http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html
Scanf already does this for you, and indeed you used the same scanf function with a variable number of arguments. You can look here: How do vararg work in C?
However you don't need to overload scanf, but rather pass to it a string telling what you need to scan. You can do this dynamically by changing the string at runtime.
The code to try is the following:
#include <stdio.h>
int main()
{
char one[] = "%d";
char two[] = "%d%d";
int o1;
int t1,t2;
scanf(one,&o1);
scanf(two,&t1,&t2);
printf("%d %d %d",o1,t1,t2);
return 0;
}
If you must use scanf() ....
"%lf" is a problem as it consumes leading white-space including '\n', so we lost where a line of input might have ended.
Instead first look for leading white-space and see if an '\n' occurs.
#define N 3
double a[N];
count = 0;
while (count < N) {
// Consume leading white-spaces except \n
unsigned char ch = 0;
while (scanf("%c", &ch) == 1 && isspace(ch) && ch != '\n') {
;
}
if (ch == '\n') {
break;
}
// put it back into stdin
ungetc(ch, stdin);
if (scanf("%lf", &a[count]) != 1)) {
break; // EOF or non-numeric text
}
count++;
}
printf("%d values read\n", count);
for (int i=0; i<count; i++) {
printf("%g\n", a[i]);
}
Alterantive to consume various multiple leading whitespaces that only uses scanf() with no ungetc():
// Consume the usual white spaces except \n
scanf("%*[ \t\r\f\v]");
char eol[2];
if (scanf("%1[\n]", eol) == 1) {
break;
}
If the line contains more than N numbers or non-numeric text, some more code needed to report and handle that.
The best solution to problems with scanf and fscanf is usually to use something other than scanf or fscanf. These are remarkably powerful functions, really, but also very difficult to use successfully to handle non-uniform data, including not only variable data but data that may be erronious. They also have numerous quirks and gotchas that, though well documented, regularly trip people up.
Although sscanf() shares many of the characteristics of the other two, it turns out often to be easier to work with in practice. In particular, combining fgets() to read one line at a time with sscanf() to scan the contents of the resulting line is often a convenient workaround for line-based inputs.
For example, if the question is about reading one, two, or three inputs appearing on the same line, then one might approach it this way:
char line[1024]; // 1024 may be overkill, but see below
if (fgets(line, sizeof line, stdin) != NULL) { // else I/O error or end-of-file
double a, b, c;
int n = sscanf(line, "%lf%lf%lf", &a, &b, &c);
if (n < 0) {
puts("Empty or invalid line");
} else {
printf("%d input num\n", n);
}
}
Beware, however, that the above may behave surprisingly if any input line is longer than 1023 characters. It is possible to deal with that, but more complicated code is required.
here is an example of using fgets, strtok and atof to achieve same:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char input[256];
double inputsf[256];
while(1) {
printf(">>> "); fflush(stdout);
char *s = fgets(input, 255, stdin);
if (!s)
break;
int count = 0;
char *t;
while (t = strtok(s, " \n")) {
s = NULL;
inputsf[count++] = atof(t);
}
printf("Found %d inputs\n", count);
for (int i = 0; i < count; i++)
printf(" %lf\n", inputsf[i]);
if (count == 0)
break;
}
return 0;
}
Bases on the #chux-ReinstateMonica comment, here is a piece of code which uses strtod. It skips leading spaces, but has an issue with the tailing spaces at the end of the string. So, some extra checking is needed there, which could be used for error checking as well. The following loop can replace the strtok loop from above.
while(*s) {
char *e;
double val = strtod(s, &e);
if (e == s)
break; // not possible to parse, break the loop
inputsf[count++] = val;
s = e;
}
You can solve your problem using those line of code
#include <stdio.h>
int main(){
int a[100];
int n;
printf("How many data you want to input: ");
scanf("%d", &n);
printf("Sample %d data Input: ", n);
for (int i=0; i <n; i++) {
scanf("%d", &a[i]);
}
printf("Sample data %d: ", n);
for (int i=0; i <n; i++) {
printf("%d ", a[i]);
}
if(n == 1){
printf("\n 1 input num\n");
}else if(n==2){
printf("2 input num\n");
}else if(n==3){
printf("3 input num\n");
}else{
printf("Error");
}
return 0;
}
if you want to take multiple input in single line use this line
int arr[100];
scanf ("%lf %lf %lf", &arr[0], &arr[1], &arr[2]);

How to use scanf to scan for multiple words?

I am trying to work on a function that take the input, the minimum character limit and the maximum character limit. I need to accept the input and count the letters even if there are 2 words or more, and
I saw people said scanf("%30[^\n]%*c") would do the trick. However, this only work if it is the first input ever, nothing more. If there has been any input above, it would just terminate the line, leaving count as zero, and run the loop infinitely. Anyone knows why ?
NOTE: I can not use anything from the <string.h> header file.
{
int n = 1;
while (n == 1)
{
int count = 0;
scanf("%30[^\n]%*c", input);
while (input[count] != '\0')
{
count++;
}
if (minimum == maximum)
{
if (count > maximum)
{
printf("String length must be exactly %d chars: ", minimum);
}
else if (count == minimum)
{
n = 0;
return input;
}
else if (count < minimum)
{
printf("String length must be exactly %d chars: ", minimum);
}
}
else
{
if (count > maximum)
{
printf("String length must be no more than %d chars: ", maximum);
}
else if (minimum <= count && count <= maximum)
{
n = 0;
return input;
}
else if (count < minimum)
{
printf("String length must be between %d and %d chars: ", minimum, maximum);
}
}
}
}
The problem with scanf("%30[^\n]%*c", input); is it fails if the new byte from stdin is a newline, returning 0 and leaving input unchanged, potentially uninitialized, causing the rest of the code to have undefined behavior.
Also note that this format will cause scanf() to read and discard the byte pending after the conversion, either the newline, which is your intent or whatever 31st character was typed by the user on the input line.
You should test the return value of scanf() to detect a conversion error and/or the end of file and only scan the array if scanf() returns 1.
You should discard extra bytes at the end of the line with a loop:
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
Or with scanf():
scanf("%*[^\n]"); // discard the rest of the input line if any
scanf("%*c"); // discard the newline if any.
To get rid of the pending newline left from previous calls to scanf(), you can write:
int c;
if ((c = getchar()) != '\n')
ungetc(c, stdin);
Or using scanf:
scanf("%1*[\n]"); // read and discard at most 1 newline byte

Why I have an alignment problem when displaying the ASCII characters in a loop?

I want to write a program which prints each letter with ASCII number.
The program should print 8 letters with ASCII number in one verse so I decide to make a counter and in each loop it should increment this variable.
The problem is more visible on this screenshot:
Why are spaces are not equal?
I think that something is wrong with loop.
My code:
int main(void) {
char ch;
int flag = 0;
while ((ch = getchar()) != '#') {
if (isalpha(ch)) {
flag++;
printf("%c : %d \t", ch, ch);
}
if ((flag % 8) == 0) {
printf("\n");
}
}
return 0;
}
Nothing wrong with the loop. its causes for extra " "(space) before \t. replace your first printf function with this:
printf("%c : %d\t", ch, ch);.
The spaces will be equal.
The loop is almost OK, you should more the test on flag inside the test on isalpha(c) otherwise you might print multiple newlines if the set of letters was not contiguous.
The alignment problem comes from the number of characters output before the TAB: "%c : %d \t" produces a single character for %c, 3 characters for :, up to 3 characters for %d, and another character for : that's 8 characters for c >= 100. The TAB character expands to the number of spaces needed to reach a column multiple of 8. Hence 1 space for c < 100 and 8 spaces for c >= 100.
You can fix this by removing the extra space before the \t.
Also note that you should read bytes from the input stream into an int variable and test for EOF too.
Here is a modified version:
int main(void) {
int ch;
int flag = 0;
while ((ch = getchar()) != EOF && c != '#') {
if (isalpha(ch)) {
printf("%c : %d\t", ch, ch);
flag++;
if ((flag % 8) == 0)
printf("\n");
}
}
return 0;
}

Wanted to check if the value entered is a number or else. "isdigit() is not working here as expected

I am stuck with a problem here in C. I am posting the question and the code I have written below. Here I have to enter 10 numbers in an array and then I need to check how many times a number appeared. But to verify that I have entered a number and not anything else, I have used "isdigit()" function. But this is of no use. Can anyone help me to solve it.
/*
(a) Ten numbers are entered from the keyboard into an array. The number to be searched is entered through the
keyboard by the user. Write a program to find if the number to be searched is present in the array and if it is present, display
the number of times it appears in the array.
*/
#include<stdio.h>
#include<ctype.h>
main()
{
int num[10];
int i, j, cnt=0;
char rept;
printf("Enter 10 numbers: \n\n");
for(i=0; i<=9; i++)
{
printf("Number %d = ", i+1);
scanf("%d", &num[i]);
fflush(stdin);
if ( !isdigit(num[i]) )
{
printf("OK\n");
}
else
{
printf("Invalid number. Enter again.\n");
i=i-1;
}
}
do
{
printf("\nEnter the number to be searched in array: ");
scanf(" %d", &j);
for (i=0 ; i<=24; i++)
{
if(num[i]==j)
cnt++;
}
if(cnt>0)
printf("\nNumber %d is present at %d places", j, cnt);
else
printf("\nNumber not present.");
printf("\n\nDo you want to search another number. Press Y to repeat. Any other key to exit");
fflush(stdin);
scanf("%c", &rept);
}while (rept=='y'||rept=='Y');
getch();
}
No you can't do that. isdigit() is supposed to work with characters and you passed a multigit integer variable.
What you can do is simply like this
if( scanf("%d",&a[i])== 1){
// you can be sure number is entered
}
And fflush(stdin) is undefined behavior.
So the use of scanf will be more prominent if you would do this
int clearstdin(){
int c;
while ((c = getchar()) != '\n' && c != EOF);
return (c == EOF);
}
In main()
int earlyend = 0;
for(size_t i=0; i<SIZE; i++){
...
...
int ret = scanf("%d",&a[i]);
while( ret == 0){
if( clearstdin() ){ /* EOF found */earlyend = 1; break; }
fprintf(stderr,"%s\n","Entered something wrong");
ret = scanf("%d",&a[i]);
}
if( earlyend ){ /*EOF found*/ }
if( ret == EOF) { /* Error occured */}
...
}
The %d conversion specifier will cause scanf to skip over any leading whitespace, then read a sequence of decimal digits, stopping at the first non-digit character. If there are no digit characters in the input (for example, you enter something like ”abc”), then nothing is read from the input stream, a[i] is not updated, and scanf will return 0 to indicate a matching failure.
So, you can do a test like
if ( scanf( “%d”, &a[i] ) == 1 )
{
// user entered valid input
}
But...
This doesn’t fully protect you from bad input. Suppose you enter something like ”123abc” - scanf will read, convert, and assign 123 and return a 1 indicating success, leaving ”abc” in the input stream to potentially foul up the next read.
Ideally, you’d like to reject the whole thing outright. Personally, I do this as follows:
char inbuf[SOME_SIZE]; // buffer to store input
if ( fgets( inbuf, sizeof inbuf, stdin ) ) // read input as text
{
char *chk; // use strtol to convert text to integer
int temp = (int) strtol( inbuf, &chk, 10 ); // first non-digit character written to chk
if ( isspace( *chk ) || *chk == 0 ) // if chk is whitespace or 0, input is valid
{
a[i] = temp;
}
else
{
// bad input
}
}
This still isn’t a 100% solution - it doesn’t make sure the user didn’t enter more characters than the buffer can hold, but it’s a step in the right direction.
Input validation in C is, frankly, a pain in the ass.

How to limit input length with scanf

In this program I have taken a dimensional character array of size[3][4],
as long as I enter a 3 characters for each row it will work well.
For example: if I enter abc abd abd I get the same output but if i enter more letters in the first or second or 3rd row I get an error.
How should I check for null character in 2 dimensional?
# include <stdio.h>
#include <conio.h>
# include <ctype.h>
void main()
{
int i=0;
char name[3][4];
printf("\n enter the names \n");
for(i=0;i<3;i++)
{
scanf( "%s",name[i]);
}
printf( "you entered these names\n");
for(i=0;i<3;i++)
{
printf( "%s\n",name[i]);
}
getch();
}
As pointed out by #SouravGhosh, you can limit your scanf with "%3s", but the problem is still there if you don't flush stdin on each iteration.
You can do this:
printf("\n enter the names \n");
for(i = 0; i < 3; i++) {
int c;
scanf("%3s", name[i]);
while ((c = fgetc(stdin)) != '\n' && c != EOF); /* Flush stdin */
}
How should I chk for null character in 2 dimensional ... [something has eaten the rest part, I guess]
You don't need to, at least not in current context.
The problem is in your approach of allocating memory and putting input into it. Your code has
char name[3][4];
if you enter more that three chars, you'll be overwriting the boundary of allocated memory [considering the space of \0]. You've to limit your scanf() using
scanf("%3s",name[i]);
Note:
change void main() to int main(). add a return 0 at the end.
always check the return value of scanf() to ensure proper input.
EDIT:
As for the logical part, you need to eat up the remainings of the input words to start scanning from the beginning of the next word.
Check the below code [Under Linux, so removed conio.h and getch()]
# include <stdio.h>
# include <ctype.h>
int main()
{
int i=0; char name[3][4];
int c = 0;
printf("\n enter the names \n");
for(i=0;i < 3;i++)
{
scanf( "%3s",name[i]);
while(1) // loop to eat up the rest of unwanted input
{ // upto a ' ' or `\n` or `EOF`, whichever is earlier
c = getchar();
if (c == ' ' || c == '\n' || c == EOF) break;
}
}
printf( "you entered these names\n");
for(i=0;i<3;i++)
{
printf( "%s\n",name[i]);
}
return 0;
}
(Cringing after reading the answers to date.)
First, state the problem clearly. You want to read a line from stdin, and extract three short whitespace separated strings. The stored strings are NUL terminated and at most three characters (excluding the NUL).
#include <stdio.h>
void main(int, char**) {
char name[3][4];
printf("\n enter the names \n");
{
// Read tbe line of input text.
char line[80];
if (0 == fgets(line, sizeof(line), stdin)) {
printf("Nothing read!\n");
return 1;
}
int n_line = strlen(line);
if ('\n' != line[n_line - 1]) {
printf("Input too long!\n");
return 2;
}
// Parse out the three values.
int v = sscanf(line, "%3s %3s %3s", name[0], name[1], name[2]);
if (3 != v) {
printf("Too few values!\n");
return 3;
}
}
// We now have the three values, with errors checked.
printf("you entered these names\n%s\n%s\n%s\n",
name[0], name[1], name[2]
);
return 0;
}
you might consider something on the order of scanf( "%3s%*s",name[i]);
which should, if I recall correctly, take the first three characters (up to a whitespace) into name, and then ignore anything else up to the next white space. This will cover your long entries and it does not care what the white space is.
This is not a perfect answer as it will probably eat the middle entry of A B C if single or double character entries are mode. strtok, will separate a line into useful bits and you can then take substrings of the bits into your name[] fields.
Perhaps figuring out the entire requirement before writing code would be the first step in the process.

Resources