How to use scanf to scan for multiple words? - c

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

Related

scanf skipped (tried adding space and \n)

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 ) ;

String Input with multiple lines

int main() {
char userInput[100]; //Store user input
//Take user input
//scanf(" %s",&userInput);
//scanf("%[^\n]s",&userInput);
//scanf("%[^\n]", &userInput);
//gets(userInput);
scanf("%[]s", &userInput); //This takes input but doesnt leave input loop
printf(" %s",userInput);
//i = index to start for looping through the string, starting at the beginning
//count = Stores occurrences of '$'
//inputLength = length of the input, used for limit of loop
int i =0,count =0;
int inputLength = strlen(userInput);
//Loop through the user input, if the character is '$', the integer count will be incremented
for (i; i < inputLength; i++){
if (userInput[i] == '$'){
count++;
}
}
printf("%d", count);
return 0;
}
Hi i'm having some issues with my code, i need to take an input of 3 lines and count the number of'$' in the input. The input method not commented "scanf("%[]s", &userInput);" is the one only i have discovered to take all 3 lines of input, BUT i can't break the input loop and continue with my program.
Any help would be greatly appreciateed
To read 3 lines with the cumbersome scanf(), code needs to look for '$', '\n', and EOF. The rest of input is discardable.
int count = 0;
int line = 0;
while (line < 3) {
scanf("%*[^$\n]"); // Scan for any amount of characters that are not $ nor \n,
// "*" implies - do not save.
char ch;
if (scanf("%c", &ch) != 1) { // Read next character.
break;
}
if (ch == '$') count++;
else line++;
}
printf("$ count %d\n", count);
As #chux suggested, reading with fgets provides a convenient way to protect from buffer overrun and without having to hard code field-width modifiers in scanf conversion specifiers.
Here, if all you need to do is count the number of '$' characters found in your input (regardless of how many lines), you can simply read ALL the input in fixed sized chunks of data. fgets does just that. It doesn't matter if you have one line, or one million lines of input. It also doesn't matter if your input lines are one-character or one million characters long. You can simply read each line and count the number of '$' found within each chunks of data read, keeping a count of the total found.
You can do this for any character. If you wanted to also count the number of line, you can simply check for '\n' characters and keep a total there as well. The only corner-case in counting lines with fgets is to insure you protect against a non-POSIX end-of-file (meaning a file with no '\n' as the final character). There are a couple of ways to handle this. Checking that the last character read was a '\n' is as good as any.
Putting the pieces together, and protecting against a non-POSIX eof, you could do something similar to the following, which simply reads all data available on stdin and outputs a final '$' and line count:
#include <stdio.h>
#define MAXC 100
int main (void) {
char buf[MAXC] = ""; /* buffer to hold input in up to MAXC size chunks */
size_t lines = 0, dollars = 0; /* counters for lines and dollar chars */
int i = 0;
while (fgets (buf, MAXC, stdin)) /* read all data */
for (i = 0; buf[i]; i++) /* check each char in buf */
if (buf[i] == '$') /* if '$' found */
dollars++; /* increment dollars count */
else if (buf[i] == '\n') /* if '\n' found */
lines++; /* increment line count */
if (i && buf[i-1] != '\n') /* protect against non-POSIX eof */
lines++;
/* output results */
printf ("input contained %zu lines and %zu '$' characters.\n",
lines, dollars);
return 0;
}
Look things over and let me know if you have further questions.
scanf("%[]s", &userInput);" is the one only i have discovered to take all 3 lines of input, BUT i can't break the input loop and continue with my program.
"%[]" is an invalid scanf() specifier. Anything may happen, it is undefined behavior, including taking all lines in and not returning.
The 's' in the format serves no purpose here - drop it.
Yes fgets() is best but let us abuse scanf() to read 3 lines and look for '$'.
char line[3][100] = {0};
// v--------- Consume all leading whitespace
// | vv ----- limit input to 99 characters as scan() appends a \0
// | || v-v-- Look for "not \n"
#define FMT_1LINE " %99[^\n]"
// Let the compiler concatenate the 3 formats into 1 string for scanf
int scan_count = scanf(FMT_1LINE FMT_1LINE FMT_1LINE, line[0], line[1], line[2]);
// Check return value
if (scan_count == 3) {
// Successfully read 3 lines
int count = 0;
for (int line_index = 0; line_index < 3; line_index++) {
char *s = line[line_index];
while (*s) { // no need for strlen(), just loop until the null character
count += *s == '$';
s++;
}
}
printf("$ count %d\n", count);
}
You write:
scanf("%[]s", &userInput); //This takes input but doesnt leave input loop
but the comment is at best misleading. Your format string is malformed, so the behavior of the scanf call is undefined. An empty scan set (between the [] in the format) does not make sense, because the resulting field could never match anything. Therefore, a ] appearing immediately after the opening ] of the scan set is interpreted as a literal character not the ending delimiter. Your scan set is therefore unterminated.
Note, too, that %[ is its own field type, separate from %s. An 's' following the closing ] of the scan set is not part of such a field descriptor, but rather an ordinary character to match.
A trivial way to do this with scanf would be to read characters one at a time in a loop via a %c field. This is probably not what the exercise is looking for, and it's a hack to use scanf() instead of getchar() for this purpose, but perhaps it would serve:
int nl_count = 0;
int dollar_count = 0;
do {
char c;
int result = scanf("%c", &c);
if (result != 1) {
break;
}
switch (c) {
case '\n':
nl_count++;
break;
case '$':
dollar_count++;
break;
}
} while (nl_count < 3);
I'm afraid it would be much more complicated to do it safely reading multiple characters at a time with a %[ field, and there is no safe way to read all three lines in one scanf call, unless you can rely on the input lines not to exceed a line length limit known to you.
int readMatrix() {
char userInput[100][3]; //Store user input
int j = 0, m = 0;
for(m = 0; m < 3; m++){
scanf("%s", &userInput[j][m]); //This takes input (Ex: 22 *(enter)* 33$ *(enter)* 66$ *(enter)*
j++; //increase the column
}
int i =0,count =0;
m = 0;
//Loop through the user input, if the character is '$', the integer count will be incremented
for (i = 0; i < 100; i++){
for(m = 0; m < 3; m++){
if (userInput[i][m] == '$'){
count++;
}
}
}
printf("%d", count);
return 0;
}

