0

To practice variable declaration, placeholders and I/O calls, I did a sample assignment in the book that I am using to study. However, I keep running into a particular problem, in that when I try to declare more than one character variable for the purpose of input, even if the compiler doesn't catch any syntax error, the program when executing will only return one character variable. This is the code in question:

#include <stdio.h>

int main()

{
double penny=0.01;
double nickel=0.05;
double dime=0.1;
double quarter=0.25;

double value_of_pennies;
double value_of_nickels;
double value_of_dimes;
double value_of_quarters;
double TOTAL;
int P;
int N;
int D;
int Q;
char a,b; 

//used "static char" instead of "char", as only using the "char" type caused a formatting error where only the latter character entered in its input would appear

printf("Please enter initials> \n");
printf("First initial> \n");
scanf("%s", &a);
printf("Second initial> \n");
scanf("%s", &b);

//"%s" was used as the input placeholder for type "char"

printf("%c.%c., please enter the quantities of each type of the following coins.\n", a, b);


printf("Number of quarters> \n");
scanf("%d", &Q);
printf("Number of dimes> \n");
scanf("%d", &D);
printf("Number of nickels> \n");
scanf("%d", &N);
printf("Number of pennies> \n");
scanf("%d", &P);

printf("Okay, so you have: %d quarters, %d dimes, %d nickels, and %d pennies.\n", Q, D, N, P);

value_of_pennies=penny*P;
value_of_nickels=nickel*N;
value_of_dimes=dime*D;
value_of_quarters=quarter*Q;

TOTAL=value_of_quarters+value_of_dimes+value_of_nickels+value_of_pennies;

printf("The total value of the inserted coins is $%.2lf. Thank you.\n", TOTAL);

//total field width omitted as to not print out any leading spaces
return(0);
}

And this is the transcribed output ("a", "e", and the four "1"s are sample arbitrary input values:

Please enter initials>
First initial>
a
Second initial>
e
.e., please enter the quantities of each type of the following coins.
Number of quarters>
1
Number of dimes>
1
Number of nickels>
1
Number of pennies>
1
Okay, so you have: 1 quarters, 1 dimes, 1 nickels, and 1 pennies.
The total value of the inserted coins is $0.41. Thank you.

I entered the characters "a" and "e" as input values for the char variables "a" and "b", but only "e" had shown up. On the other hand, should I have put a "static" in the "char" variable declaration, both inputted char values will be displayed in the relevant print call.

For future reference, I would like to ask about why such a thing would occur the way that it did, and the value of the "static" word in the declaration.

(As an aside, I am aware that I could have simply made the "value_of_(insert coin here)" variables as constant macros.)

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Astatine
  • 3
  • 1
  • 2
  • Similar question: http://stackoverflow.com/questions/2928863/difference-between-static-const-char-and-const-char?rq=1 –  Jun 12 '15 at 16:36
  • I don't see where you use static in your code. And since you only work inside main, static wouldn't do any difference, except for initializing the varaible with `0`. Maybe you refer as `static` to something other than what static is. – bolov Jun 12 '15 at 16:40
  • There is not a single question mark in the entire post. – barak manos Jun 12 '15 at 16:43
  • @bolov et al: I do not state that I have placed "static" in THIS code sample. I say that, should I have inserted the word, it works as intended. My question refers to the issue in the code sample that I've posted here, especially since this is a recurring issue for me. – Astatine Jun 13 '15 at 01:01

2 Answers2

2

With a definition like

char a,b; 

writing a statement like

scanf("%s", &a);
scanf("%s", &b);

invokes undefined behaviour. %s is not a format specifier for a char. Using wrong format specifier can and will lead to UB. You should use %c to scan a char.

To elaboreate,

  • %s format specifier expects a corresponding argument which is a pointer to char array. It scans multiple characters until it encounters a space (whitespace character, to be pedantic) or newline or EOF.
  • %c format specifier expects a corresponding argument which is a pointer to char variable. It reads only one char from the input buffer.

So, with %s, if you supply the adress of a char variable, it will try to access beyond the allocated memory region for writing the scanned data, which will invoke UB.

You may want to read some more on printf(), scanf() and format specifiers before moving forward.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • Not arguing with what you are saying, but I'm curious - Is it really UB? I feel it should be pretty well defined - `scanf` will write to that pointer as if it was a pointer of type specified in the format. For example, would this be UB: `uint32_t buffer[1024]; scanf("%s", buffer);` ? – mtijanic Jun 12 '15 at 16:47
  • @mtijanic I understand your doubt, and really glad you asked. Can you please read on `C11` standard, chapter `§7.21.6.1`, paragraph 8 and 9, saying "the argument shall be a pointer to the initial element of an array of character type"...and "If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined." – Sourav Ghosh Jun 12 '15 at 16:50
  • @mtijanic the full paragraph is too big to be quoted here. Hope you won't mind reading the same on web. :-) – Sourav Ghosh Jun 12 '15 at 16:51
  • 1
    Thanks, that answers my question perfectly. Now I'm curious as to whether any mainstream compiler actual does something weird in that case. I'll test it out on all of them when I find the time. Thanks again. – mtijanic Jun 12 '15 at 16:53
  • Actually, I think that was just a CYA in case you pass arguments which are larger than expected, such as `scanf("%d %d", MyLargerThanPointerStruct, &myInt);`, which will obviously interpret a part of the struct as an `int*`, which is UB. Since some of it was UB, there's no point for the standard to define parts of it, so they just say everything is UB. Thanks again for the n1570 reference. – mtijanic Jun 12 '15 at 16:58
  • @Sourav Ghosh: Thank you very much for your answer. However, I would like to add that while I understand that while `%s` doesn't correspond directly, using `%c` has also been problematic for me in the past-- actually, it literally causes another issue, where after inputting a character, the program refuses to advance to the next line (and this is when I only put in ONE non-numeric character). Using `%s` in conjunction with `static char` strangely works, for some reason. – Astatine Jun 13 '15 at 01:10
0

You have used the wrong format specifier for char. char uses %c not %s. As far as static goes, I'm a bit confused about your question. You say in a comment that you are using static char, but I do not see any variables declared as static char.

Daniel
  • 6,595
  • 9
  • 38
  • 70