Parameters of the scanf function

Asked

Viewed 1,052 times

4

When studying the function scanf with a little more depth I arose a doubt about the arguments I put before the % when reading a string, ie scanf("argumentos...%s",minhastring), in the following codes I add a space and the character 'J' before the % to check the behavior of the scanf, ie the cleaning of the buffer is not what is under study, because this is not a correct way to do such a treatment, but rather the utility of putting characters before the %:

1st version of the code:

//abrindo um arquivo para escrever o resultado do que for digitado
FILE *arq = fopen("testes.txt","w");
char str1[20], str2[20];
//lendo duas strings, o %19 limita o numero de caracteres a ser armazenado, evitando o
//overflow e o [^\n] faz com que o conteudo seja lido até encontrar uma quebra de linha,
// tornando possivel a leitura de strings com espaço
printf("Digite a primeira string: ");
scanf("%19[^\n]s", str1);
printf("Digite a segunda string: ");
scanf("%19[^\n]s", str2);
//armazenando a string formatada no arquivo: testes.txt
fprintf(arq, "Foi digitado \"%s\" e \"%s\" ", str1, str2);
//fechando o arquivo
fclose(arq);

Here are some tests and their outputs in a file:

first

Type the first string: Antonio

Type the second string:

It was typed "Antonio" and "NÊ8 þÿÿÿb8v¼[=v@"

I then changed the code and put a space before the "%" of the second scanf and also added the character 'J'.

Before the change: scanf("%19[^\n]s", str2);

Now scanf(" J%19[^\n]s", str2)

I could not type the second string, after typing the first the program was terminated, in the next example the space is probably "catching" the ' n', and the character 'J' is forcing the second string to start with the letter 'J':

2nd version of the code:

FILE *arq = fopen("testes.txt","w");
char str1[20], str2[20];
printf("Digite a primeira string: ");
scanf("%19[^\n]s", str1);
printf("Digite a segunda string: ");
scanf(" J%19[^\n]s", str2);
fprintf(arq, "Foi digitado \"%s\" e \"%s\" ", str1, str2);
fclose(arq);

Here are some tests and respective outputs in a file:

first

Type the first string: Maria Eduarda

Type the second string: Joao Carlos

It was typed "Maria Eduarda" and "oao Carlos"

2nd

Type the first string: Maria Eduarda

Type the second string: Maria Joaquina

It was typed "Maria Eduarda" and " Þþÿÿÿb8v¼[=v@"

Interesting Findings: The Space of scanf is solving the problem of what was left in stdin, the "n' that is left" of the first data entry was ignored. By placing the letter 'J', or any other, before the '%' sign I can only correctly read a string if it starts with the given letter as parameter, and the informed letter is ignored by scanf, which does not store it in the variable, as in the first test:

Type the first string: Maria Eduarda

Type the second string: Joao Carlos

It was typed "Maria Eduarda" and "oao Carlos"

->This doubt arose when doing some tests and "playing" a little in code Blocks. I find C a very interesting language. And I would like to remove this doubt: What happens when I put arguments between quotation marks and '%' in the scanf? And when they’re usually used, if they’re used?

  • I could even answer, but I don’t know if that’s what you want. First: working is not being right. Second: scanf() it is problematic, to do some exercises, ok, for general use, better to use something else: http://answall.com/a/111703/101, http://answall.com/q/42981/101

  • @Bigown It was my first post here, I made a mistake by not specifying my doubt better. The question of buffer and stdin was not the focus of my question, but parameters that appear before the % of the scanf. I do not intend to use it in this way, only to know if I can and if so, if it has been implemented to be used in this way or if it will only show undefined behavior. For example when typing "love", if my scanf looks like this: scanf("a%s", str). Why is the letter 'a' ignored? When typing a word that does not start with 'a' can’t store the value in the variable? Thank you.

  • I think you’re accessing inappropriate places of memory that explains these strange characters

1 answer

4


Before we start, I think you actually wanted to use "%19[^\n]" instead of "%19[^\n]s". The second version actually means "a string up to 19 characters \n, followed by the letter "s".

The reason for the strange behavior of your first program is that the first scanf does not consume the \n of the first line of your input file. When the second scanf tries to run, it comes face to face with this \n and can’t read what’s on the second line.

Apparently, when the scanf using [ cannot read anything it does not modify the string buffer you pass to it. I think it would make more sense if he filled the buffer with an empty string but it seems that this is not the case... Anyway, you can get rid of that exquisite output if you initialize your buffers with a default value:

char str1[20] = "AAAA";
char str2[20] = "BBBB";

About his second program, the at the beginning of the formatting string of the second scanf means "consume zero or more whitespace". This includes the \n of the first line that had disrupted the first version of its program (and would also include white spaces at the beginning of the second line).


That said all, I do not recommend using scanf to read entire lines that way. As you may have noticed, it is very easy to shoot yourself in the foot with the scanf in this case and the two versions of your program have subtle bugs (the first does not work and the second eats blanks at the beginning of the second line).

Instead of using the scanf recommend using the function fgets to read an entire line. It receives the output buffer, the maximum buffer size (maximum number of characters plus one) and a FILE* where the entrance will be read:

fgets(str1, 20, stdin);
fgets(str2, 20, stdin);

The only problem with fgets is that it includes the \n no buffer. If you don’t like the \n you will need to remove it in hand.


Another possibility is to read the input characters one by one, with getchar or fgetc. It takes more work but allows you to have a very fine control of what you are doing.


Back to the question at the end of your post:

What happens when I put arguments between quotes and '%' in the scanf?

The first argument of the scanf function (the "format string") consists of a sequence directives. A directive can be:

  1. A sequence of spaces (space, tab, line break, etc)
  2. A normal letter (other than % or a mirror)
  3. A conversion specification, starting with the letter %

The semantics of scanf consists of processing directives in sequence.

  1. In the space directive, the scanf consumes zero or more spaces, stopping just before the first character of the input that is not a space or EOF.
  2. In the case of the standard letter directive, the scanf tries to read exactly one character of the input and fails if the read character is not as expected.
  3. In the case of Directives with %, scanf does something different depending on each case. Usually it will be ignore spaces followed by trying to read something from the input.

For a concrete example, consider the call scanf(" J%d%19[abc]", &n, buf). In this case the format string has 4 directives and the scanf will do the following:

  1. Ignore all whitespace at the beginning of the input.
  2. Read the letter J input (and fail if not had a J to read)
  3. Ignore blanks; read an entry number and store it at the address &n (and fail if you can’t read a number)
  4. Read a string (maximum 19 letters) containing only the letters a, b, or c and store it in buf. (The conversion %[ is an exception and does not ignore white spaces before trying to read the formatted data)
  • Thanks for commenting, as I said to another user I misexplained my doubt, so I edited the post to be clearer. I know the fgets function, and I always use it when I work with strings, I just really wanted to know how the scanf works. Both scanf and printf are interesting functions that we often don’t get all the potential. Thanks again.

  • I edited my question to try to clarify the behavior of the scanf. For more details, I recommend reading the manual

  • 1

    @Jjoao: You were right... were typos.

  • Thank you very much for the comments, they helped me a lot.

  • @Luishenrique: do not forget to mark the answer as "accept" :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.