How to enter new line until empty line is encountered in C

This is my code here, I'm trying to create a programme that counts characters using functions and then determine the average value of characters when an empty line is encountered. The programme is suppose to allow the user to enter multiple lines until an empty line is encountered but I can't seem to.
#include <stdio.h>
#include <Windows.h>
int main()
{
char str[1000];
int Digits, Char, SpecialChar, linecount = 0;
int counter;
int total;
int average;
Digits = Char = SpecialChar = 0;
printf("Please type in your words here: ");
gets(str);
for (counter = 0; str[counter] != NULL; counter++)
{
if (str[counter] >= '0' && str[counter] <= '9')
Digits++;
else if ((str[counter] >= 'A' && str[counter] <= 'Z') || (str[counter] >= 'a' && str[counter] <= 'z'))
Char++;
else
SpecialChar++;
}
while (str[counter] != '\n')
{
if (str[counter] = '\n')
{
linecount ++;
}
}
total = Digits + Char + SpecialChar;
average = total / linecount;
printf("\nDigits: %d \nCharacters: %d \nSpecial Characters: %d \nLine: %d", Digits, Char, SpecialChar, linecount);
printf("\nTotal no. of characters = %d", total);
printf("\nAverage no. of characters = %d", average);
Sleep(5000000);
return 0;
}
As far as I know, the function gets is interrupted after "\n". Also, using fgets you will have to put an attention on the '\0' addition on the string. That means that
The programme is suppose to allow the user to enter multiple lines until an empty line is encountered but I can't seem to.
will never be able to be accomplished using gets this way. Because gets is not a recommended function, I edited you code a little bit in a way that you might be searching.
Something to metion, that I found out it might be a logic error, before you read this code
for (counter = 0; str[counter] != NULL; counter++)
This seems strange, because the fgets will always record the "\n" character. So, the next condition
if (str[counter] = '\n')
will never be true
I see some others errors on you code, but, not majors ones. So, I see the suggestion as a sufficient as appointing them
while (fgets(str, 1000, stdin) && str[0] != '\n'){ //I dont know if checking the first element of the string is redundancy,
//because, the I think the fgets function will return NULL if you just press enter, as the first character
for (counter = 0; str[counter] != '\n'; counter++{
if (str[counter] >= '0' && str[counter] <= '9')
Digits++;
else if ((str[counter] >= 'A' && str[counter] <= 'Z') || (str[counter] >= 'a' && str[counter] <= 'z'))
Char++;
else
SpecialChar++;
}
linecount ++; //new line is someting that you will always reach, so,
//there is no reason for any condition
}
Solution is below:
#include <stdio.h>
#include <Windows.h>
int main()
{
char str[1000];
int Digits, Char, SpecialChar, linecount = 0;
int counter;
int total;
int average;
int flag = 1;
Digits = Char = SpecialChar = 0;
printf("Please type in your words here: ");
while(flag == 1)
{
gets(str);
if (str[0] == NULL || str[0] == '\n')
{
flag = 0;
break;
}
for (counter = 0; str[counter] != NULL; counter++)
{
if (str[counter] >= '0' && str[counter] <= '9')
Digits++;
else if ((str[counter] >= 'A' && str[counter] <= 'Z') || (str[counter] >= 'a' && str[counter] <= 'z'))
Char++;
else
SpecialChar++;
}
linecount ++;
}
total = Digits + Char + SpecialChar;
average = total / linecount;
printf("\nDigits: %d \nCharacters: %d \nSpecial Characters: %d \nLine: %d", Digits, Char, SpecialChar, linecount);
printf("\nTotal no. of characters = %d", total);
printf("\nAverage no. of characters = %d", average);
Sleep(5000000);
return 0;
}
The gets() function is unsafe and extremely susceptible to buffer overflows. Never use this function. A better alternative is fgets(), though the non-standard (but widely available) POSIX getline() function is also a good option.
Both fgets() and gets() fetch a line of input, but gets() discards the newline character, while fgets() keeps it and stores it in the input buffer (if there is room). This means that you may need to remove the newline character after fetching a line of input with fgets(). It also means that when the user simply presses ENTER, the input buffer contains only a \n character, followed by a \0 null terminator; fgets() always null-terminates the input buffer.
To read multiple lines of user input, stopping only when the user presses ENTER, fgets() should be called in a loop. One way of doing this is to use a for(;;) {} loop construction, which never terminates (equivalent to while(1) {}). If the first character in a line of input is a \n character, then a break; statement exits the loop.
Notes on the Posted Code
The posted code is comparing input characters with character constants to determine whether the input is numeric, alphabetic, or otherwise. This is better, and more portably, accomplished by using Standard Library functions from ctype.h. Using library functions here means that the code does not need to explicitly consider the current locale or character encoding (which may not be ASCII or UTF-8).
The posted code contains the line:
for (counter = 0; str[counter] != NULL; counter++) {}
Note that NULL is the null pointer constant, equivalent to (void *) 0, but not equivalent to 0. The goal of this loop appears to be to iterate over a string, terminating when the null terminator (\0) is reached. So, the controlling expression should be changed:
for (counter = 0; str[counter] != '\0'; counter++) {}
Also, the purpose of this loop in the posted code is unclear:
while (str[counter] != '\n')
{
if (str[counter] = '\n')
{
linecount ++;
}
}
If str[counter] is a newline character, then the loop is not entered; otherwise the if statement in the loop body assigns '\n' to str[counter], evaluating to true and incrementing linecount. On the next iteration str[counter] == '\n', so the loop is terminated. After the previous loop (with NULL changed to '\0' in the controlling expression), counter is the index of the \0 character in str, so this loop replaces the null terminator with a newline character, making str a string no longer. This will lead to undefined behavior if the code later attempts to treat str as a string.
If the line if (str[counter] = '\n') is a typo, meant to be if (str[counter] == '\n'), then this is an infinite loop once entered.
An Example Program
Here is a heavily modified of the posted code that uses fgets() to get user input, and Standard Library functions to classify input characters.
The fgets() function returns a null pointer in the event of an error, so this is checked for and handled in about the simplest way possible. After input has been stored in the str[] buffer array, the first character is checked; if it is \n, then the user entered an empty line (probably: see the next paragraph), and the loop is terminated. Otherwise, the next step is to see if the input line contains a newline character at all. The strchr() (from string.h) function is used here for this. If the \n is not found, then a null pointer is returned, otherwise a pointer to the \n character is returned. This is used to write over the \n with \0, effectively removing the newline character. Then linecount is incremented. Thus, the line counter is incremented only when a newline character is encountered in the input.
Note that when input is too large for the input buffer, at least the newline character will remain in the input stream waiting for the next I/O function call. It is possible that only the newline character remains in the input stream, so on the next loop iteration the first character in the buffer is \n, interpreted by this program as an empty line. If there is a possibility that input will be larger than the buffer allocation, more subtlety will be required to handle this situation. One solution is to use a flag to indicate whether the start of a line is being read. Here, line_start is initialized to 1, set to 1 whenever linecount is incremented, and set to 0 whenever a newline character is not found in the input buffer. In order for a newline to indicate an empty line of input, line_start must be set to 1, and the first character in the input buffer must be a \n character. With this modification, the program will reliably read lines of input even longer than the allocated 1000 characters. You can test this out by making the allocation for str[] smaller; try char str[2];.
Here is the complete program:
#include <stdio.h>
#include <ctype.h> // for isdigit(), isalpha()
#include <string.h> // for strchr()
int main(void)
{
char str[1000];
int Digits = 0;
int Char = 0;
int SpecialChar = 0;
int linecount = 0;
int counter;
int total;
int average;
puts("Please type in your words here:");
int line_start = 1;
for (;;) {
if (fgets(str, sizeof str, stdin) == NULL) {
/* Handle error */
fprintf(stdin, "I/O error\n");
return 1;
}
/* Terminate loop on empty line */
if (line_start && str[0] == '\n') {
break;
}
/* If newline present, remove and increment linecount */
char *cptr = strchr(str, '\n');
if (cptr != NULL) {
*cptr = '\0';
++linecount;
line_start = 1;
} else {
line_start = 0; // complete line not read
}
/* update character counters */
for (counter = 0; str[counter] != '\0'; counter++) {
unsigned char uc = str[counter];
if (isdigit(uc)) {
Digits++;
} else if (isalpha(uc)) {
Char++;
} else {
SpecialChar++;
}
}
}
total = Digits + Char + SpecialChar;
average = total / linecount; // integer division
printf("Digits: %d \nCharacters: %d \nSpecial Characters: %d \nLine: %d\n",
Digits, Char, SpecialChar, linecount);
printf("Total no. of characters = %d\n", total);
printf("Average no. of characters = %d\n", average);
return 0;
}

Validation using scanf() to protect against string

I have a code here that has a job to see if the user input is either string or integer from a range of 1-49. If I enter "asdas" it says invalid, and if I enter a integer from "1-49" it says valid. The problems I am having with this code is that if I enter "2 asda"
it will it count it has valid, and invalid at the same time, and if I enter "2 2" It will consider that valid as well. Just found out it also accepts "2d" as a valid input to.
for (i = 0; i < 6; i++)
{
printf("\nPlease enter the %d winning ticket numbers!: ", i+1);
if (scanf("%d", (&winningNumbers[i])) == 0 || (winningNumbers[i] <= 0) || (winningNumbers[i] >= 50))
{
inputFlush();
printf("\nInvalid Input. Please re-enter.\n") ;
i = i - 1;
}
}
for (i = 0; i < 6; i++)
{
printf("%d, ", winningNumbers[i]);
}
Read the entire line into a string (fgets, line 2 in the snippet). Read data from the string using sscanf: read the integer and one more character, after a space. Check whether sscanf returns something different than 1. If it does then you either have strings in the beginning (it returns 0 since it couldn't read an integer) or you have extra whitespace characters at the end (that is it also matched the %c format specifier). The space is needed to jump over whitespace until the end of the line (including the stored \n).
printf("\nPlease enter the %d winning ticket numbers!: ", i+1);
fgets(buffer, size, stdin);
if (sscanf(buffer, "%d %c", &winningNumbers[i], &c) != 1 || (winningNumbers[i] <= 0) || winningNumbers[i] >= 50))
{
// inputFlush(); not needed now that you read the entire line
printf("\nInvalid Input. Please re-enter.\n") ;
i = i - 1;
}
Look at this example.
#define MAX_LINE_SIZE 500
int main(int argc, char** argv)
{
char line[MAX_LINE_SIZE];
unsigned int num;
char *ptr;
while (fgets(line, MAX_LINE_SIZE, stdin) != NULL){
num = strtol(line, &ptr, 10);
if (line[0] != '\n' && (*ptr == '\n' || *ptr == '\0')) {
printf("Your num: %u\n", num); // check num if you need
} else {
printf("Error\n");
}
}
return 0;
}
The output:
12
Your num: 12
45
Your num: 45
34 2
Error
ads
Error
Here fgets function read data from stdin. strtol parse read string and assign an address of a char after parsed number to ptr pointer. Assuming that user has to input only one number (without any character after) we have to check whether *ptr is new line or end of line.
line[0] != '\n' prevents empty string.
Check the next character using peek, as detailed here. You can tell if it's good or not that way.
Another SO question that's pretty much the same.

Putting numbers separated by a space into an array

I want to have a user enter numbers separated by a space and then store each value as an element of an array. Currently I have:
while ((c = getchar()) != '\n')
{
if (c != ' ')
arr[i++] = c - '0';
}
but, of course, this stores one digit per element.
If the user was to type:
10 567 92 3
I was wanting the value 10 to be stored in arr[0], and then 567 in arr[1] etc.
Should I be using scanf instead somehow?
There are several approaches, depending on how robust you want the code to be.
The most straightforward is to use scanf with the %d conversion specifier:
while (scanf("%d", &a[i++]) == 1)
/* empty loop */ ;
The %d conversion specifier tells scanf to skip over any leading whitespace and read up to the next non-digit character. The return value is the number of successful conversions and assignments. Since we're reading a single integer value, the return value should be 1 on success.
As written, this has a number of pitfalls. First, suppose your user enters more numbers than your array is sized to hold; if you're lucky you'll get an access violation immediately. If you're not, you'll wind up clobbering something important that will cause problems later (buffer overflows are a common malware exploit).
So you at least want to add code to make sure you don't go past the end of your array:
while (i < ARRAY_SIZE && scanf("%d", &a[i++]) == 1)
/* empty loop */;
Good so far. But now suppose your user fatfingers a non-numeric character in their input, like 12 3r5 67. As written, the loop will assign 12 to a[0], 3 to a[1], then it will see the r in the input stream, return 0 and exit without saving anything to a[2]. Here's where a subtle bug creeps in -- even though nothing gets assigned to a[2], the expression i++ still gets evaluated, so you'll think you assigned something to a[2] even though it contains a garbage value. So you might want to hold off on incrementing i until you know you had a successful read:
while (i < ARRAY_SIZE && scanf("%d", &a[i]) == 1)
i++;
Ideally, you'd like to reject 3r5 altogether. We can read the character immediately following the number and make sure it's whitespace; if it's not, we reject the input:
#include <ctype.h>
...
int tmp;
char follow;
int count;
...
while (i < ARRAY_SIZE && (count = scanf("%d%c", &tmp, &follow)) > 0)
{
if (count == 2 && isspace(follow) || count == 1)
{
a[i++] = tmp;
}
else
{
printf ("Bad character detected: %c\n", follow);
break;
}
}
If we get two successful conversions, we make sure follow is a whitespace character - if it isn't, we print an error and exit the loop. If we get 1 successful conversion, that means there were no characters following the input number (meaning we hit EOF after the numeric input).
Alternately, we can read each input value as text and use strtol to do the conversion, which also allows you to catch the same kind of problem (my preferred method):
#include <ctype.h>
#include <stdlib.h>
...
char buf[INT_DIGITS + 3]; // account for sign character, newline, and 0 terminator
...
while(i < ARRAY_SIZE && fgets(buf, sizeof buf, stdin) != NULL)
{
char *follow; // note that follow is a pointer to char in this case
int val = (int) strtol(buf, &follow, 10);
if (isspace(*follow) || *follow == 0)
{
a[i++] = val;
}
else
{
printf("%s is not a valid integer string; exiting...\n", buf);
break;
}
}
BUT WAIT THERE'S MORE!
Suppose your user is one of those twisted QA types who likes to throw obnoxious input at your code "just to see what happens" and enters a number like 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 which is obviously too large to fit into any of the standard integer types. Believe it or not, scanf("%d", &val) will not yak on this, and will wind up storing something to val, but again it's an input you'd probably like to reject outright.
If you only allow one value per line, this becomes relatively easy to guard against; fgets will store a newline character in the target buffer if there's room, so if we don't see a newline character in the input buffer then the user typed something that's longer than we're prepared to handle:
#include <string.h>
...
while (i < ARRAY_SIZE && fgets(buf, sizeof buf, stdin) != NULL)
{
char *newline = strchr(buf, '\n');
if (!newline)
{
printf("Input value too long\n");
/**
* Read until we see a newline or EOF to clear out the input stream
*/
while (!newline && fgets(buf, sizeof buf, stdin) != NULL)
newline = strchr(buf, '\n');
break;
}
...
}
If you want to allow multiple values per line such as '10 20 30', then this gets a bit harder. We could go back to reading individual characters from the input, and doing a sanity check on each (warning, untested):
...
while (i < ARRAY_SIZE)
{
size_t j = 0;
int c;
while (j < sizeof buf - 1 && (c = getchar()) != EOF) && isdigit(c))
buf[j++] = c;
buf[j] = 0;
if (isdigit(c))
{
printf("Input too long to handle\n");
while ((c = getchar()) != EOF && c != '\n') // clear out input stream
/* empty loop */ ;
break;
}
else if (!isspace(c))
{
if (isgraph(c)
printf("Non-digit character %c seen in numeric input\n", c);
else
printf("Non-digit character %o seen in numeric input\n", c);
while ((c = getchar()) != EOF && c != '\n') // clear out input stream
/* empty loop */ ;
break;
}
else
a[i++] = (int) strtol(buffer, NULL, 10); // no need for follow pointer,
// since we've already checked
// for non-digit characters.
}
Welcome to the wonderfully whacked-up world of interactive input in C.
Small change to your code: only increment i when you read the space:
while ((c = getchar()) != '\n')
{
if (c != ' ')
arr[i] = arr[i] * 10 + c - '0';
else
i++;
}
Of course, it's better to use scanf:
while (scanf("%d", &a[i++]) == 1);
providing that you have enough space in the array. Also, be careful that the while above ends with ;, everything is done inside the loop condition.
As a matter of fact, every return value should be checked.
scanf returns the number of items successfully scanned.
Give this code a try:
#include <stdio.h>
int main()
{
int arr[500];
int i = 0;
int sc = 0; //scanned items
int n = 3; // no of integers to be scanned from the single line in stdin
while( sc<n )
{
sc += scanf("%d",&arr[i++]);
}
}

Resources