getchar vs scanf: why won't getchar work? - c

I wrote a simple program to input a number and return any value which when divided by it will return a remainder of 3.
I'm currently reading K&R and it doesn't teach scanf until something like Chapter 7 so I tried to use getchar. It doesn't work, but scanf does. What am I doing wrong?
int main()
{
int c, i;
printf("Input an integer: ");
//c = getchar();
scanf("%d", &c);
for (i = 1; i <= 100; i++) {
if ((i % c) == 3) {
printf("%d\n", i);
}
}
return 0;
}
Optional side question: It seems like people here have been advising not to start with K&R. What might be a better alternative for a beginner?

This:
scanf("%d", &c);
Is requesting scanf() to read an integer value from standard input. The scanf() function will read from standard input as much characters as needed, and then parse them into an integer, storing the value in the variable c (i.e. at the address pointed by &c). The return value of scanf() also communicates the number of correctly parsed items, so in this case you should check if the returned value is 1.
This:
c = getchar();
Is requesting getchar() to read a single character from standard input. The getchar() function will try to read a character, and will return it (casted to an int) in case of success. In case of error or end of file, the special integer value EOF will be returned. The fact that getchar() returns an int doesn't mean that the function will parse the input like scanf("%d", ...) does. Indeed, the return value has type int only because it's needed to distinguish a valid character from EOF.
To know more, refer to the manual pages for scanf and getchar using the man command, e.g. man scanf. Consulting manual pages is important to understand the semantics of a function. Always read the manual. Alternatively, you can look it up online: scanf(), getchar().
If you want to scan a single character using getchar() and convert it into an integer, then you can do the following:
#include <stdio.h> // getchar(), puts()
#include <ctypes.h> // isdigit()
int main(void) }
int c;
c = getchar();
if (c == EOF) {
puts("Error!");
return 1;
}
if (!isdigit(c)) {
puts("Character is not a digit!");
return 1;
}
int value = c - '0';
// value now holds the integer corresponding to the digit that was read from input
/* ... */
return 0;
}
Note: c - '0' works because characters representing digits have sequentially increasing values in the ASCII table (from 0x30 to 0x39). See also man ascii.

getchar reads one symbol from the inputs stream and returns it as its integer value of its internal representation or EOF.
So to read a number that has at least two digits you have to call getchar several times and then convert the symbols' representations to the corresponding integer number.
Opposite to getchar scanf tries to read a whole number as an integer if you specified the conversion format %d or similar specially designed to read numbers
Here is a demonstrative program that shows how your program can be implemented using getchar. In the program there is no check whether the user entered a too big number. You can add such a check yourself.
#include <stdio.h>
#include <ctype.h>
int main(void)
{
const unsigned int REMAINDER = 3;
printf( "Input a non-negative integer: " );
unsigned int n = 0;
for ( int c; ( c = getchar() ) != EOF && isdigit( ( unsigned char )c ); )
{
const unsigned int Base = 10;
n = Base * n + ( c - '0' );
}
if ( n > REMAINDER )
{
const unsigned int N = 100;
for ( unsigned int i = 0; i < N; i++ )
{
if ( ( i + 1 ) % n == REMAINDER ) printf( "%u ", i + 1 );
}
putchar( '\n' );
}
return 0;
}
The program output might look for example like
Input a non-negative integer: 10
3 13 23 33 43 53 63 73 83 93
As for books then it is always difficult to read a book on a language or technology which you are not familiar yet.

Related

How to detect space and letters in a Char in C?

