Convert scanf to a different argument size - c

Let's say I have the following to print a character entered by the user (using int to allow EOF in other places):
int ch;
scanf("%d", &ch);
printf("The character you entered was: %c\n", (char) ch);
Here, I am converting to a char in the printf function. How would I do that in the scanf function instead? For example, something like:
int ch;
scanf("%c", & (char) ch); // ???
printf("The character you entered was: %c\n", ch);
How would that be done?

You would scan a char and afterward convert it to int:
char c;
int ch;
if (scanf(" %c", &c) == 1) {
ch = (unsigned char) c;
} else {
ch = EOF;
}
The explicit conversion to unsigned char produces a result analogous to getchar()'s. There is a subsequent automatic conversion from that result to type int. In the case where scanf() fails to scan a character (other than leading whitespace), ch is set explicitly to EOF, much as getchar() would do.
Note also that the given format explicitly skips leading whitespace, as %d and most other format directives automatically do, but %c does not. This is for consistency with your %d variation -- it is not what getchar() does.
If you scan just one char into an otherwise uninitialized int, then you may not use the resulting int value without evoking undefined behavior on account of the three indeterminate bytes. Even if you initialized your int first -- to zero, say -- scanning one byte into it does not necessarily produce an int with the same value as that char, so no, no trick with scanning directly to the int is reliable. Theoretical UB aside, that could not be expected to work as you want on a big-endian machine or if the integer value of the scanned character were negative.

This cannot be done.
In
scanf("%c", xxx);
the xxx part simply must be an expression of type pointer-to-char.
So you must either do
char c;
scanf("%c", &c);
or, if you really want to get it into an int variable, you're going to have to do something like
int i;
char c;
scanf("%c", &c);
i = c;
If you were to try to do
scanf("%c", (char *)&i); /* WRONG */
you're doing something that's at best squirrelly and at worst (in other, related cases) downright undefined. It might seem to work, but it would be quite wrong.
For example, I just tried
int i = 0x01020304;
scanf("%c", (char *)&i); /* WRONG */
printf("i = %c\n", i);
printf("i = %d = %x\n", i, i);
and typed "X". The first printf printed i = X, so it seemed to work. But the second printf printed i = 16909176 = 1020378, which is certainly not the ASCII value of the character 'X'! On a big-endian machine, it probably would have worked even less well.
Why doesn't it work? Well, scanf and %c expect an argument of type pointer-to-char, because %c is going to fill in precisely one value of type char. If you say
scanf("%c", &i); /* WRONG */
it's wrong, and a conscientious compiler will typically warn you with something like "warning: format specifies type 'char *' but the argument has type 'int *'". If you try to shut the compiler up, by writing
scanf("%c", (char *)&i); /* WRONG */
the cast will indeed make the warning go away, and now we're left with the problem that we started with a pointer-to-int, and we're pretending it's a pointer-to-char. scanf will play along with the game, but: it will use the pointer to fill in only one byte of the int variable, leaving the rest completely alone.

Well, you could always do this:
int ch;
scanf("%c",(char*) &ch);
printf("you entered %c\n",ch);

Related

A problem with the behaviour of scanf when data type is unsigned char

