-1

first I would to like to mention that I am new to programming.

I am trying to write a program that takes in multiple inputs, last of which is a string, when I use the gets() or fgets() functions they read the input from the after previous input finishes. So for example:

printf("Enter decimal:\n");
scanf("%d",&x);
printf("Enter string:\n");
gets(str[100]);
printf("%d\n%s",x,str);

Sample Input/Output:

Enter decimal:
3\n            //If I change line after inputting the decimal the program continues as if it already read the string
Enter string:
3  

However If the input is as follows:

Enter decimal:
3 Hello World\n            
Enter string:
3  
Hello World

I suppose this is how the gets() and fgets() functions work but is there a way to control it in sense or is there an alternative (The string that would be inputted can be very long )

Thanks in advance.

Jens
  • 69,818
  • 15
  • 125
  • 179
Alk
  • 13
  • 1

2 Answers2

2

Read more about C standard IO. Notice that gets was deprecated and dangereous but is now removed from the C standard. You should never use it (and please, forget that it has existed). Probably you mean fgets(str, sizeof(str), stdin) instead of your call to the disappeared gets, assuming that str is some array of chars, e.g. declared as char str[100];.

You might read an entire line with fgets (or even getline(3), see this) then parse that buffer, perhaps using sscanf (or strtol, or strtok, or using your own lexing & parsing techniques).

Notice that sscanf (like fscanf and scanf) returns a scanned item count (and accepts %n) but don't care about end-of-lines. You need to use that.

Read documentation of the functions you are using very carefully.

When reading from a genuine file, you could also reposition inside it using fseek (with ftell). That won't work on the console (since the terminal is generally non-seekable).

Perhaps you could use some terminal related libraries (such as ncurses or readline). These are not in the C11 standard n1570 and might not be available on your operating system (but on Linux and some others OSes, you have them).

Remember that your stdin is not always a terminal. Think of redirections and pipelines.

Read also How to Debug Small Programs. Be sure to compile your code with all warnings and debug info (so gcc -Wall -Wextra -g if using GCC).

If you are on Linux or some POSIX operating system, be aware that stdin is related to the file descriptor 0 (named STDIN_FILENO). So if you want to wait till some input is available, consider using poll(2) on that file descriptor.

PS. Your question is really unclear. I can just guess what you want to do.... Consider improving it after having read more documentation...

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Thank you, the sources you provided are very helpful. Since I am new programming I am still not quite familiar with the technical wording, I will be sure to read more! – Alk Jul 02 '18 at 23:25
1

There are multiple problems in your code:

  • gets() is obsolete and risky because the destination array size is not passed to the function, so it cannot prevent a buffer overrun if user input is too long. It has been finally removed from the latest version of the C Standard. Use fgets() instead.
  • mixing scanf() and fgets() is error prone as scanf() leaves part of user input pending, such as the newline typed by the user after the number, and this pending input will be read by fgets(), which in this particular case will return immediately because the pending newline is precisely what fgets() expects to end its input.

I recommend using fgets() to read input line by line and use sscanf to convert the input to the expected types. It has the extra advantage of allowing easy error recovery.

Here is a modified version:

#include <stdio.h>
#include <string.h>

int main() {
    char buf[100];
    int x;

    for (;;) {
        printf("Enter decimal: ");
        if (!fgets(buf, sizeof buf, stdin))
            return 1;
        if (sscanf(buf, "%d", &x) == 1)
            break;
        printf("Invalid input: not a number\n");
    }
    for (;;) {
        printf("Enter string:\n");
        if (!fgets(buf, sizeof buf, stdin))
            return 1;
        buf[strcspn(buf, "\n")] = '\0';  // strip the trailing newline if any
        if (buf[0] != '\0')
            break;
        printf("Invalid input: empty string\n");
    }
    printf("%d\n%s\n", x, buf);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189