0

Hello all what i am trying to do is to scanf a string to 2 struct variables but when running the code it simply passes though the scanf (both of them) and goes to the printf.

My code is the following:

struct s_Especialidade{
    char nome[60];
    char descricao[60];
    struct s_Especialidade *proximo;
};

typedef struct s_Especialidade Especialidade;
typedef Especialidade *PESPECIALIDADE; 

void novaEspecialidade()
{
    PESPECIALIDADE novo = malloc(sizeof(Especialidade) );
    int opcao=0;
    printf("\nNome: ");
    scanf("%59[^\n]\n", (novo->nome));
    printf("\nDescricao: ");
    scanf("%59[^\n]\n", (novo->descricao));
    novo->proximo = NULL;
    printf("\n%s - %s",novo->nome, novo->descricao);
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    Welcome to Stack Overflow. Please read the [FAQ] soon. You can always edit your own question; I've transplanted the extra information into the question for you this time, but you could have done it too. Since you don't check the return value from `scanf()`, you can't tell whether it is happy or not. What was the read operation before this? Did it make sure that the newline before was read? – Jonathan Leffler Jun 13 '13 at 16:42

3 Answers3

4

The trouble is that white space (including newlines) in scanf() format strings behaves peculiarly — it means an arbitrary sequence of white space characters.

When it prompts Nome:, you can type a name ('Alexander the Great') and a newline, but the scanf() keeps reading until it comes across another character that isn't white space. So, you might type 'Conqueror of Asia', and then the prompt Descricao: will appear, and it will read until you type another character that isn't white space, and then it will terminate.

For example:

$ ./name-prompt
Nome: Alexander The Great 
Conqueror of Asia

Descricao: a

<<Alexander The Great>> - <<Conqueror of Asia>>
$

This is from the code:

#include <stdio.h>
#include <stdlib.h>

struct s_Especialidade{
    char nome[60];
    char descricao[60];
    struct s_Especialidade *proximo;
};

typedef struct s_Especialidade Especialidade;
typedef Especialidade *PESPECIALIDADE; 

static
void novaEspecialidade(void)
{
  PESPECIALIDADE novo = malloc(sizeof(Especialidade) );
  printf("\nNome: ");
  if (scanf("%59[^\n]\n", (novo->nome)) != 1)
      printf("Oh, bother!\n");
  printf("\nDescricao: ");
  if (scanf("%59[^\n]\n", (novo->descricao)) != 1)
      printf("Oh, bother!\n");
  novo->proximo = NULL;
  printf("\n<<%s>> - <<%s>>\n", novo->nome, novo->descricao);
  free(novo);
}

int main(void)
{
  novaEspecialidade();
  return 0;
}

Note that the printf() output ends with a newline; that's generally a good idea.

To work around this, modify the scanf() format to:

"%59[^\n]"

After the scanf(), do the equivalent of:

int c;
while ((c = getchar()) != EOF && c != '\n')
    ;

Package it into a function — maybe gobble() or read_to_newline().

Or use fgets() to read the line and sscanf() to parse it; that often works better.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

Are you trying to read 60 characters and indicating that by 59 in the scanf statement? Then, your scanf is wrong. Change it to: scanf ( "%s", novo->nome ); and it should work. Same with the other scanf.

unxnut
  • 8,509
  • 3
  • 27
  • 41
  • Thx for your response but i already tried that, and the resulte was if i input a name for example mine "Ricardo Sacramento" the space in the middle will be the end of the first scanf and then in my result printf will be ricardo - sacramento and the objective is to appear a name "ricardo Sacramento"- "description" for example. I want the scanf to read until a \n appear or until 59 characters. – Ricardo Sacramento Jun 13 '13 at 16:46
  • Then, you may want to change it to `gets` or `fgets`. That will allow you to read till the newline. You can use `fgets ( novo->nome, sizeof ( novo->nome ), stdin );` and you should be good but may have to replace the tailing newline character by a `NULL`. – unxnut Jun 13 '13 at 16:59
  • To remove the newline character as a result of `fgets`, add the following statement: `novo->nome[strlen(novo->nome)-1] = NULL;` – unxnut Jun 13 '13 at 17:09
-1

Here is a complete example, reading two strings from stdin, then using sscanf to remove the trailing newline and printing them:

#include <stdio.h>

struct {
    char first[60];
    char second[60];
} store;

int main(int argc, char ** argv) {
    char buffer[60];

    printf("write something: ");
    fgets(buffer, 60, stdin);
    sscanf(buffer, "%s", store.first);

    printf("write something else: ");
    fgets(buffer, 60, stdin);
    sscanf(buffer, "%s", store.second);

    printf("you wrote: %s then %s\n", store.first, store.second);

    return 0;
}
Guillaume
  • 10,463
  • 1
  • 33
  • 47
  • He doesn't want to read 'at most 59 characters' precisely; he wants to read at most 59 non-newline characters followed by a newline (not that he'll ever be able to tell whether the newline was actually matched). – Jonathan Leffler Jun 13 '13 at 16:45
  • You're right, my answer was stupid... rewrote it to use fgets – Guillaume Jun 13 '13 at 16:51
  • I want to be able to read a string with a space in between for the max of 59 characters. – Ricardo Sacramento Jun 13 '13 at 16:51
  • well... fgets reads one line, so it stops at the first newline, and the size parameter force it to stop at 60 characters. – Guillaume Jun 13 '13 at 16:53
  • I did try it and what happens is when i compile it with "fgets(novo->nome,59,stdin" and "fgets(novo->descricao,59,stdin);" the output is: nome: descricao: and then i start writing and i should be wrinting in the middle – Ricardo Sacramento Jun 13 '13 at 16:54
  • I tried you example and still when compiling does not let me introduce the name it passes always though it right to the description its like the first fgets is not there – Ricardo Sacramento Jun 13 '13 at 17:15
  • Do you mean that running my example as a "standalone" program does not works? Or do you mean it doesn't works when included in your program? If that's the second, are you using the input stream before? If so, you may have to flush the input stream: http://stackoverflow.com/questions/2187474/i-am-not-able-to-flush-stdin – Guillaume Jun 13 '13 at 17:26
  • I mean when included does not work it only stops for input in the description not in the name, and no its the first input stream – Ricardo Sacramento Jun 13 '13 at 17:31
  • yeah... that's it then, try adding `while ((c = getchar()) != '\n' && c != EOF);` before the first input (with c being a char) – Guillaume Jun 13 '13 at 17:33
  • i will try it but what does the line do? IT WORKED so many thanks to all guys rly. Just saved my life xD. but what its does the line?? thx – Ricardo Sacramento Jun 13 '13 at 17:37
  • 1
    Your `while ((c = getchar()) != EOF && c != '\n');` loop requires `c` to be an `int` for reliable operation. If it isn't, you run into one of two problems, depending on whether plain `char` is signed or unsigned. If plain `char` is signed, then a valid character (e.g 0xFF, often ÿ, y-umlaut, formally U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS) matches EOF and prematurely terminates the input. If plain `char` is unsigned, no value ever matches EOF, so the loop won't terminate on EOF. – Jonathan Leffler Jun 13 '13 at 18:23