Testing chars and ints within a char variable - c

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 = &num;
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 = &num; 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.

Related

I wrote a program which should terminate when 'n' or 'N' is entered but it doesn't work

It does not terminate when 'n' or 'N' is entered. How do i make it work?
Also, why will the "\n\nGive n or N to terminate loop" statement not work if I don't add flush(stdin)?
#include <stdio.h>
void main() {
int i, n, sump, sumn;
char ch;
sump = 0;
sumn = 0;
do
{
printf("\nGive integer n ");
scanf("%d", &n);
if (n > 0)
sump = sump + n;
else
sumn = sumn + n;
printf("\n\nGive n or N to terminate loop");
fflush(stdin);
scanf("%c", &ch);
} while ((ch != 'n') || (ch != 'N'));
printf("Sum of positive number=%d", sump);
printf("\nSum of negative number=%d", sumn);
}
When you press the Enter key for the numeric input (for the n variable) then that's added as a newline '\n'.
This newline is still in the input buffer of stdin when you read the character for ch.
And unlike many format which skips white-space (like newline) the %c format reads all characters, including that newline.
The #obvious" solution is simple: To ask scanf to skip any leading space, by adding a single space in the format string:
scanf(" %c", &ch);
// ^
// Note space here
And as mentioned in a comment by Stefan Riedel, the condition is incorrect as well. The negation of ch == 'n' || ch == 'N' is not ch != 'n' || ch != 'N'. Instead De Morgan's laws dictate that the connecting logical operation must change as well:
ch != 'n' && ch != 'N'
Or you could simplify it:
tolower(ch) != 'n'
There's another way to do this:
#include <stdio.h>
#include <stdlib.h>
int main() {
char inp[100];
int n, sump = 0, sumn = 0;
while(1)
{
printf("Give integer, or \"n\" to stop: ");
if(fgets(inp, sizeof(inp), stdin) == NULL) break;
if(inp[0] == 'n' || inp[0] == 'N') break;
n = atoi(inp);
if (n > 0)
sump = sump + n;
else
sumn = sumn + n;
}
printf("Sum of positive number=%d\n", sump);
printf("Sum of negative number=%d\n", sumn);
}
In this program, there's not a separate prompt for the "n".
You can type a number, or type "n".
This is much more convenient for the person entering the numbers.
But it means you can't use scanf to read the input, because there's no way to ask scanf to, "read a number, or maybe the string 'n'".
But it's actually fine to not use scanf for input, because it turns out scanf is actually pretty terrible for user input.
This program reads a whole line of input, as text, using fgets.
Then it looks at the first character of the line to see if it's 'n' or 'N'.
Then, if it wasn't an N, it calls atoi to convert the string into an integer.
There are better ways to convert strings to integers -- that is, atoi has its problems, so it's recommended to use the more sophisticated strtod in "real" programs, but atoi is nice and simple, and sort of an intermediate step here.

read ints from standard input until \n is found

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

Input, Output C Program

