Search code examples
cinputiooutputfgets

Why fgets is not inputting first value?


I am writing a program to write my html files rapidly. And when I came to write the content of my page I got a problem.

#include<stdio.h>

int main()
{
int track;
int question_no;

printf("\nHow many questions?\t");

scanf("%d",&question_no);

char question[question_no][100];

    for(track=1;track<=question_no;track++)
    {
        printf("\n<div class=\"question\">%d. ",track);
        printf("\nQuestion number %d.\t",track);
        fgets(question[track-1],sizeof(question[track-1]),stdin);
        printf("\n\n\tQ%d. %s </div>",track,question[track-1]);
    }

}

In this program I am writing some questions and their answers (in html file). When I test run this program I input the value of question_no to 3. But when I enter my first question it doesn't go in question[0] and consequently the first question doesn't output. The rest of the questions input without issue.

I searched some questions on stackoverflow and found that fgets() looks for last \0 character and that \0 stops it.
I also found that I should use buffer to input well through fgets() so I used: setvbuf and setbuf but that also didn't work (I may have coded that wrong). I also used fflush(stdin) after my first and last (as well) scanf statement to remove any \0 character from stdin but that also didn't work.

Is there any way to accept the first input by fgets()?
I am using stdin and stdout for now. I am not accessing, reading or writing any file.


Solution

  • Use fgets for the first prompt too. You should also malloc your array as you don't know how long it is going to be at compile time.

    #include <stdlib.h>
    #include <stdio.h>
    
    #define BUFSIZE 8
    
    int main()
    {
        int track, i;
        int question_no;
        char buffer[BUFSIZE], **question;
    
        printf("\nHow many questions?\t");
    
        fgets(buffer, BUFSIZE, stdin);
        question_no = strtol(buffer, NULL, 10);
    
        question = malloc(question_no * sizeof (char*));
        if (question == NULL) {
            return EXIT_FAILURE;
        }
        for (i = 0; i < question_no; ++i) {
            question[i] = malloc(100 * sizeof (char));
            if (question[i] == NULL) {
                return EXIT_FAILURE;
            }
        }
    
        for(track=1;track<=question_no;track++)
        {
            printf("\n<div class=\"question\">%d. ",track);
            printf("\nQuestion number %d.\t",track);
            fgets(question[track-1],100,stdin);
            printf("\n\n\tQ%d. %s </div>",track,question[track-1]);
        }
    
        for (i = 0; i < question_no; ++i) free(question[i]);
        free(question);
        return EXIT_SUCCESS;
    }
    

    2D arrays in C

    A 2D array of type can be represented by an array of pointers to type, or equivalently type** (pointer to pointer to type). This requires two steps.

    Using char **question as an exemplar:

    The first step is to allocate an array of char*. malloc returns a pointer to the start of the memory it has allocated, or NULL if it has failed. So check whether question is NULL.

    Second is to make each of these char* point to their own array of char. So the for loop allocates an array the size of 100 chars to each element of question. Again, each of these mallocs could return NULL so you should check for that.

    Every malloc deserves a free so you should perform the process in reverse when you have finished using the memory you have allocated.

    malloc reference

    strtol

    long int strtol(const char *str, char **endptr, int base);

    strtol returns a long int (which in the code above is casted to an int). It splits str into three parts:

    1. Any white-space preceding the numerical content of the string
    2. The part it recognises as numerical, which it will try to convert
    3. The rest of the string

    If endptr is not NULL, it will point to the 3rd part, so you know where strtol finished. You could use it like this:

    #include <stdio.h>                                                                                                                             
    #include <stdlib.h>                                                                                                                            
    
    int main()                                                                                                                                     
    {                                                                                                                                              
        char * endptr = NULL, *str = "    123some more stuff";                                                                                       
        int number = strtol(str, &endptr, 10);                                                                                                       
        printf("number interpreted as %d\n"                                                                                                          
               "rest of string: %s\n", number, endptr);                                                                                              
        return EXIT_SUCCESS;                                                                                                                         
    }
    

    output:

    number interpreted as 123
    rest of string: some more stuff
    

    strtol reference