read ints from standard input until \n is found - c

I'm trying to make a function that reads ints from stdin. it has to read until a certain amount of numbers is read (count in example below), or until it finds a '\n'.
Since as far as I am aware scanf (with %d format specifier) ignores newlines, I used getchar and converted the character into the number it should be.
this works but only for 1 digit numbers.
is there any better way to achieve this?
This is my code:
char num = getchar();
while (num != '\n' && count < 9) {
//boring operations that don't matter
num = getchar()
}

Reading via fgets() is better. Continue reading if your must use scanf().
To use scanf("%d",...), we need extra care to read a line. As "%d" consumes leading white-space, including '\n', we need more code to look for white-space and test if a '\n' is found.
int count = 0;
while (count < 9) {
// Read leading spaces
int ch;
while (isspace((c = getchar())) && c != '\n') {
;
}
if (c == '\n' || c == EOF) break; // We are done reading
ungetc(c, stdin); // put character back
int some_int;
if (scanf("%d", &some_int) == 1) {
printf("Integer found %d\n", some_int);
count++;
} else {
// Non-numeric input, consume at least 1 character.
getchar();
}
}
If numeric text is outside the range of int, the above use of "%d" is undefined behavior. For robust code, use fgets().

The %d conversion specifier only ignores leading whitespace. So you can do something like:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
int n = argc > 1 ? strtol(argv[1], NULL, 10) : 10;
int x;
while( n-- && scanf("%d%*[ \t]", &x) == 1 ){
printf("Read: %d\n", x);
int c = getchar();
if( c == EOF || c == '\n' ){
break;
}
ungetc(c, stdin);
}
return 0;
}
However, this will probably not handle a stream like 10 5 x in a reasonable way. You'll need more logic on the first non-whitespace after an integer to handle that (maybe just do if( c == EOF || ! isdigit(c) ){ break; }). Parsing data with scanf if fickle (it really never has a purpose outside of university exercises). Just use fgets and strtol.

scanf() doesn't ignore \n
#include <stdio.h>
#include <stddef.h>
int main(int argc , char *argv[])
{
int b;
char c;
scanf("%d%c",&b,&c);
if(c == '\n') printf("and then " );
}

Someone posted an answer and then deleted but it was the perfect solution for my problem, so all credit to the original author.
The solution was reading normally with scanf and afterwards,with getchar, checking if it was \n or EOF. If it was break out of the cycle, if it wasn't, "unread" with ungetc so you can scanf the number in the next iteration.
So my final code looks like this:
while(scanf("%d",&num) == 1 && count<9){
//boring operations
c = getchar();
if (c == EOF || c == '\n') break;
if (ungetc(c,stdin) == EOF) break;
}
NOTE: like Andrew Henle pointed out in the replies, this doesn't work unless it is guaranteed that there isn't any space between the digits and the newline

Related

Flush output buffer every N chars

I would like to flush my buffer after every three characters are typed in (instead of the \n). What would be the proper way to change the line-buffer trigger to be from being \n to being every 3 chars?
So far I have something like this:
#include<stdio.h>
#define CHAR_BUFFER 3
int main(void)
{
int ch;
int num=0;
while ((ch = getchar()) != EOF) {
if (ch == '\n') continue; // ignore counting newline as a character
if (++num % CHAR_BUFFER == 0) {
printf("Num: %d\n", num);
fflush(stdout);
putchar(ch);
}
}
return 0;
}
What the program currently produces is:
$ main.c
Hello how are you?
Num: 3
lNum: 6
Num: 9
wNum: 12
rNum: 15
yNum: 18
?
So instead of printing out all three chars, it seems to only grab the last one. What would be the correct way to do this?
Here are two examples of what I want:
H<enter>
// [nothing returned since we have not yet hit our 3rd character]
el<enter>
Hel // [return 'Hel' since this is now a multiple of three]
putchar() shouldn't be inside the if. You want to print all the characters, the condition is just for flushing.
#include<stdio.h>
#define CHAR_BUFFER 3
int main(void)
{
int ch;
int num=0;
while ((ch = getchar()) != EOF) {
if (ch == '\n') continue; // ignore counting newline as a character
putchar(ch);
if (++num % CHAR_BUFFER == 0) {
printf("Num: %d\n", num);
fflush(stdout);
}
}
return 0;
}
Note that this is for flushing the output buffer. It has nothing to do with how input is read or echoed, which requires using OS-specific functions.
See Capture characters from standard input without waiting for enter to be pressed and ANSI C No-echo keyboard input

Read user input until a specific character is encountered