So thats my programm:
This program scans and prints numbers, but I want it to print "Mistake" if a character is entered. It produces an infinite loop if I put something like an "a" in. Why?
#include <stdio.h>
int main(void){
printf("Enter a number: \n");
int a;
while(scanf("%d",&a)!=EOF){
if(46<'a'<58){
}
else{
printf("Mistake.");
return -1;
}
printf("%d\n",a);
}
}
First of all, you cannot chain the relational operators in C. You need to change
if(46<'a'<58){
to
if ((46 < 'a') && ( 'a' < 58 )) {
to make it work.
That said, a char value is not a match for %d format specifier. You need to either
use %c to scan the input as char and check the ASCII value
use %d to scan the int input and check for the return value of scanf() for success. Also, in case scanf() fails for a non-int value, you need to clean up the input buffer before you loop again to avoid the infinite looping.
Read input as a string with fgets(), then test it as needed.
Using scanf("%d", ...) returns 0, 1, or EOF when it fails, reads an int or end-of-file is detected. Code could test that return value, but robust code simple does not use scanf().
char buf[100];
while(fgets(buf, sizeof buf, stdin) != NULL) {
int a;
if (sscanf(buf, "%d",&a) == 1) {
printf("%d\n",a);
} else {
puts("Mistake.");
}
}
if(46<'a'<58) does not work. it first compares 46<'a' which is 1:true and then compares 1 < 58 which is also true. #124...
46 < 'a' < 58 is always true, because 46 < 'a' evaluates to 1, and then 1 < 58 evaluates to 1. Also I suppose you want a, rather than 'a', which is actually a literal. Additionally, I think your code has some logical problems.
Here is the refined code:
#include <stdio.h>
int main(void){
puts("Enter a number:");
char a;
while(scanf("%c", &a) != EOF) {
if(('0' <= a && a <= '9') || a == '\n'){
putchar(a);
}
else
{
puts("Mistake.");
return -1;
}
}
}

' ', '\n' , scanf() and output screen

I wrote the following code to accept characters from user and enter into an array till he inputs a free space (' ') or a line \n. But code is not functioning. As in, when space bar or return key is pressed in the input, my computer is still accepting values without exiting the loop.
char X[99];
printf ("Type the string without spaces\n");
for (i=0;i<99;i++) {
scanf ("%c",&m);
if(m!=' '&&m!='\n')
X[i]=m;
else i=99;
}
Please explain the error.
First the issue: the default tty mode is canonical, meaning input is made available line by line (see man termios)
Once you fix that, you can use getchar() or read() to get one character at a time. The tty setting, example straight out of the man page of termios .
#include <stdio.h>
#include <termios.h>
int ttySetNoncanonical(int fd, struct termios *prev)
{
struct termios t;
if (tcgetattr(fd, &t) == -1)
return -1;
if (prev != NULL)
*prev = t;
t.c_lflag &= ~ (ICANON);
t.c_cc[VMIN] = 1; // 1-char at a go
t.c_cc[VTIME] = 0; // blocking mode
if (tcsetattr(fd, TCSAFLUSH, &t) == -1)
return -1;
return 0;
}
void main(void) {
printf ("\nType the string without spaces\n");
ttySetNoncanonical(0,NULL); // set to non-canonical mode
char X[1000];
int m, ec=0;
int i;
X[0] = 0;
for (i=0;i<1000;i++) {
//ec = read(0,X+i,1); // read one char at a time
m = getchar();
if(m == EOF || m==' ' || m=='\n') {
X[i] = 0;
break;
}
X[i] = m;
}
printf("You entered %s. Bye.\n\n", X);
}
HTH. You might want to check the boundary condition, in case your user typed in 1000 characters. It works for me on a GNU Linux.
use getch(), scanf() will not work that way.
it would be something like :
for(i=0;i<99;i++)
{
char ch=getch();
if(m!=' ' && m!='\n' && m!='\r')
X[i]=m;
else i=99;
printf("%c",ch);
}
The scanf function reads and ignores any whitespace characters encountered before the next non-whitespace character (whitespace characters include spaces, newline and tab characters). So, instead of
scanf("%c",&m);
use
m = getchar();
The function int getchar ( void ); gets character from stdin, returns the next character from the standard input (stdin). It is equivalent to calling getc with stdin as argument.
Also, the condition should use logical-AND as in:
if(m!=' '&& m!='\n')
Also, outside the loop, write,
X[i] = '\0';
Lets look into the if condition
if(m!=' '||m!='\n')
1. When m is space m=' ' (i.e. ASCII value 32)
m=' '
As per your if condition (Cond1 || Cond2), Cond1 will fail and o/p will be 0 but Cond2 will be TRUE, because it is not ' '.
if(FALSE || TRUE)
will be if(TRUE).
When your input is newline (i.e ASCII value 10).
m='\n'
Here Cond1 will be TRUE because it is not SPACE, due to this it will not check the second condition as per C. and will execute the if(TRUE) statement.
Please try to code it by yourself.... It will help you to clear few C doubts and u will get to know how || and && condition works.
Better to use getchar() instead of scanf in here as you read character by character. Usually we use scanf for get strings as input.
Using the logical operators: && (AND) operator checks for one condition to be false, while or || (OR) operator checks for one condition to be true. So if you use && operator, it checks whether it is a space, and if not, it returns false, without even checking the second condition(EOF). But if you use || operator, as used below, it checks for both cases. Check for more details in operators here
You also have to increment the counter (i) after adding an item to the array (Inside the if) as if you don't, it will continuously add items to the same place of the array, which means you will lost the precious inputs.
So, here's my code:
char X[99];
char m;
printf ("Type the string without spaces\n");
for (i=0;i<99;i++) {
m = getchar();
if(m == ' ' || m=='\n') {
X[i]=m;
i++;
}
else i=99;
}
With the function getch(); it ends if your pressing space or enter!
#include <stdio.h>
int main(void) {
char m, X[99];
int i;
printf("Type the string without spaces\n");
for (i = 0; i < 99; i++) {
m = getch();
if (m == ' ' || m == '\n' || m == '\r')
i=100;
else
X[i] = m;
printf("%c", m);
}
}
try this
#include <stdio.h>
int main(){
int i;
char m, X[99];
printf("Type the string without spaces\n");
for (i=0;i<98;i++){//98 --> sizeof(X) -1
scanf("%c",&m);
if(m!=' ' && m!='\n')
X[i] = m;
else
break;
}
X[i] = '\0';
puts(X);
return 0;
}
Here's a working code:
#include <stdio.h>
int main ()
{
char x[100] = {0};
char m;
int i, j;
printf ("Type:\n");
for (i=0; i<99; i++) {
m = getchar();
getchar();
if ((m != ' ') && (m != '\n')) {
x[i] = m;
} else {
printf ("Breaking.");
break;
}
}
printf ("\n");
for (j=0; j<i; j++)
printf ("%c\n", x[j]);
return 0;
}
Here I have used an extra getchar() to consume the newline used to enter the character m. And so (please note) you will also need to enter a newline after a space (' ') and a newline ('\n') to enter and store these in m and compare them in the next lines.
First error, as everyone has pointed out is the logical operator in the if() statement. It should be
if(m!=' ' && m!='\n')
As you want to check if the entered character is neither a (space) nor a \n, so you have to use the && operator.
Next, the error you are getting is because of something called the trailing character. When you enter a letter and press enter (at the point where your scanf("%c",&m) is asking for input). That letter gets stored in the variable m, but the newline character \n caused by the enter pressed is still in the stdin. That character is read by the scanf("%c",&m) of the next iteration of the for loop, thus the loop exits.
What you need to do is consume that trailing character before the next scanf() is executed. for that you need a getchar() which does this job. So now your code becomes something like this..
#include<stdio.h>
int main()
{
char X[99];
char m;
int i;
printf("Type the string without spaces\n");
for (i=0;i<99;i++)
{
scanf("%c",&m);
if(m!=' ' && m!='\n')
{
X[i]=m;
getchar(); // this statement is consuming the left out trailing character
}
else
i=99;
}
printf("%s",X);
}
Now, the program works exactly as you want.

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