Do you know how I can detect space and letters in a CHAR variable?
I need to detect letters or space in a input of numbers:
This what I want to do:
Enter Document Number of 8 numbers:
// i press space and pressed enter
ERROR: please enter the age again: 4fpdpfsg
There's where my code doesn't detect the letters after the 4, and what I want is recognize that there's letters in the input, and then shows only the 4.
int isLetter(char input[]){
int i = 0;
while(input[i]!='\0'){
if((input[i]!=' ') && (input[i]<'a'||input[i]>'z') && (input[i]<'A'||input[i]>'Z'))
return 0;
i++;
}
return 1;
}
The standard C library has various character type testing functions. They are declared in the #include <ctype.h> header.
Unfortunately, the obvious way of using these functions is often wrong. They take an argument of type int which is actually expected to be an unsigned character value (a byte, effectively) in the range 0 to UCHAR_MAX. If you pass in a char value which happens to be negative, undefined behavior ensues, which might work by coincidence, crash or worse yet form a vulnerability similar to heartbleed (possibly worse).
Therefore the cast to (unsigned char) is quite likely necessary in the following:
#include <ctype.h>
/* ... */
char ch;
/* ... */
if (isalpha((unsigned char) ch) || ch == ' ') {
/* ch is an alphabetic character, or a space */
}
Simple character constants (not numeric escaped ones) derived from the C translation time character set have positive values in the execution environment; code which can safely assume that it only manipulates such characters can do without the cast. (For instance, if all the data being manipulated by the program came from string or character literals in the program itself, and all those literals use nothing but the basic C translation time character set.)
That is to say, isalpha('a') is safe; a is in the C translation time character set, and so the value of the character constant 'a' is positive. But say you're working with source code in ISO-8859-1 and have char ch = 'à';. If char is signed, this ch will have a negative value, which is fine according to ISO C because an accented à isn't in the basic C translation character set. The expression isalpha(ch); then passes a negative value to the isalpha function, which is wrong.
Try:
if (!((input[i] == ' ') || (input[i] >= 'a' && input[i] <= 'z') || (input[i] >= 'A' && input[i] <= 'Z')))
or, better:
#include <ctype.h>
if (!((input[i] == ' ') || isalpha(input[i])))
You could use sscanf(input,"%d%n",&number,&nrOfDigits) which reads in an integral value into number and additionally stores the position of the first character which has not been part of the number in nrOfDigits. With this information, you can then decide what to do, e.g. nrOfDigits < 8 would indicate that either the input was shorter than 8 characters, or that it does contain less than 4 consecutive digits. See sample code of the usage below.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int isLetter(char input[]){
int nrOfDigits=0;
int number;
int scannedElems = sscanf(input,"%d%n",&number,&nrOfDigits);
if (scannedElems == 0) {// number could not be read--
printf ("No number read.\n");
return 0;
}
else {
char c = input[nrOfDigits];
int isAlpha = isalpha(c);
printf("input %s leads to number %d with %d digit(s); first characer after the digits is '%c', (isalpha=%d)\n", input, number, nrOfDigits, c, isAlpha);
return number;
}
}
int main(){
isLetter("4fpdpfsg"); // input 4fpdpfsg leads to number 4 with 1 digit(s); first characer after the digits is 'f', (isalpha=1)
isLetter("afpdpfsg"); // No number read.
isLetter("12345678"); // input 12345678 leads to number 12345678 with 8 digit(s); first characer after the digits is '�', (isalpha=0)
return 0;
}
BTW: you could implement a similar logic with strtoul as well.
hey guys i finally get the way to detect the input is conformed only for 8 numbers theres the code
char* InputDni(char dni[])
{
int sizeletter;
int i;
fflush(stdin);
gets(dni);
// 8 is the size of DNI in argentina
while((isLetter(dni)) || (strlen(dni)!=8))
{
printf("ERROR: enter again the DNI: ");
fflush(stdin);
gets(dni);
}
sizeletter=strlen(dni);
for(i=0 ;i<sizeletter; i++)
{
while(isalpha(dni[i]))
{
printf("ERROR: enter again the DNI: ");
fflush(stdin);
gets(dni);
i++
}
}
return dni;
}
//isLetter
int isLetter(char input[])
{
int i = 0;
int sizeletter;
int flag=1;
sizeletter=strlen(input);
for(i=0;i<sizeletter;i++)
{
if((input[i]!=' ') && (input[i]<'a'||input[i]>'z') && (input[i]<'A'||input[i]>'Z'))
{
flag=0;
}
}
return flag;
}
picture of the code running in cmd:

