cscanfstdinfgetsgetchar

Is there an elegant way to handle the '\n' that gets read by input functions (getchar(), fgets(), scanf()) in C?


I am trying a simple exercise from K&R to append string2 at the end of string1 using pointers. In case of overflow i.e. buffer of string1 can't contain all of string2 I want to prompt the user to re-enter string2 or exit.

I have written the following code:

#include<stdio.h>
#include<string.h>
#define MAXLINE 1000
int get_input(char *s);
int str_cat(char *s, char *t);

void main()
{
    char input1[MAXLINE], input2[MAXLINE], c; 
    get_input(input1);
    check:
    get_input(input2);
    if((strlen(input1) + strlen(input2) + 2) <= MAXLINE)
    {
        str_cat(input1, input2);
        printf("%s\n", input1);
    
    }
    else
    {
        input2[0] = '\0';
        printf("String overflow\n Press: \n 1: Re-enter string. \n 2: Exit.\n");
        scanf(" %d", &c);
        if(c == 1){
            input2[0] = '\0';
            get_input(input2);
            goto check;
        }

    }

}

int get_input(char *arr)
{
    int c;
    printf("Enter the string: \n");
    while(fgets(arr, MAXLINE, stdin))
    {
        break;
    }
}
int str_cat(char *s, char *t)
{
    while(*s != '\0')
    {
        s++;
    }
    while((*s++ = *t++) != '\0')
    {
        ;
    }
    *s = '\0';
}

Initially, I was using the standard getchar() function mentioned in the book to read the input in get_input() which looked like this:

int get_input(char *arr)
{
    int c;
    printf("Enter the string: \n");
    while((c = getchar()) != '\n' && c != EOF)
    {
        *arr++ = c;
    }
    *arr = '\0';
}

So, I have a few questions:

  1. What's a better way to fgets() from reading the input on encountering '\n' than the one I have used?

     while(fgets(arr, MAXLINE, stdin))
     {
         break;
     }
    
  2. fgets() stops reading the line and stores it as an input once it either encounters a '\n' or EOF. But, it ends up storing the '\n' at the end of the string. Is there a way to prevent this or do I have to over-write the '\n' manually?

  3. Even though I used the modified version of scanf(" %d", &c), my output looks like this: (https://i.sstatic.net/M5aX4.jpg). Despite that I get Enter the string: twice when prompted to re-enter the second string in case of an overflow situation. Is the modified scanf() messing with my input? And how do I correct it?


Solution

  • In general, do not mix fgets with scanf. Although it may be a bit bloaty, you will avoid many problems by being consistent with reading input with fgets and then parse it with sscanf. (Note the extra s)

    A good way to remove the newline is buffer[strcspn(buffer, "\n")] = 0

    Example:

    // Read line and handle error if it occurs
    if(!fgets(buffer, buffersize, stdin)) {
        // Handle error
    }
    
    // Remove newline (if you want, not necessarily something you need)
    buffer[strcspn(buffer, "\n")] = 0;
    
    // Parse and handle error
    int val;
    if(sscanf(buffer, "%d", &val) != 1) {
        // Handle error
    }
    
    // Now you can use the variable val
    

    There is one thing here that might be dangerous in certain situations, and that is if buffer is not big enough to hold a complete line. fgets will not read more than buffersize characters. If the line is longer, the remaining part will be left in stdin.