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;
}
}
Related
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 relatively new to C and would like to know how to prevent an overflow from input...
So for example, I have:
scanf("%d", &a);
Where a is an integer.
So what I could I do to prevent someone from entering a number that's larger than max integer? Due to the constraints of the problem I'm working on, you HAVE to use scanf. How do I go about restricting the input?
It is very challenging to prevent user input.
There is no magic hand to reach out and stop the user from beating away at the keyboard.
But code can limit what it reads.
scanf() is tough to limit. It may not set errno on overflow. Code can limit the number of char to say 9. That's a first step but one can not enter values like "1000000000" or "00000000000000001".
// Assume INT_MAX = 2,147,483,647.
scanf("%9d", &a);
A pedantic method would use fgetc(). An unsigned method follows. int takes a bit more.
unsigned a = 0;
int ch = fgetc(stdin);
while (isspace(ch)) {
ch = fgetc(stdin);
}
while (isdigit(ch)) {
ch -= '0';
if (a >= UINTMAX/10 && (a > UINTMAX/10 || ch > UINTMAX%10)) {
a = UINTMAX;
break; // overflow detected.
}
a = a*10 + ch;
ch = fgetc(stdin);
}
ungetc(ch, stdin); // Put back `ch` as it was not used.
But I prefer to change the goal and simply tell the user again, even if it means reading in more characters.
// 0:success or EOF
int Read_int(const char *prompt, int *dest, int min, int max) {
for (;;) {
char buf[(sizeof(int)*3 + 3)*2]; // 2x generous buffer
fputs(prompt, stdout);
if (fgets(buf, sizeof buf, stdin) == NULL) {
return EOF;
}
char *endptr;
errno = 0;
long l = strtol(buf, &endptr, 10);
// no conversion or junk at the end ....
if (buf == endptr || *endptr != '\n') {
continue;
}
if (!errno && l >= min && l <= max) {
*dest = (int) l;
return 0; // success
}
}
}
// Sample usage
int a;
Read_int("Enter an `int`\n", &a, INT_MIN, INT_MAX);
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");
}
}
}
I have two problems writing my code. The first problem I have is getting my getchar() to work if the user enters no text and just hits enter. I need to print an error if they do so and prompt the user to reenter the text in a loop until they do enter text. Is there any way to do so because everything I have tried has failed.
Here is the code I have for that section:
printf("Enter a text message: ");
while((c=getchar()) != '\n' && c != EOF)
{
text[i]= c;
i++;
}
I am new to C so I am limited on ideas to fix my dilemma. As you can see I am setting the input equal to an array. This leads to my second problem, I need to limit the input to no more than 100 characters. But, instead of giving the user an error I need to just chop off the extra characters and just read the first 100.
The simplest solution to your problem is to use fgets. We can give limit to the input so that it doesn't read the extra characters after the given limit.
Refer this sample code. Here I am printing the string if the user is not pressing Enter key:
#include <stdio.h>
int main()
{
char str[100];
fgets(str, 100, stdin);
if(str[0] != '\n')
{
puts(str);
}
return 0;
}
#include <stdio.h>
#define MAXSIZE 100
int main() {
char text[MAXSIZE+1]; // one extra for terminating null character
int i = 0;
int c;
while (1) {
printf("Enter a text message: ");
i = 0;
while ((c = getchar()) != '\n' && c != '\r' && c != EOF) {
if (i < MAXSIZE) {
text[i]= c;
i++;
}
}
if (i > 0 || c == EOF)
break;
printf("Empty string not allowed.\n");
}
text[i] = '\0';
printf("You entered: %s\n", text);
return 0;
}
Test code to detect non-compliant system:
#include <stdio.h>
int main() {
int c;
printf("Just hit enter: ");
c = getchar();
if (c == '\r')
printf("\\r detected!!!\n");
else if (c == '\n')
printf("\\n detected.\n");
else
printf("Yikes!!!\n");
return 0;
}
First of all getchar() can take only one character an input. It cannot take more than one character.
char c;
int total_characters_entered = 0;
do
{
printf ("Enter a text message: ");
c = getchar();
if (c != '\n')
{
total_characters_entered++;
}
} while (total_characters_entered <= 100);
I have written some code that will iterate in while loop until user has entered 100 characters excluding "Simple Enter without any text"
Please let me know if it does not satisfy your requirement. We will work on that.
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++]);
}
}