Use scanf() to input to multiple variables? - c

I am wondering if it is possible to use scanf() to read one line (actually just 1 digit from 0 to 9) and input the data as both a char variable and an integer variable so the user only has to enter the number once. Any help would be greatly appreciated. I am writing in C, using nano as my text editor, gcc as my compiler, and Ubuntu 12.04 as my OS. I also have access to Windoze, if necessary. Thanks in advance!

You can read the integer in with scanf and then convert it to a character by adding '0'. Since digits are always represented sequentially, this will convert any single digit integer to its corresponding character value.
int i;
do {
printf("Enter an integer: ");
scanf("%d", &i);
if (i < 0 || i > 9)
printf("Please try again (number must be between 0 and 9)\n");
} while (i < 0 || i > 9);
char c = i + '0';
// now i has the number and c has the character
printf("%d %c\n", i, c); // outputs, e.g., 4 4

You don't want to take the variable in twice, you want to use a cast or type conversion.
Read the variable as a character, check if it is between '0' and '9' (character zero and character nine), and if it is, cast it to an int like so: int x = (int)(my_character-'0');.
If you want to be very safe or need more-than-one-character strings, see the atoi function.

Related

Output the decimal versions of unknown input

I'm trying to write a short script to take in 6 inputs that will be in decimal, hex or octal and output their decimal versions. For example, if I input 1, 1 should be output. Input 010, should get 8, input 0x20, should get 32. Do I have to test each value to see if scanf reads it as its type or can I cast them after scanf reads them all as is? Also do I need functions to convert the octal and hex values to decimal or can I cast them? I'm very new to C and don't understand it well yet, but here's what I have so far (it outputs -200 as 32765 for whatever reason):
int num[6];
printf("Enter six integers:\n");
int i = 0;
int j;
while (i < 6){
if(scanf("0x%x", &j) == 1){
scanf("0x%x", &num[i]);
//hexToDec(num[i]);
} else if (scanf("0%o", &j) == 1){
scanf("0%o", &num[i]);
//octalToDec(num[i]);
} else {
scanf("%i", &num[i]);
}
i+=1;
}
for(int p = 0; p < 6; p+=1){
printf("%i\n", num[p]);
}
Answer for future reference: simply scanning in with "%i" does the conversions automatically. Revised code below:
int main(){
int num[6];
printf("Enter six integers:\n");
int i = 0;
while (i < 6){
scanf("%i", &num[i]);
i+=1;
}
for(int p = 0; p < 6; p+=1){
printf("%i\n", num[p]);
}
}
You cannot use scanf("0x%x", &j) to test the input and then use scanf("0x%x", &num[i]) to put the value in num[i]. scanf consumes the characters it accepts, so they are no longer in the input stream. When you do the second scanf, the characters are gone.
Instead, just attempt to scan the desired thing. If it works, you are done. If it does not work, go on to an else:
if (scanf("0x%x", &num[i]) == 1)
; // Worked, nothing to do.
else if (scanf("0%o", &num[i]) == 1)
;
else if (scanf("%i", &num[i]) == 1)
;
else
{
// Nothing worked, should put error-handling code here.
}
That is actually not great code for real applications, because scanf will consumes some of the input even if it ultimately fails. For example, with scanf("0x%x", &num[i]), if the input contains “0x” but then contains a non-hexadecimal character, scanf will consume the “0x” but leave the next character. However, it suffices for a learning exercise.
Once you have values in the num array, they are just int values. They are mathematical values, not numerals that are in octal, decimal, or hexadecimal. You can print them with %o for octal, or %d or %i for decimal. The original numeral is irrelevant. When printing, the mathematical value will be used to format a string in the requested base.
You should not use %x for printing an int, as %x is for unsigned int. However, you could convert an int to unsigned int and then print it with %x.
Note that you should not scan to int objects with %x. %x is for scanning to unsigned int objects. You can actually scan hexadecimal, octal, and decimal using:
if (scanf("%i", &num[i]) == 1)
;
else
…
The %i specification will recognize hexadecimal numerals beginning with “0x”, octal numerals beginning with “0”, and decimal numerals.
If you did not want to use %i for all three, because you want direct control for some reason, you will need to write more code. Standard C does not provide a direct way to scan only a hexadecimal numeral to an int. You would need to get the characters from the input and calculate the value from them or scan to an unsigned int and then convert the result to an int.
You can use function strtol with a base of 0 to do auto-detection of the integral value's base according to the input strings format (cf, for example, strtol documentation at cppreference.com):
long strtol( const char *str, char **str_end, int base )
Interprets an integer value in a byte string pointed to by str. ...
The valid integer value consists of the following parts:
(optional) plus or minus sign
(optional) prefix (0) indicating octal base (applies only when the base is 8 or ​0​)
(optional) prefix (0x or 0X) indicating hexadecimal base (applies only when the base is 16 or ​0​)
If the value of base is ​0​, the numeric base is auto-detected.
So a call like long val = strtol("0x10",NULL,0); will yield a decimal value of 16.
Note that you can also use scanf in conjunction with format specifier %i, since this is defined to behave just as a call to strtol:
​int scanf( const char *format, ... )
%i matches an integer. The format of the number is the same as expected by strtol() with the value ​0​ for the base argument (base is
determined by the first characters parsed)
The quick answer is use only
if(scanf("%i", &j) == 1){
...
}
what I have so far (it outputs -200 as 32765 for whatever reason):
Yet error handing of scanf() is troublesome. Far better to read the line of user input with fgets() and then parse the line - perhaps with strtol().

