0
votes

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.

3
@interjay No! It's genuine. :D It is just mine.Ashish Tomer
What? I'm just saying that this question is basically the same as the linked one. I didn't say that you copied it or anything like that. It was just an automatically generated comment that is created when someone votes to close a question as a duplicate of another.interjay
@AshishTomer; Yes, we know that its your's :). @interjay just mean to say that this type of question has already been asked before.haccks
Okay! :D :D ha ha ha haAshish Tomer

3 Answers

2
votes

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

2
votes

This is because the previous newline character left in the input stream by scanf(). Note that fgets() stops if it encounters a newline too.

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer

Don't mix fgets() and scanf(). A trivial solution is to use getchar() right after scanf() in order to consume the newline left in the input stream by scanf().

2
votes

As per the documentation,

The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, or a < newline > is read and transferred to s, or an end-of-file condition is encountered

In case of scanf("%d",&question_no); a newline is left in the buffer and that is read by

fgets(question[track-1],sizeof(question[track-1]),stdin);

and it exits.

In order to flush the buffer you should do,

while((c = getchar()) != '\n' && c != EOF)
        /* discard */ ;

to clear the extra characters in the buffer