So I have no idea why this behavior is observed:
#include <stdio.h>
int main()
{
unsigned char c;
char d;
scanf("%hhu", &d);
printf("%c\n", d);
return 0;
}
If I remember correctly %hhu is for unsigned char. If I input almost any character like a, or b the answer is nothing and d gets the value 0. But if I input 97 then d prints the value a (so ASCII is converted to char). This clearly not the case when the data type is char. I can just input the character directly and it is stored.
Also in the slight modification of this code
#include <stdio.h>
int main()
{
unsigned char c;
char d;
int g;
scanf("%hhu", &d);
printf("%c\n", d);
scanf("%d", &g);
printf("%d is g\n", g);
return 0;
}
If I give first input as a character like w or a then it just skips the second scanf, but if the input is a number then it works normally.
You are correct that the %hhu format specifier expects an unsigned char* argument. However, the u part of the format dictates that the input be interpreted as a decimal integer. To input the data as an (unprocessed) character, you should use the %c format specifier.
Format specifier %u is for reading decimal integer and %hhu is %u with length modifier added.
To read one character to char variable, use specifier %c.
If I input almost any character like 'a', or 'b' the answer is nothing and d gets the value 0. But if I input 97 then d prints the value a. (so ASCII is converted to char) This clearly not the case when the data type is char.
What scanf does is not related to the type but to the format specifier you use (which in turn defines what types are expected in the arguments).
When you use %hhu, the input is read as a signed decimal integer, parsed as strtoul would, and stored in an unsigned char. This is why 97 is read correctly.
Further, in both examples you should take into account the return value to know whether there was any failure. That way you will be able to detect errors and do whatever is required, like asking the user again.
a is not a valid input for %hhu. An integer (in the Math sense) is expected. If we add error checking (code below), we get:
$ gcc -Wall -Wextra -pedantic a.c -o a && ./a
a
Number of assigned variables: 0
Can't read: Invalid input
#include <stdio.h>
#include <stdlib.h>
int main(void) {
unsigned char c;
int rv = scanf("%hhu", &c);
if (rv == EOF) {
if (ferror(stdin)) {
perror("Can't read");
} else {
fprintf(stderr, "Can't read: Premature EOF\n");
}
exit(1);
}
printf("Number of assigned variables: %d\n", rv);
if (rv < 1) {
fprintf(stderr, "Can't read: Invalid input\n");
exit(1);
}
printf("%hhu\n", c);
return 0;
}
Invalid input stays in the handle's buffer to be obtained by future reads. So an error in a early scanf can cause later scanf to fail.
If you wish to proceed after an error, you could simply read until you get a LF to clear any "junk" in the buffer.
void read_stdin_to_eol(void) {
while (1) {
int ch = getchar();
if (ch == '\n' || ch == EOF)
return ch;
}
}
If I remember correctly %hhu is for unsigned char. If I input almost any character like 'a', or 'b' the answer is nothing and d gets the value 0.
"%hhu" expects input text to be numeric like "123". Then the value of 123 is save in d. d did not get the value of 0. d was not changed by the scanf("%hhu", &d); as input was invalid.
If you want to read a character into an unsigned char
unsigned char d;
if (scanf("%c", &d) == 1) Success();
If you want to read a numeric text into an unsigned char
unsigned char d;
if (scanf("%hhu", &d) == 1) Success();
In all cases, test the return value of scanf().
If I give first input as a character like 'w' or 'a' then it just skips the second scanf, but if the input is a number then it works normally.
When scanf() fails to convert input text per the provided specifiers, scanning stops and the offending text remains in stdin.
A common code idiom is to read remaining input and toss it until '\n'.
int ch;
while ((ch = getchar()) != '\n') && ch !- EOF) {
;
}

How do I fix a run-time error emitted by a safe function from Annex K?

I am starting out in C and I need to write a program that outputs the ASCII character for a given integer.
This is what I have:
#include <stdio.h>
int main(void)
{
char ch;
printf("Enter an ASCII code: ");
scanf_s("%d", &ch);
printf("The character for %d is %c\n", ch, ch);
}
I am getting a run-time error saying that the variable is corrupted, however, the window pops up allowing me to input an integer, and the program gives the correct output.
How do I fix this run-time error?
The %d format specifier expects an int * as a parameter, but you're passing in a char *. Because a char is smaller than an int, the function will attempt to write more bytes than the variable can hold. This invokes undefined behavior which in your case causes a crash.
Either change the type of ch to int, or use the %hhd format specifier which expects a char *.
ch is a variable of type char, but you're trying to read into it using %d, which is the format specifier for an int. That means your scanf writes over extra memory that it shouldn't. Change your declaration of ch to:
int ch;
And your program should work fine.

Can scanf() store values?