isdigit() returning true for integers 10 and up

Novice C student here.
Could someone please explain why isdigit() is returning true for values 10+?
I'm doing a pretty basic assignment regarding a guessing game and must use isdigit() to inform user if he has entered a number 1-10 or not.
The program seems to be running fine otherwise, I just would like to know the reasoning behind isdigit() returning true for values 10+.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
int main()
{
int iRandomNum = 0;
char cResponse = '0';
srand(time(NULL));
iRandomNum = (rand() % 10) + 1;
printf("\nGuess a number between 1 and 10: ");
scanf("%c", &cResponse);
if (!isdigit(cResponse) || cResponse<'0'+1)
printf("\nYou did not enter a number 1-10");
else if ((cResponse - '0') == iRandomNum)
printf("\nCorrect!");
else
{
printf("\nSorry, you guessed wrong\n");
printf("The correct guess was %d\n", iRandomNum);
}
return 0;
}
If you add a printf to log the value of cResponse, the problem will become apparent very quickly:
printf("\nGuess a number between 1 and 10: ");
scanf("%c", &cResponse);
printf("cResponse is %c\n", cResponse);
outputs:
Guess a number between 1 and 10: 10
cResponse is 1
As you can see, only the first character is stored in cResponse (which makes sense, as it's just a single character), and since that first character is a digit, your isdigit() call returns true.
If you want to read numbers greater than 10, you can read to an int instead:
int cResponse = 0;
printf("\nGuess a number between 1 and 10: ");
scanf("%d", &cResponse);
printf("cResponse is %d\n", cResponse); // prints '10' if I type '10'
Note that you cannot use isdigit() in this case, although you can still easily check your bounds using if (cResponse >= 0 && cResponse <= 10).
You are passing a char to isdigit, which can only hold a single character. Thus, while you may be typing in 10, only the first character (which is a digit) is getting into cResponse.
Instead of reading the users input as a char, read it in as an int. This way you can just use if(guess >= 1 && guess <= 10). Since you need 10 as part of the range of inputs a char (which is a single character) wont do. You will either need to use a string (which will make things more complicated) or just use an int.

Having Difficulty with isdigit() in C

I have been trying to add some experience in C to my experience with Python and started with a basic addition program. One thing that I'm trying to do is check if the input is a number or a character as seen here:
#include <stdio.h>
#include <ctype.h>
int main()
{
int n, sum=0,c,value;
printf("Enter the Number of Integers You Want to Add\n");
scanf("%d", &n);
if(isdigit(n))
{
printf("Enter %d Integers\n", n);
for(c=1; c<=n; c++)
{
scanf("%d", &value);
if(isalpha(value))
{
printf("ENTER INTEGER NOT CHARACTER\n");
break;
}
else
{
sum = sum + value;
}
}
printf("Sum of Entered Integers = %d\n",sum);
}
else
{
printf("ENTER INTEGER NOT CHARACTER\n");
break;
}
return 0;
}
Initially I had tried this using isalpha(), and the program worked fine when adding numbers but interpreted characters as zeros instead of printing the "not an integer" statement. However, now that I reworked it to use isdigit(), it does not recognize ANY input as an integer, whether or not it is. Is there something that I'm just doing wrong?
When you use scanf to read an integer, you get just that, an integer. (To read a single character, you need %c and a pointer-to-char).
When you use isdigit(), you need to supply the representation of that character (e.g. in ASCII, the character '0' has the representation 48, which is indeed its value as an integer). To recap:
isdigit(0) is false
isdigit(48) is true (for ASCII, ISO8859, UTF-8)
isdigit('0') is true (no matter the character set)
isdigit('0' + n) is true for integers n = 0 ... 9
PS: Not testing the return value from scanf is asking for trouble...
Neither isdigit nor isalpha work as you think they do. The intent of those library functions is to check whether a given code point, represented as an int, is within a subset of points defined by the standard to be digit characters or alpha characters.
You should be checking the results of your scanf calls rather than assuming they just work, and acting on those results accordingly. If you request an integer and one is successfully scanned, then it will tell you so. If that fails, your course of action is probably to consume the rest of the line (through newline or EOF) and possibly try again:
#include <stdio.h>
int main()
{
int n,value,sum=0;
printf("Enter the Number of Integers You Want to Add\n");
if (scanf("%d", &n) == 1 && n > 0)
{
printf("Enter %d Integers\n", n);
while (n--)
{
if (scanf("%d", &value) == 1)
{
sum = sum + value;
}
else
{
// consume the rest of the line. if not EOF, we
// loop around and try again, otherwise break.
while ((value = fgetc(stdin)) != EOF && value != '\n');
if (value == EOF)
break;
++n;
}
}
printf("Sum of Entered Integers = %d\n", sum);
}
return 0;
}
Properly done you should be able to enter valid integers beyond single digits (i.e. values > 10 or < 0), which the above allows.
The %d marker to scanf tells it to interpret the input as a number (more accurately, it indicates that the pointer in the arguments points to an integer type). It can't do anything but put an integer into that argument. If it can't interpret the input as a number, scanf stops scanning the input and returns immediately.
isdigit() evaluates its argument as a character code, as Jens points out above. However, scanf already turned the character code into a pure number.
From the scanf man page:
On success, the function returns the number of items of the argument list
successfully filled.
In your program, you are trying to read just one item from stdin, so scanf should return 1. So check for that and you'll know that it all worked out ok:
printf("Enter the Number of Integers You Want to Add\n");
while(scanf("%d", &n) != 1) {
printf("That's not a valid integer. Please try again.\n");
}
You cannot use isdigit() the way you are using it because you're already using scanf to convert the user input to an integer. If the user had not input an integer, scanf would have already failed.
Look at the man pages for all the C functions you are using, they will show you what the function expects and what the return values will be under different circumstances.
In the case of isdigit(), the input is expected to be an unsigned char representing an ASCII character. This can be a bit confusing because ASCII characters are in fact represented as a type of integer, and a string is an array of those. Unlike languages like Python which hide all that from you. But there is a big difference between the STRING of a number (array of characters that contain the characters of the digits of the number) and the INTEGER itself which is in a form the processor actually uses to do math with... (simplified explanation, but you get the idea).

How can I read a varying amount of integer input in C?

I will be getting three lines of input. The first line will give me 2 integers and the third line will give me 1 integer. But the second line can give me any number of integers ranging between 1 to 100. For example, the input could be:
2 1
5 6 1 9 2
10
or could be:
10 4
5 6
9
I can read the second line of integer input into an integer array for a fixed number of integers, but cannot do so for a varying number of integers. I suppose, in this case, I should use a while loop which will break when scanf() finds a newline. How do I code that?
Read the line into a buffer (#John Coleman) using using fgets() or getline().
Parse the string looking for whitespace that may contain a '\n', exit loop if found. Then call strtol() or sscanf() to read the 1 number. Check that function's return value for errors too.
Repeat above steps.
I am actually a newbie in programming and am unaware of most of the functions. The only string functions I know of are strlen() and strcmp(). And my i\o function knowledge is limited to printf() and scanf().
Anyhow, I solved my problem in this way:
int a[101];
int i, num;
char ch;
for (i = 0; i < 101; i++)
a[i] = 0;
while (1)
{
scanf("%d%c", &num, &ch);
i = num;
a[i] = num;
if (ch == '\n')
break;
}
This works!
The value of num had to be equal to the value i because my program needed it.

Storing int variable from user into array in C

I am fairly new to c programming, and also this forum but I thought I would give it a try. What I want to do is have a user enter a 4 digit number. From there i want to take the number and store it in an array, so as i could call arr[2] when I need it and so on and so on. Thanks in advance for any help!
I would really like to know what is going on here. Thanks again
Many possibilities exist to implementing the behavior you want. Here's one way of doing it:
int arr[4];
int i;
char var1[4];
printf("Please enter a 4 digit number: ");
scanf("%s", var1);
for (i = 0; i < 4; i++ ) {
arr [i] = var1[i] - '0'; // convert char to int
printf("%d", arr[i]);
}
printf("\n");
Your code does not do what you think it does. scanf reads a line from the console. %d matches a number (i.e. 123), not a digit (i.e. 1, 2, 3). You call printf in a loop, not scanf (i.e. you capture one number and you print it multiple times).
Actually, I see it is more than that - you are assuming integer in C++ means digit. Your array of 4 integers does not hold a 4 digit number - it holds four separate integers, each of which can be (usually) from -2147483648 to +2147483648.
The thing is, it's not easy to break a number into digits - because "digits" are base 10 (decimal) while a computer thinks in base 2 (binary). What we can do instead is read and write the number and digits as text, instead. Read the integer as a string, and write each digit as a character:
#include <stdio.h>
int main()
{
char input[4];
//get input as text, instead of as a number
printf ("Please enter a 4 digit number: ");
scanf ("%s", input);
for ( int i = 0; i < 4; i++ )
{
//print as char instead of as number
printf ("%c\n", input[i]);
}
}
This code is not perfect. If the user entered "blah" it will print "b" "l" "a" "h" instead of complain about non-numeric input. If the user enters more than 4 characters, our array of characters to hold the number will overflow causing serious security risks and a crash.
var1 is an integer and you are storing it in each element of the integer array arr, hence the output
If you want to store each number as a character, use fgets, or if you want to store it a number, do
i=0;
while(var1){
arr[len-i-1] = var1%10; //len is 4 in your case
var1 /= 10;
i--;
}
You have asked scanf to read an integer value. You might want to read a string instead.
In a pinch, you can use fgets:
char number[5];
if( fgets(number, sizeof(number), stdin) != NULL )
{
for( i = 0; i < 4; i++ ) {
printf( "%c\n", number[i] );
}
}

Resources