How to scan in values and ignore the characters

I am a newbie to C and I was looking over some questions where I pondered upon a question where we need to scan in values using the users input. Example
1 2 3 45 6 7. So Automatically we scan these values into a 2D array.
One thing that troubles me is what If the user inputs
1 2 3 2 3 Josh, how can we ignore Josh and only scan in the values into the array.
I looked at using getchar and use a flag variable but I am unable to figure out the conundrum of differentiating between the integer and character.
/* This is something that I tried */
#include <stdio.h>
int main(int argc, char *argv[]) {
int a;
int b;
int A[10];
while (((a = getchar()) != '\n') && (b = 0)) {
if (!(a >= "A" && a <= "Z")) {
scanf("%d", A[b]);
}
b++;
}
}
}
I think one good method for achieving what you want is using scanf with the format "%s", which will read everything as a string, effectively splitting the input according to white spaces. From the manual:
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.
To convert the string to integer, you can use atoi. From the manual:
The atoi() function converts the initial portion of the string
pointed to by nptr to int.
So, if it converts the initial portion of the string into an integer, we can use that to identify what is a number and what's not.
You can build a simple "word detector" for atoi.
Using the function isalpha from ctype.h you can do:
int isword(char *buffer)
{
return isalpha(*buffer);
}
And rewriting your reading program you have:
#include <stdio.h>
#include <ctype.h>
int isword(char *buffer)
{
return isalpha(*buffer);
}
int main(void)
{
char input[200];
int num;
while (1) {
scanf("%s", input);
if (!strcmp(input, "exit")) break;
if (isword(input)) continue;
num = atoi(input);
printf("Got number: %d\n", num);
}
return 0;
}
You should keep in mind that the name isword is fallacious. This function will not detect if buffer is, in fact, a word. It only tests the first character and if that is a character it returns true. The reason for this is the way our base function itoa works. It will return zero if the first character of the buffer is not a number - and that's not what you want. So, if you have other needs, you can use this function as a base.
That's also the reason I wrote a separate function and not:
if (!isalpha(input[0]))
num = itoa(input);
else
continue;
The output (with your input):
$ ./draft
1 2 3 2 3 Josh
Got number: 1
Got number: 2
Got number: 3
Got number: 2
Got number: 3
exit
$
About assigments and &&
while (((a = getchar()) != '\n') && (b = 0))
As I said in a comment, this loop will never work because you're making a logical conjunction(AND) with an assignment that will always return zero. That means the loop condition will always evaluate to false.
In C, assignments return the value assigned. So, if you do
int a = (b = 10);
a will have now hold the value 10. In the same way, when you do
something && (b = 0)
You're effectively doing
something && 0
Which will always evaluate to false (if you remember the AND truth table):
p q p && q
---------------
0 0 0
0 1 0
1 0 0
1 1 1
Your code is completely wrong. I suggest to delete it.
You could use scanf with %d to read in numbers. If it returns 0, there is some invalid input. So, scan and discard a %s and repeat this process:
int num = -1;
while(num != 0)
{
printf("Enter a number, enter 0 to exit:");
if(scanf("%d", &num) == 0) /* If scanf failed */
{
printf("Invalid input found!");
scanf("%*s"); /* Get rid of the invalid input (a word) */
}
}

C-programming loop wont stop with scanf!=0