Can someone please provide me some examples? Thank you :)
#include <stdio.h>
int main()
{
int tcount = 0, ccount = 0, dcount = 0;
char ch;
printf("Enter your characters (! to end): \n");
/* What program code to write to get the result? */
printf("digits: %d\n", dcount);
printf("letters: %d\n", ccount);
return 0;
}
is it using for loop?
for (tcount=0;tcount<10;tcount++)
{
scanf("%c",&ch);
if(ch == '!')
break;
}
Test Result:
hello 5432 user#
digits: 4 letters: 9
I would recommend you to use getchar() instead of scanf() for reading single characters.
Or if you have to, you have to skip leading whitespaces
scanf(" %c",&ch);
^ Note the space
Here is a simple example which could be helpful to you, using functions isdigit() and isalpha() from ctype.h library.
int c, numberCounter = 0, letterCounter = 0;
while ((c = getchar()) != '!')
{
if (isalpha(c))
{
letterCounter++;
}
else if (isdigit(c))
{
numberCounter++;
}
}
If you can't use additional libraries like ctype.h, take a look at the ASCII table, for example
if (c >= '0' && c <= '9') // '0' == 48, '9' == 57
{
// c is digit
}
Try something like:
do
{
char c = getchar();
if(c!='!')
{
... do something ....
}
}
while(c != '!');
Yes you need to use a loop for, or a while:
for (tcount=0;tcount<10;tcount++)
{
scanf("%c",&ch);
if(ch == '!')
break;
}
or the while code:
while(ch != '!'){
scanf("%c",&ch);
printf("There are nothing to see here");
}
The POSIX getdelim function does exactly what you're asking for (most code floating around uses getline, but it is exactly the same other than the extra argument). Beware the possibility that the delimiter does not occur within the buffer size.
Also, for interactive input, you might want to put the TTY in raw mode, or the user will have to press enter anyway.

Why we need getchar() although using scanf()?

