0

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.

noelicus
  • 14,468
  • 3
  • 92
  • 111
Ashish Tomer
  • 55
  • 1
  • 8
  • possible duplicate of [fgets instructions gets skipped.Why?](http://stackoverflow.com/questions/2907062/fgets-instructions-gets-skipped-why) – interjay Nov 20 '13 at 09:58
  • @interjay No! It's genuine. :D It is just mine. – Ashish Tomer Nov 20 '13 at 10:02
  • 3
    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 Nov 20 '13 at 10:04
  • 1
    @AshishTomer; Yes, we know that its your's :). @interjay just mean to say that this type of question has already been asked before. – haccks Nov 20 '13 at 10:07

3 Answers3

2

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().

P.P
  • 117,907
  • 20
  • 175
  • 238
2

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

Suvarna Pattayil
  • 5,136
  • 5
  • 32
  • 59
2

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

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • I am already asking user about the Number of Questions he want to enter. So why do I use malloc. Won't malloc increase the processing time? Because this program looks much lengthier than mine. (I am beginner :P) – Ashish Tomer Nov 20 '13 at 10:29
  • You find out during the execution of your program how big the array should be - you don't know in advance. Are you genuinely concerned about the time it takes to do a few `malloc`s, even if you are relying on manual input from the user? – Tom Fenech Nov 20 '13 at 10:38
  • @AshishTomer I've added a few more lines for you as well - you should check whether `malloc` has succeeded. If not, it returns a `NULL` pointer. – Tom Fenech Nov 20 '13 at 10:43
  • And I am glad by the way you created 2-D array through first for loop. Does `if statement` in first `for loop` check whether `malloc` has succeeded? Also, what is the role of 2nd argument in `strtol()` function? I read some where on internet that it's the next character to the one you want to convert to Long Integer. But that was not clear enough. Can you explain to me please? Or if you could give me a link. – Ashish Tomer Nov 21 '13 at 05:12
  • I can not digest your answer: – Ashish Tomer Nov 21 '13 at 07:00
  • I can not digest your answer:
    First you allocate memory to whole question(array) :-
    `question = malloc(question_no * sizeof (char*));`
    which is just 4 bytes (in case user wants to input 4 questions)
    And then question is mutated as 2-D array in first loop, where each individual array is 100 bytes long. What makes 'question' 400 bytes long array.
    I may be wrong but that's how I am perceiving your answer.
    Please reply me.
    – Ashish Tomer Nov 21 '13 at 07:07
  • Feneh Or is it just dynamically elastic array. ( **I mean can allocated memory increase on it's own this way?** ) – Ashish Tomer Nov 21 '13 at 07:12
  • @AshishTomer Some of us have to sleep you know! I have explained my use of `malloc` and `strtol` in the answer. – Tom Fenech Nov 21 '13 at 09:59
  • :( I am really sorry. It evening here on my side. – Ashish Tomer Nov 21 '13 at 10:40