What is wrong with this ? Also, I have to use scanf(). It is supposed to read any integers and sum them, the loop is to stop when 0 is entered..
main (void){
int a;
int r=0;
while(scanf(" %d",&a)){
r=r+a;
}
printf("the sum is %d\n",r);
return 0;
}
Quoting from man
These functions return the number of input items assigned. This
can be
fewer than provided for, or even zero, in the event of a matching fail-
ure. Zero indicates that, although there was input available, no conver-
sions were assigned; typically this is due to an invalid input character,
such as an alphabetic character for a `%d' conversion.
The value EOF is
returned if an input failure occurs before any conversion such as an end-
of-file occurs. If an error or end-of-file occurs after conversion has
begun, the number of conversions which were successfully completed is
returned.
So, that pretty much explains what is returned by scanf().
You can solve the problem by adding ( 1 == scanf("%d", &a) && a != 0 ) as the condition in your while loop like
int main (void)
{
int a;
int r=0;
while( 1 == scanf("%d", &a) && a != 0 )
{
r=r+a;
}
printf("the sum is %d\n",r);
return 0;
}
Also note that you have to specify the type of main as int main().
I would also like to add that the loop will end when you enter a character like 'c' ( or a string ) and it will show the sum of all the numbers you entered before entering the character.
scanf() doesn't return what it has written to the variable. It returns the total number of items successfully filled.
EDIT:
You would be much better off using fgets() to read from stdin and then using sscanf() to get the integer, which you can check against 0.
#define BUFF_SIZE 1024
int main (void)
{
int a;
int r = 0;
char buffer[BUFF_SIZE] = {0};
while(1) {
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, "%d", &a);
if(!a)
break;
r = r + a;
}
printf("the sum is %d\n", r);
return 0;
}

Odd printing behavior in C

I'm trying to print out comma seperated values in my C program, but I think I keep getting memory allocations instead.
When running from the command line, this happens.
1
49 this is the response
10 this is the response
1
49 this is the response
10 this is the response
Here is my program:
void main(){
int j;
int idnum;
j = 0;
char entry[99];
do{
idnum = get_field(entry);
j++;
}
while(idnum!='\n' && idnum!= ',' && j!= MAXTYPES);
int recur = 0;
while (recur != 4){
printf("%4d\n", entry[recur]);
recur++;
}
printf("\nEnd of Input\n");
}
int get_field(char entry[]){
int idnum;
char n;
int j = 0;
char temp[45];
while ((n=getchar())!= EOF){
printf("%d this is the response\n",n);
}
return idnum;
}
Problems I see:
In get_field, you have not initialized idnum and returning it from the function.
In get_field, the while loop to read the data is strange. I am not sure what you are trying to accomplish. However, you if type 1 and then press Enter, two characters are added to the input stream: '1' and '\n'. You are reading them as char, using getchar, and printing them as int (by using the "%d" format).
That explains the output you are getting.
49 is the decimal representation of '1'.
10 is the decimal representation of '\n'
The return type of getchar is int. You should change the type of n in get_field to int from char. That could be source of problems depending on the platform you are working in.
With %d you are printing the ASCII values. ASCII value of 1 is 49 and of \n is 10.
These are what you are getting.
You may want to print them with %c.
Since n is a char type data.So,you've to use %c instead of %d Like this:
printf("%c this is the response\n",n);

How to ignore floating number in scanf("%d")?

If user enters floating number for an integer variable I want to print invalid input. is that possible?
int a;
scanf("%d",&a); // if user enters 4.35 print invalid input
I have tried for characters like this
if(scanf("%d",&a)==1);
else printf("invalid input");
But how to do for floating numbers. If user enters 4.35 it truncates to 4 but I want invalid input.
Since the start of a floating point number with any digits before the decimal point looks like an integer, there is no way to detect this with %d alone.
You might consider reading the whole line with fgets() and then analyzing with sscanf():
int a;
int n;
char line[4096];
if (fgets(line, sizeof(line), stdin) != 0 && sscanf(line, "%d%n", &a, &n) == 1)
...analyze the character at line[n] for validity...
(And yes, I did mean to compare with 1; the %n conversion specifications are not counted in the return value from sscanf() et al.)
One thing that scanf() does which this code does not do is to skip blank lines before the number is entered. If that matters, you have to code a loop to read up to the (non-empty) line, and then parse the non-empty line. You also need to decide how much trailing junk (if any) on the line is tolerated. Are blanks allowed? Tabs? Alpha characters? Punctuation?
You'll have to read it as a double and then check if it is an integer. The best way to check if it is an integer is to use modf, which returns the decimal portion of the double. If there is one you have an error:
double d;
scanf("%lf", &d);
double temp;
if(modf(d, &temp)){
// Handle error for invalid input
}
int a = (int)temp;
This will allow integers or floating point numbers with only 0s after the decimal point such as 54.00000. If you want to consider that as invalid as well, you are better off reading character by character and verifying that each character is between 0 and 9 (ascii 48 to 57).
This can not be done with out reading pass the int to see what stopped the scan.
Classic idiom
char buf[100];
if (fgets(buf, sizeo(buf), stdin) == NULL) {
; // deal with EOF or I/O error
}
int a;
char ch;
if (1 != sscanf(buf, "%d %c", &a, &ch)) {
; // Error: extra non-white space text
}
You can do it using strtol() and strtod() and comparing the end pointers, e.g. this:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buffer[100];
char * endptr_n;
char * endptr_d;
long n;
double d;
fgets(buffer, 100, stdin);
n = strtol(buffer, &endptr_n, 10);
if ( endptr_n == buffer ) {
fputs("You didn't enter a number.", stderr);
return EXIT_FAILURE;
}
d = strtod(buffer, &endptr_d);
if ( *endptr_d == '\0' || *endptr_d == '\n' ) {
if ( endptr_d == endptr_n ) {
puts("You entered just a plain integer.");
} else {
puts("You entered a floating point number - invalid.");
}
} else {
puts("You entered garbage after the number - invalid.");
}
return EXIT_SUCCESS;
}
outputs:
paul#local:~/src/c$ ./testint
2
You entered just a plain integer.
paul#local:~/src/c$ ./testint
2.3
You entered a floating point number - invalid.
paul#local:~/src/c$ ./testint
3e4
You entered a floating point number - invalid.
paul#local:~/src/c$ ./testint
4e-5
You entered a floating point number - invalid.
paul#local:~/src/c$ ./testint
423captainpicard
You entered garbage after the number - invalid.
paul#local:~/src/c$
It doesn't use scanf(), but that's a good thing, and it avoids the need to manually check the input following the integer you read.
Obviously, if the only thing on the line is the number, then a lot of this becomes unnecessary, since you can just call strtol() and check *endptr_n immediately, but if there may be other stuff on the line this is how you can do it, e.g. if you want to accept an integer followed by anything non-numeric, but not a floating point followed by the same thing, you can just remove the if ( *endptr_d == '\0' || *endptr_d == '\n' ) logic.
EDIT: updated the code to show the check to *endptr.
This one is bit easier:
#include <stdio.h>
int main()
{
int a;
long double b;
scanf("%f",&b);
a = (int) b;
a == b ? printf("%d\n",a) : printf("Invalid input!");
return 0;
}
Input: 4
Output:
4
Input: 4.35
Output:
Invalid input
Here's an easy way:
#include <stdio.h>
int main(int argc, char **argv) {
int d;
printf("Type something: ");
// make sure you read %d and the next one is '\n'
if( scanf("%d", &d) == 1 && getchar() == '\n' ) {
printf("%d\n", d);
}
return 0;
}
.
$ a.exe
Type something: 312312.4214
$ a.exe
Type something: 2312312
2312312
$ a.exe
Type something: 4324.
$
First of all, there is nothing wrong with scanf. When a user enters a float then they actually type in a number dot number. So, code a scanf to detect that data entry.
main()
{
char c1[2];
int num1;
int nr_nums;
nr_nums = scanf("%d%1[.e0123456789]", &num1, &c1);
if (nr_nums == 1) {printf("\ndata = %d", num1);}
if (nr_nums == 2) {printf("\nInvalid");}
}
Modified this code per another possible data entry format of 1. or 3e-1 as suggested by a comment.
This code gets to the basics of your requirement. It accepts Integer data entry and detects when a float is entered.
If you have your number represented as a string (when you have used fgets) you can run a for loop through it and compare each character to '.'.
One other option I can see follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char mystring[31];
scanf("%30s[0-9]\n", mystring);
int mynumber = atoi(mystring);
printf("here is your integer: %d", mynumber);
getchar();
getchar();
return 0;
}

Resources