this code should read a positive number and if user enter a non-numeric value, it asking him again to enter a number and wait the input to check again till entering a number
do
{
printf("Enter a positive number: ");
}
while ( (scanf("%d%c", &n,&c) != 2 || c!='\n' || n<0) ) ;
but actually when entering non-numeric it keeps doing the body of the while loop without reading the waiting to check the condition of the while loop while(scanf("%d%c", &n,&c) != 2 || c!='\n' || n<0)
when edit the condition to
int clean_stdin()
{
while (getchar()!='\n');
return 1;
}
do
{
printf("Enter a positive number: ");
}
while ( (scanf("%d%c", &n,&c) != 2 || c!='\n' || n<0) && clean_stdin() ) ;
It executes in the right way, but I don't understand why we need to add getchar() although we already use scanf() in the condition
When scanf("%d%c", ... encounters non-numeric input, the "%d" causes the scanning to stop and the offending character to remain in stdin for the next input function. The "%c" does not get a chance to read that non-numeric character.
If code re-reads stdin with the same scanf("%d%c", ..., the same result. Some other way is needed to remove the non-numeric input. getchar(), getch(), etc. will read any 1 character.
Example code GetPositiveNumber()
Consider using fgets to collect input. Any invalid input is already removed from the input stream making it simpler to try again.
Parse the input with sscanf or others as needed.
char input[40] = "";
int valid = 0;
int n = 0;
do {
printf ( "Enter a positive integer\n");
if ( fgets ( input, sizeof ( input), stdin)) {
int last = 0;
if ( 1 == ( valid = sscanf ( input, "%d%n", &n, &last))) {
if ( n < 0 || input[last] != '\n') {
valid = 0;//reset if negative or last is not newline
}
}
}
else {
fprintf ( stderr, "problem getting input from fgets\n");
return 0;
}
} while ( valid != 1);
Because scanf() with most specifiers ignores white spaces, and you need to collect them before calling scanf() again if a '\n' is left in the buffer. If you don't collect them (and discard them immediately), then scanf() will return immediately on the next call.
See this code
#include <stdio.h>
int
main(int argc, char* argv[]) {
char c = 0;
scanf("%c", &c);
printf("%c\n", c);
scanf("%c", &c);
printf("%c\n", c);
return 0;
}
If you type over two or three characters, second call of scanf doesn't work as interructive. And getch() is not standard. Also you shouldn't call getchar() since it may block. You can use fseek.
Hack using fseek works only on Windows. :-(
BAD SOLUTION
#include <stdio.h>
int
main(int argc, char* argv[]) {
char c = 0;
scanf("%c", &c);
printf("%c\n", c);
fseek(stdin, 0, SEEK_END);
scanf("%c", &c);
printf("%c\n", c);
return 0;
}
GOOD SOLUTION
#include <stdio.h>
int
main(int argc, char* argv[]) {
char buf[BUFSIZ];
char c = 0;
scanf("%c", &c);
printf("%c\n", c);
while (!feof(stdin) && getchar() != '\n');
scanf("%c", &c);
printf("%c\n", c);
return 0;
}
This works good on Windows & Linux

Print each word in a separate line from an input string

I'm having trouble printing each word in a separate line from an input string in C. The question from the assignment I'm doing states:
Take a sentence as input and print its words in separate lines.
My Code:
#include<stdio.h>
int main()
{
int i;
char s[100];
scanf("%s", s);
for(i=0; s[i]!='\0'; i++)
{
printf("%c", s[i]);
if(s[i]==' ')
{
printf("\n");
}
}
}
Any help would be appreciated.
In your code,
printf("%s", s[i]);
is wrong. Change it to
printf("%c", s[i]);
as, you're trying to print a char value. The conversion specifier for a char is %c.
Note: Always remember, using wrong conversion specifier will lead to undefined behaviour.
Also, while scan()-ing with %s, you cannot read the whole space-delimited input as a single string. From the man page,
%s
Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.
You need to use fgets() to do the job.
That said,
Indent your code properly, make it human-readable.
Chnage scanf("%s", s); to scanf("99%s", s); to avoid possible buffer overflow by putting longer input string than 99 chars.
the proper signature for main() is int main(void).
Rookie, using line-oriented input like fgets or getline is, in general, the proper way to read a line of text. However, when doing simple splitting on a single character, reading a character at a time can be advantageous.
In your case if your task is to read a sentence up to 100 characters and print the words of the sentence out on separate lines, then there is no reason to read the sentence into an array and store the words. You can simply read/print each character until a space is read, then print a newline instead of the space. The reading/printing continues until you reach 100 chars, encounter a newline or EOF:
#include <stdio.h>
#define MAXC 100
int main(void) {
int c = 0;
size_t n = 0;
printf ("\n Enter a sentence.\n\n input: ");
/* read up to 100 characters from stdin, print each word on a line */
while (n < MAXC && (c = getchar ()) != EOF && c != '\n')
{
if (c == ' ')
printf ("\n");
else
printf ("%c", c);
n++;
}
printf ("\n");
if (n == MAXC) /* read and discard remaining chars in stdin */
while ((c = getchar ()) != '\n' && c != EOF);
return 0;
}
Use/Output
$ ./bin/getchar_print_nl_space
Enter a sentence.
input: This is a sentence to split into words.
This
is
a
sentence
to
split
into
words.
Note: if you were going to store all characters, up to 100 (meaning 99 chars and 1 null-terminator), you would need to adjust the length check to n < MAXC - 1 and then null-terminate the array:
char s[MAXC] = {0};
/* read up to 99 characters from stdin into s */
while (n < MAXC - 1 && (c = getchar ()) != EOF && c != '\n')
s[n++] = c;
s[n] = '\0'; /* null-terminate after last character */
if (n == MAXC - 1) /* read and discard remaining chars in stdin */
while ((c = getchar ()) != '\n' && c != EOF);
You would then repeat the logic checking for a space and printing a newline in a for loop:
for (c = 0; c < n; c++)
if (s[c] == ' ')
printf ("\n");
else
printf ("%c", s[c]);
Understanding both manner of input, character-oriented input and line-oriented input will save you time allowing you to match the correct tool to the situation. Here, there is no "more correct" or "less correct" approach, just different ways of doing it.
I think one more way to do this work in a better way is as following.
#include <stdio.h>
#include <string.h>
#define MAX_CHAR 100
int main() {
char s[100],*c;
int i = 0;
scanf("%[^\n]", s);
//Write your logic to print the tokens of the sentence here.
for ( c = s; *c != (int)NULL; c++){
if ( *c == ' '){
*c = '\n';
}
}
printf("%s",s);
return 0;
}
Below code is the answer.
Program also calculates number of space/char and new line.
http://cprograming-char-operation.blogspot.com/2018/07/for-given-statement-print-word-in-each.html
/* Program 1_12 */
/* Count number of line, space and char */
/* Replace a char with specific newline */
/* Add blank space in first input */
#include<stdio.h>
int main()
{
int c,nl,nc,ns,nt;
nl=nc=ns=nt=0;
int d,r, prevd, prevr;
printf("Enter which char to replace :: ");
/* prev is stored before of \n */
while((d = getchar()) != '\n' && (prevd = d));
d = prevd;
printf("Enter word below \n");
while((c=getchar()) != EOF)
{
++nc;
if(c==' ')
++ns;
if(c=='\n')
++nl;
if(c=='\t')
++nt;
/* Replace a char with A */
if(c==d)
putchar('\n');
else
putchar(c);
}
printf("total char=%2d, newline=%2d, space=%2d tabs=%2d\n",nc,nl,ns,nt);
return 0;
}
/* Written by: Prakash Katudia <prakash.katudia#gmail.com> */
gcc ./my_code.c
./a.out
Enter which char to replace :: #space#
Enter word below
hello how are you
hello
how
are
you
#include<stdio.h>
#include<string.h>
int main()
{
char a[1000];
int i,len;
scanf("%[^\n]s",a);
len=strlen(a);
for(i=0;i<len;i++)
{
if(a[i] !=' ')
{
printf("%c", a[i]);
printf("\n");
}
}
}

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