Hi I am now learning the C language and I have a little problem with a exercise of the book I read. My code is this:
#include<stdio.h>
int main()
{
unsigned char one=0;
unsigned char two=0;
printf("Quantity 1 = ");
scanf("%d",&one);
printf("Quantity 2 = ");
scanf("%d",&two);
printf("The value is %d",one);
return 0;
}
Why when I am trying to see the value of one the initial value appears and not the value after the scanf?
You need to use int type in conjuction with %d specifier, and char with %c specifier. And %u with unsigned integers.
#include<stdio.h>
int main()
{
unsigned int one=0; unsigned int two=0;
printf("Quantity 1 = ");scanf("%u",&one);
printf("Quantity 2 = ");scanf("%u",&two);
printf("The value is %u",one);
return 0;
}
Basicaly, scanf will try to read integer from input and it will try to store it inside memory location that is not large enough, so you will have undefined behavior.
You can find good reference here.
However, if you try to use character for an input type, you may want ask yourself why you won't get a chance to enter a second Quantity (if you type 4 and press enter). This is because second scanf will read enter key as a character. Also, if you try to type 21 (for a twentyone), it will fill the first value with 2 and second with 1 (well, with their ASCII values).
So, be careful - be sure that you always choose the right type for your variables.
Never use scanf.
Never use scanf.
Seriously, never use scanf.
Use fgets (or getline, if you have it) to read an entire line of input from the user, then convert strings to numbers with strtol or its relatives strtod and strtoul. strsep may also be useful.
Check if scanf() is working properly by reading its return value. For quickstart, read the details about scanf() at this link.
What you are doing is inputting a integer using "%d" into an unsigned char variable, therefore scanf() may not be working as it should.
Change
unsigned char one=0; unsigned char two=0;
to
unsigned int one=0; unsigned int two=0;
and also use %u instead of %d then it will print the value after scanf().
You declared the variable one to be a char:
unsigned char one=0;
But then you told scanf to read an int:
scanf("%d",&one); /* %d means int */
Int is bigger than char (typically 4-bytes vs. 1-byte), causing the problem you describe.
Change your scanf to:
scanf("%c",&one); /* %c means char */
Then when you print out the value, also print a char:
printf("The value is %c",one); /* %c means char */

Using the scanf() function

I intend to modify each other letter of a particular string. But for the purposes of this program none of that occurs. So far I've grabbed a string from the user and stored it in userinput and intend to print it.
#include <stdio.h>
#include <string.h>
int main(void) {
char userinput[256] ="";
printf("Enter somthing to change:\n");
scanf("%s", &userinput);
printf("%s\n", userinput);
int k = 2; // This is just here to do something every time k is even
int j = strlen(userinput);
for (int i = 0; i < j; i++) {
if(k % 2 == 0) {
printf("%s", userinput[i]);
k++;
}
else {
printf("%s", userinput[i]);
k++;
}
}
}
The strlen() function however does not work on the userinput. I figure this is because strlen() is supposed to take the address of the first char of a string and then iterate until reaching a null char but scanf doesn't actually create a null char.
I couldn't figure out a way of adding the '\0' after the string without first knowing the length of the string.
How would I go about accessing the length of a stored character sequence if it's stored in an array?
This:
scanf("%s", &userinput);
should be:
scanf("%s", userinput);
The address of operator & is unrequired, and incorrect. Arrays decay to the address of their first element when passed to a function. scanf("%s") will append a null terminating character so it is unnecessary to explicitly insert one.
To prevent potential buffer overrun specify the maximum number of characters that scanf() should write to userinput. This should be one less than the size of userinput, leaving room for the terminating null character:
scanf("%255s", userinput);
The incorrect format specifier (which is undefined behaviour) is being used to print the characters of userinput: use %c not %s. This:
printf("%s", userinput[i]);
must be:
printf("%c", userinput[i]);
Change
scanf("%s", &userinput);
to
scanf("%s", userinput);
The & operator is not required in the case of String capture. The scanf() automatically appends the null character('\0') to the end of the string so int j = strlen(userinput); should work.
If you still want to calculate the length without this function efficiently here is the link How to calculate the length of a string in C efficiently?
Change this
scanf("%s", &userinput);
with
scanf("%s", userinput);
we have to use addresses for scanf:
If we will scan into an int a then we have to call scanf() with the address of a => &a
If we will scan into a double a then we have to call scanf() with the address of a => &a
But If we will scan data into with pointer (memory address) int *a; or char array char a[50]; then we have to call scanf() with the pointer or with the array without adding &
From the scanf() page
Depending on the format string, the function may expect a sequence of
additional arguments, each containing a pointer to allocated storage
where the interpretation of the extracted characters is stored with
the appropriate type. There should be at least as many of these
arguments as the number of values stored by the format specifiers.
Additional arguments are ignored by the function. These arguments are
expected to be pointers: to store the result of a scanf operation on a
regular variable, its name should be preceded by the reference
operator (&) (see example).
You're confused about types, as others have indicated. Using scanf and printf when you're confused about types is dangerous!
scanf("%s", &userinput);
The type of &userinput is char (*)[256], but scanf expects %s to correspond to a char *. Since the type expected and the type given differ and aren't required to have the same representation, the behaviour is undefined.
I figure this is because strlen is supposed to take the address of the
first char of a string and then iterate until reaching a null char but
scanf doesn't actually create a null char.
Wrong. scanf certainly does assign a null character, when you use the %s format specifier. That is, providing scanf doesn't encounter an error or EOF. On that note, you should probably check for errors from scanf:
if (scanf("%s", userinput) != 1) {
/* Insert error handling here */
}
... as you should with all standard library functions in C.
k is pointless. Your loop already increments i at the same frequency as k.
strlen returns a size_t. Make sure you store return values in the right types. If a function returns size_t, then you store the return value in size_t. If a function returns int, then you store the return value in an int. Got it? Whatever the return type is, is whatever type you use to store the return type. Use the manual to find that out.
printf("%s", userinput[i]);
There's that type confusion again. userinput[i] is a char. %s tells printf to expect a char *. When the argument is invalid, the behaviour is undefined. That may cause your program to malfunction. Consider printf("%c", userinput[i]); or printf("%s", &userinput[i]);.

