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++]);
}
}
Related
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
I'm towards solving the exercise, but just half way, I find it so weird and cannot figure it out,
the next is the code snippet, I know it is steps away from finished, but I think it's worth figuring out how come the result is like this!
#define MAXLINE 1000
int my_getline(char line[], int maxline);
int main(){
int len;
char line[MAXLINE];/* current input line */
int j;
while((len = my_getline(line, MAXLINE)) > 0 ){
for (j = 0 ; j <= len-1 && line[j] != ' ' && line[j] != '\t'; j++){
printf("%c", line[j]);
}
}
return 0;
}
int my_getline(char s[], int limit){
int c,i;
for (i = 0 ; i < limit -1 && (c = getchar()) != EOF && c != '\n'; i++)
s[i] = c;
if (c == '\n'){
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
It will be compiled successfully with cc: cc code.c. But the following result is subtle!
Iit is working for lines without \t and blanks:
hello
hello
but it does not work for the line in the picture:
I typed hel[blank][blank]lo[blank]\n:
Could anyone help me a bit? many thanks!
The problem is that you are stuck because you try to get a full line and process it. It's better to process (and the problems of K&R are mostly this way all) the input char by char. If you don't print characters as you detect spaces, but save them in a buffer, and print them if there's a nontab character when you read one past the accumulated ones, then everything works fine. This is also true for new lines. You should keep the last (nonblank) character (as blanks are eliminated before a new line) read to see if it is a newline... in that case, the new line you have just read is not printed, and so, sequences of two or more newlines are only printed the first. This is a sample complete program that does this:
#include <stdio.h>
#include <stdlib.h>
#define F(_f) __FILE__":%d:%s: "_f, __LINE__, __func__
int main()
{
char buffer[1000];
int bs = 0;
int last_char = '\n', c;
unsigned long
eliminated_spntabs = 0,
eliminated_nl = 0;
while((c = getchar()) != EOF) {
switch(c) {
case '\t': case ' ':
if (bs >= sizeof buffer) {
/* full buffer, cannot fit more blanks/tabs */
fprintf(stderr,
"we can only hold upto %d blanks/tabs in"
" sequence\n", (int)sizeof buffer);
exit(1);
}
/* add to buffer */
buffer[bs++] = c;
break;
default: /* normal char */
/* print intermediate spaces, if any */
if (bs > 0) {
printf("%.*s", bs, buffer);
bs = 0;
}
/* and the read char */
putchar(c);
/* we only update last_char on nonspaces and
* \n's. */
last_char = c;
break;
case '\n':
/* eliminate the accumulated spaces */
if (bs > 0) {
eliminated_spntabs += bs;
/* this trace to stderr to indicate the number of
* spaces/tabs that have been eliminated.
* Erase it when you are happy with the code. */
fprintf(stderr, "<<%d>>", bs);
bs = 0;
}
if (last_char != '\n') {
putchar('\n');
} else {
eliminated_nl++;
}
last_char = '\n';
break;
} /* switch */
} /* while */
fprintf(stderr,
F("Eliminated tabs: %lu\n"),
eliminated_spntabs);
fprintf(stderr,
F("Eliminated newl: %lu\n"),
eliminated_nl);
return 0;
}
The program prints (on stderr to not interfer the normal output) the number of eliminated tabs/spaces surrounded by << and >>. And also prints at the end the full number of eliminated blank lines and the number of no content lines eliminated. A line full of spaces (only) is considered a blank line, and so it is eliminated. In case you don't want blank lines with spaces (they will be eliminated anyway, as they are at the end) to be eliminated, just assign spaces/tabs seen to the variable last_char.
In addition to the good answer by #LuisColorado, there a several ways you can look at your problem that may simplify things for you. Rather than using multiple conditionals to check for c == ' ' and c == '\t' and c == '\n', include ctype.h and use the isspace() macro to determine if the current character is whitespace. It is a much clearer way to go.
When looking at the return. POSIX getline uses ssize_t as the signed return allowing it to return -1 on error. While the type is a bit of an awkward type, you can do the same with long (or int64_t for a guaranteed exact width).
Where I am a bit unclear on what you are trying to accomplish, you appear to be wanting to read the line of input and ignore whitespace. (while POSIX getline() and fgets() both include the trailing '\n' in the count, it may be more advantageous to read (consume) the '\n' but not include that in the buffer filled by my_getline() -- up to you. So from your example output provided above it looks like you want both "hello" and "hel lo ", to be read and stored as "hello".
If that is the case, then you can simplify your function as:
long my_getline (char *s, size_t limit)
{
int c = 0;
long n = 0;
while ((size_t)n + 1 < limit && (c = getchar()) != EOF && c != '\n') {
if (!isspace (c))
s[n++] = c;
}
s[n] = 0;
return n ? n : c == EOF ? -1 : 0;
}
The return statement is just the combination of two ternary clauses which will return the number of characters read, including 0 if the line was all whitespace, or it will return -1 if EOF is encountered before a character is read. (a ternary simply being a shorthand if ... else ... statement in the form test ? if_true : if_false)
Also note the choice made above for handling the '\n' was to read the '\n' but not include it in the buffer filled. You can change that by simply removing the && c != '\n' from the while() test and including it as a simple if (c == '\n') break; at the very end of the while loop.
Putting together a short example, you would have:
#include <stdio.h>
#include <ctype.h>
#define MAXC 1024
long my_getline (char *s, size_t limit)
{
int c = 0;
long n = 0;
while ((size_t)n + 1 < limit && (c = getchar()) != EOF && c != '\n') {
if (!isspace (c))
s[n++] = c;
}
s[n] = 0;
return n ? n : c == EOF ? -1 : 0;
}
int main (void) {
char str[MAXC];
long nchr = 0;
fputs ("enter line: ", stdout);
if ((nchr = my_getline (str, MAXC)) != -1)
printf ("%s (%ld chars)\n", str, nchr);
else
puts ("EOF before any valid input");
}
Example Use/Output
With your two input examples, "hello" and "hel lo ", you would have:
$ ./bin/my_getline
enter line: hello
hello (5 chars)
Or with included whitespace:
$ ./bin/my_getline
enter line: hel lo
hello (5 chars)
Testing the error condition by pressing Ctrl + d (or Ctrl + z on windows):
$ ./bin/my_getline
enter line: EOF before any valid input
There are many ways to put these pieces together, this is just one possible solution. Look things over and let me know if you have further questions.
I'm having trouble finding out how to set up a loop where i enter input and then
stop the input by pressing 'e' or 'E'. The input entered is integers but needs to be stopped with a character. That is where i get lost. I have seen a bunch of information about using ascii conversions but i dont know how efficient that would be. This code is broken but it is as far as i could get. Any information would be helpful.
int main(void)
{
char num;
int sub;
while (sub != 'e' || sub != 'E') {
scanf("%d", &num);
sub = #
printf("%d", num);
}
return 0;
}
Simple.
#include <stdio.h>
#include <ctype.h>
int main(void) {
char c = getchar();
int num;
while (c != 'e' || c != 'E') {
if (isdigit(c))
num = c - '0';
c = getchar();
}
return 0;
}
But you don't have to use an ascii character as a way to stop input. You can use EOF which is -1. It is Ctrl-D on UNIX systems and Ctrl-Z on Windows.
int c;
while ((c = getchar()) != EOF)
A direct way to distinguish between an input of int, 'e' and , 'E' is to read a line of user input with fgets() and then parse it.
#define LINE_SZ 80
char buf[LINE_SZ];
while (fgets(buf, sizeof buf, stdin) && buf[0] != 'e' && buf[0] != 'E') {
if (sscanf(buf, "%d", &num) != 1) {
Handle_other_non_int_input();
}
sub = #
printf("%d", num);
}
As noted in the comments, (sub != 'e' || sub != 'E') is always true. If sub can never be e and E at the same time.
Note that sub is an int and not an integer pointer (int *).
The line sub = # assigns sub with num's address.
And the value of sub is used in the control expression of the while loop before it is initialised. sub has garbage value at that point which is indeterminate. You have to initalise it with some value before using it.
Do
int num, rv;
while( 1 )
{
rv=scanf("%d", &num);
if(rv==0)
{
if( (num=getchar())=='e' || num=='E' )
{
break;
}
else
{
while(getchar()!='\n');
continue;
}
}
printf("\n%d", num);
}
A value is read into num by scanf() whose return value is stored in rv.
scanf() returns the number of successful assignments which in this case should be 1 if an integer value was read into num since %d is the format specifier.
If rv is 1, it is a number and is printed. Otherwise it could be a character which won't read by the scanf() and would remain unconsumed in the input buffer. The first byte of this data is read by the getchar() and if this is e or E, the loop is exited but otherwise the input buffer is cleared till a \n is encountered and the next iteration of the loop is done without going into the part where the printing takes place.
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;
}
I need to write a program in c that gets integers as input from the user.
input example:
10 20 50 70
The user presses Enter and then the input is over.
I can't think of a condition to make it happen. I tried to write:
int grades[1000];
int i=0;
while(scanf("%d", &grades[i])!=EOF)
{
i++;
}
It is not working.
Reading a line of user input and then parsing is really the best approach as with #The Paramagnetic Croissant
If code can not pre-define an input buffer size or must parse the line while it comes in then using scanf("%d",... is OK. Non-elegant code occurs with finding the '\n'.
#define N 1000
int grades[N];
int i=0;
for (i=0; i<N; i++) {
// Consume leading white-space, but not \n
int ch;
while ((ch == fgetc(stdin)) != '\n' && isspace(ch));
// normal exit
if (ch == '\n' || ch == EOF) break;
ungetc(ch, stdin);
if (1 != scanf("%d", &grades[i])) {
// Non-numeric data
break;
}
i++;
}
If you need read an entire line, then read an entire line, simple as that. If you google "C read line", you will most probably end up reading the documentation of fgets(). Then you google "C convert string to integer", and you perceive that there exists a function called strtol() in the C standard library. Armed with these two weapons, and applying some logic, you can deduce something like this:
const size_t max_numbers = 1000; // however many
int numbers[max_numbers];
size_t index = 0;
char buf[LINE_MAX];
while (index < max_numbers && fgets(buf, sizeof buf, stdin)) {
char *p = buf;
char *end;
while (index < max_numbers && *p && *p != '\n') {
numbers[index++] = strtol(p, &end, 10);
p = end;
}
}