String of characters within the scanf. Why and how does scanf works ("Day% d", & day);

3

Problem

I was making a code that would be to read a string and then an integer value:

int dia, h, m, s;
char dp;            //Dois pontos.
scanf("Dia %d",&dia);   //Inicio do evento.
...

I thought about creating a string for the user to enter the word "Day" and then the value. But I saw a code with this example above, the word Day goes inside the scanf without storing in a string . In this case, if we type exactly as it is inside scanf (if it were "day" or "day" would not work, it must be exactly equal to what is inside scanf ), ie "Day xx" (where xx can be any integer value) it works, and without needing to read characters and store in a variable, ie, I did not point my information to any address to be stored.

I was curious to know why and how this happens.

Questions

Why, without storing a variable and not pointing to an address, with almost nothing reporting to the compiler that would type a string , did scanf run normally?

How did this happen? This string has to go somewhere, and as I did not specify, where did it go? What process does the compiler do with this string ?

    
asked by anonymous 13.10.2014 / 13:00

2 answers

4

There are several errors there. You've never seen books because of this. I think you need to understand at least two concepts in C. I will not go into too much detail.

Pointers

When you type &dia it's the same as saying "at address". This is a way to use pointer. The pointer is an indicator that you will use a memory address. The scanf() expects as other parameters after the first one is the formatting that you send as memory address arguments. That's why you can not just send dia . If you sent this variable in this way, you would be sending the value to the function and that is not what you should do. Then you did it right, sent the address where dia is stored.

dia as well as h , m and s and dp are stored somewhere as you stated before. Probably one after the other. Although this is implementation and platform dependent, these variables are probably reserving 4 bytes each which is the most common size for type int . The type char probably has 1 . Then you reserved 17 bytes in sequence.

Since you sent the address from dia to scanf() , it will store the characters read at this address you passed. The first four characters will be in the variable dia , the next four characters in the variable h , and so on. What if I type more than 17 characters? See below.

Can you save characters in integers? You can!

Indefinite Behavior

You are using a concept called indefinite behavior that is widely used by languages like C where you need flexibility, ease of adaptation to multiple platforms, and creative ways to improve performance. C is almost an Assembly . C allows direct access to hardware . C does not control too much what the programmer is doing. C understands that the programmer should know what he's doing even if he does something potentially dangerous.

So you're storing characters where you should have integers. No problem. Of course in your case is not the intention, but it works (I always say that working is different from being right). Each 4 characters will form an integer. A value that probably has no meaning for your program, but it works.

The problem is when you move up from 17 characters. There you will be storing data in non-reserved memory area for variables. Yes, this is possible in C, so C is such a cool and powerful language but also so dangerous. C allows you to write anywhere in the memory of your application. And that's where you can cause serious problems for her. In some cases, by coincidence will not cause. Only programming can not produce results by coincidence.

You could have caused an even bigger problem. I could have sent the value of dia as if it were the pointer (I'm not talking about sending the address as you sent it, it would be calling scanf("Dia %d", dia); ). And it could "work". Of course you would be trying to store the data read by scanf() in an address you even know the value. Yes, because you did not initialize values for the variables, then their values are those that were already in memory in that position.

Unless you know very well what you are doing, have a very strong motive, never use undefined behavior in your programs.

Format error of scanf()

I will not say much because the Omni response has already given the important details of this. The string formatting is wrong. You are specifying a format that does not exist, which is not well interpreted by scanf() . That's where you end up even doing nothing. But it does not have to because the compiler gives some error, the fault occurs running.

The responsibility is not of the compiler in this case. It is from the inner code of scanf() . Do not forget that scanf() is a function like any other. Some programmer created it as you create your programs. It does not have any privileges in C, it's just a program that goes along with C to make it easier to perform some operations by default. Luckily, the function does not let you do what you please and do not let you cause all the disaster I mentioned above. But it is also far from doing what you want and being something useful.

Conclusion

So your "work" is a "more or less" good. It does not make a mistake, but it works, it does not work.

    
13.10.2014 / 13:31
4

What happens in this case is that it is passed to scanf(...) a formatting string. This format string indicates to scanf(...) how to process the read input, ie it is a format directive. If when processing the input the validation of this directive fails, scanf(...) stops reading the inputs and returns.

A directive can be made up of the following elements:

  • A sequence of spaces;

  • A normal character (a-zA-Z0-9, etc.) as long as it is not a white space or a%;

  • A conversion specifier that is started by the% character. The inputs are read and converted according to this specifier and placed on the respective pointer (for example, scanf("%d", &i) .

In your case, your formatting directive is "Day% d". With this directive, scanf(...) is waiting to read an input that starts as "Day" and then an integer. So when you put something that does not begin with "Day" the scanf(...) fails and nothing is read for the dia variable.

Examples:

scanf(...) successful:

int dia = 0;
scanf("Dia %d", &dia); // Input: Dia 123
printf("%d", dia); // Output: 123

scanf(...) failed:

int dia = 0;
scanf("Dia %d", &dia); // Input: 123
printf("%d", dia); // Output: 0 (valor colocado em dia)

scanf(...) failed (day variable not initialized):

int dia;
scanf("Dia %d", &dia); // Input: 123
printf("%d", dia); // Output: int_min (valor default de inicialização do int)

For more information, check out this page that exhaustively describes how scanf(...) and the supported formatting strings.

    
13.10.2014 / 13:31