Getting Debug Error in C

i am a learner of 'C' and written a code, but after i compile it, shows a Debug Error message, here is the code:
#include<stdio.h>
void main()
{
int n,i=1;
char c;
printf("Enter Charecter:\t");
scanf("%s",&c);
printf("Repeat Time\t");
scanf("%d",&n);
n=n;
while (i <= n)
{
printf("%c",c);
i++;
}
}
Pls tell me why this happens and how to solve it
The scanf("%s", &c) is writing to memory it should not as c is a single char but "%s" expects its argument to be an array. As scanf() appends a null character it will at the very least write two char to c (the char read from stdin plus the null terminator), which is one too many.
Use a char[] and restrict the number of char written by scanf():
char data[10];
scanf("%9s", data);
and use printf("%s", data); instead of %c or use "%c" as the format specifier in scanf().
Always check the return value of scanf(), which is the number of successful assignments, to ensure subsequent code is not processing stale or uninitialized variables:
if (1 == scanf("%d", &n))
{
/* 'n' assigned. 'n = n;' is unrequired. */
}
scanf("%s",&c); should be scanf("%c",&c);
The %s format specifier tells scanf you're passing a char array. You're passing a single char so need to use %c instead.
Your current code will behave unpredictably because scanf will try to write an arbitrarily long word followed by a nul terminator to the address you provided. This address has memory allocated (on the stack) for a single char so you end up over-writing memory that may be used by other parts of your program (say for other local variables).
I'm not sure you understood the answer to your other question: Odd loop does not work using %c
These format specifiers are each used for a specific job.
If you want to get a:
character from stdin use %c.
string (a bunch of characters) use %s.
integer use %d.
This code:
char c;
printf("Enter Character:\t");
scanf("%c",&c);
Will read 1 character from stdin and will leave a newline ('\n') character there. So let's say the user entered the letter A in the stdin buffer you have:
A\n
The scanf() will pull 'A' and store it in your char c and will leave the newline character. Next it will ask for your int and the user might input 5. stdin now has:
\n5
The scanf() will take 5 and place it in int n. If you want to consume that '\n' there are a number of options, one would be:
char c;
printf("Enter Character:\t");
scanf("%c",&c); // This gets the 'A' and stores it in c
getchar(); // This gets the \n and trashes it
Here is a working version of your code. Please see inline comments in code for fixes:
#include<stdio.h>
void main()
{
int n,i=1;
char c;
printf("Enter Character:\t");
scanf("%c",&c);//Use %c instead of %s
printf("Repeat Time\t");
scanf("%d",&n);
n=n;//SUGGESTION:This line is not necessary. When you do scanf on 'n' you store the value in 'n'
while (i <= n)//COMMENT:Appears you want to print the same character n times?
{
printf("%c",c);
i++;
}
return;//Just a good practice
}

Resources