3
int main(int argc, char const *argv[]) {
    int id = access_queue();
    char priority;
    char message[100];

    while (message != "") {
        printf("Enter message:\n");
        int result = scanf("%[^\n]s", message);

        if (result == 0) {
            write_value(id, "", '3');
            break;
        }
        printf("Enter priority:\n");
        priority = getchar();
        scanf(" %c", &priority);

        if (priority == '1' || priority == '2' || priority == '3')
            write_value(id, message, priority);
        else
            printf("Priority must 1, 2 or 3 (1 being the highest)\n");
    }
}

Okay, so I have this code which is supposed get the message from the terminal and then ask for the priority until the message is empty. The problem is that after asking for the priority and getting the value, it goes back to "Enter message" and without by input takes an empty string.

Jeff Linahan
  • 3,775
  • 5
  • 37
  • 56
Turqay Umudzade
  • 171
  • 2
  • 13
  • 2
    The space you already have before `%c` instructs `scanf` to filter leading whitespace. Most of the format specifiers for `scanf` automatically filter leading whitespace without that, but `%c` and `%[...]` and `%n` do not. Please see [scanf() leaves the newline char in the buffer](https://stackoverflow.com/questions/5240789/scanf-leaves-the-new-line-char-in-the-buffer). – Weather Vane Apr 18 '20 at 19:31
  • @user3121023 it fixed by the problem but caused another one, it won't accept an empty message – Turqay Umudzade Apr 18 '20 at 19:32
  • 3
    I suggest switching all input to `fgets`, and if necessary apply `sscanf` to that. Don't forget the newline retained. Please see [Removing trailing newline character from fgets() input](https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input/28462221#28462221) although that's only necessary for a string input: `sscanf` with say, `%d` will ignore that. – Weather Vane Apr 18 '20 at 19:34
  • tried switching to fgets(message,100,stdin); and priority=getchar(); and I'm still having the skipping problem – Turqay Umudzade Apr 18 '20 at 19:40
  • 1
    Note that `while (message != "")` won't work. To compare strings, use the `strcmp` function. – user3386109 Apr 18 '20 at 19:41
  • 2
    Don't mix your methods. the `getchar` will leave a newline in the input buffer which will be read by the next `fgets.` If you use one method, use that for everything. Get the character from the first element of a string input by `fgets`. You can be more rigorous if you want to check it was *only one* character entered. – Weather Vane Apr 18 '20 at 19:42
  • @WeatherVane how can i use fgets for a char? – Turqay Umudzade Apr 18 '20 at 19:49
  • Suppose you use `fgets` to enter a string to say `char mystring[4]` then the char will be `priority = mystring [0]`. – Weather Vane Apr 18 '20 at 19:58
  • did that still the same problem with skipping – Turqay Umudzade Apr 18 '20 at 19:59
  • 1
    Does this answer your question? [scanf() leaves the new line char in the buffer](https://stackoverflow.com/questions/5240789/scanf-leaves-the-new-line-char-in-the-buffer) –  Apr 18 '20 at 20:11

2 Answers2

4

There are some problems in your code:

  • while (message != "") is always false: message == "" compares the addresses of the array message and the array in which the string constant "" is stored in memory. You cannot compare strings with ==, you must use strcmp() or simply while (*message != '\0') but message is uninitialized so this test has undefined behavior. You probably just want to iterate the loop as long as the user does not enter an empty string, so make the loop an infinite loop and test the termination condition explicitly.

  • scanf("%[^\n]s", message); the s is incorrect, character class specifications stop at the ].

  • if (result == 0) is not enough: scanf() will return EOF on end of file, so you should test if (result != 1)

  • priority = getchar() will read the pending newline, which scanf(" %c", &priority) would ignore anyway, remove this line.

  • scanf(" %c", &priority) will read the next non blank character from the user but will leave the rest of the line input by the user in the input stream, including the newline, which will cause the next iteration to fail because the first character available will be a newline, causing scanf() to return 0.

Here is a modified version:

#include <stdio.h>

int main(int argc, char *argv[]) {
    int id = access_queue();
    char priority;
    char message[100];

    for (;;) {
        printf("Enter message:\n");
        int result = scanf("%99[^\n]", message);
        if (result != 1)
            break;
        printf("Enter priority:\n");
        if (scanf(" %c", &priority) != 1)
            break;
        if (priority == '1' || priority == '2' || priority == '3')
            write_value(id, message, priority);
        else
            printf("Priority must 1, 2 or 3 (1 being the highest)\n");

        /* read and ignore the rest of the line entered by the user */
        while ((c = getchar()) != EOF && c != '\n')
            continue;
    }
    write_value(id, "", '3');
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

Use fgets() to read a line of user input instead of scanf() until you understand why scanf() is so troublesome.

    char buf[sizeof message * 2];

    //int result = scanf("%[^\n]s", message);
    fgets(buffer, sizeof buffer, stdin); // Better code would check return value if NULL
    int result = sscanf(buffer, "%99[^\n]", message);

...

    // scanf(" %c", &priority);
    fgets(buffer, sizeof buffer, stdin);
    sscanf(buffer, " %c", &priority);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 1
    @TurqayUmudzade `scanf()` and family have a lot to them. `scanf()` reads _and_ parses. IMO, best to separate reading with `fgets()` from parsing `sscanf(), strtol()`, etc. – chux - Reinstate Monica Apr 18 '20 at 20:32