• C

getline function reading from a text file

Hi folks,

I`m doing a project with a few friends where we create a virtual pub quiz using C.

I have a few files which I read into the console, most of which I am fine with.  The file I am having trouble with is the actual question file.

This file contains 20 questions, each question is followed by 4 answers [ example below ]:

Where were the 1970 football World Cup finals held ?
Mexico,Spain,Brazil,England

What I am trying to do is obviously read this file into an array, then display each question and the answers on a seperate line [ as it is in the text file ] rather than all on one line like it currently is.

The code I am working with is below:


void readquiz() {
      
      int i;
      
      FILE *quiz_ptr;
      
      quiz_ptr = fopen("quiz.txt", "r");
      
      if(quiz_ptr != NULL) {
            
            i=0;
            
            while (fscanf(quiz_ptr, "%s", var[i]) != EOF) {
                  printf("%s ", var[i]);
                  i++;
            }
            
            printf("\n\n");
            fclose(quiz_ptr);
      }
}


Currently the data is printed as this :

Where were the 1970 football World Cup finals held ? Mexico,Spain,Brazil,England


I want it to look like this :

Where were the 1970 football World Cup finals held ?
Mexico,Spain,Brazil,England

Problem is I dont know how getline works and cant find much info on it, can anyone help ?

Thanks.
LVL 2
3nigmaticAsked:
Who is Participating?
 
brettmjohnsonCommented:
Don't use getline() - it is non-standard.  Use fgets() instead.  It also has the benefit of being better documented.


void readquiz() {
     int i;
     FILE *quiz_ptr;
     char *answs[4];
     char *sep = ",\r\n";
     char line[4096];

     quiz_ptr = fopen("quiz.txt", "r");
     
     if(quiz_ptr != NULL) {
          while (fgets(line, sizeof(line), quiz_ptr) {      /* read the next question */
               fputs(line, stdout);      /* display question */

               if (fgets(line, sizeof(line), quiz_ptr) {      /* read the answers */
                   /* parse the answers into an array */
                   for(i = 0, tok = strtok(line, sep); i < 4 && tok; i++, tok = strtok(NULL, sep))
                       answs[i] = tok;
                   /* display the answers */
                   printf("a) %s\tb) %s\tc) %s\td) %s\n\n", answs[0], answs[1], answs[2], answs[3]);
               }
          }
         
          printf("\n\n");
          fclose(quiz_ptr);
     }
}
0
 
Kent OlsenData Warehouse Architect / DBACommented:
Hi 3nigmatic,

How is the data file structured?  Are the questions and answers on 1 line or several?

My guess is that everything is on one line.  In that case, you'll have to split the line yourself.  Not too tough, though.


char *Question;
char *Answers;

          while (fscanf(quiz_ptr, "%s", var[i]) != EOF) {
               Question = var[i];
               Answer = strchr (Question, '?');
               if (Answer) {
                 ++Answer;
                 *Answer = 0;
               }
               printf("%s\n%s", Question, Answer);
               i++;



That will do for demonstration purposes, though I suggest that you rethink your array so that you can put the questions and answers in different locations.


Good Luck!
Kent
0
 
3nigmaticAuthor Commented:
Quiestions file data structure is like this:

Where were the 1970 football World Cup finals held ?
Mexico,Spain,Brazil,England
In books by JRR Tolkien, what kind of creatures are Bilbo and Frodo Baggins ?
Hobbits,Orcs,Elves,Humans
Which Italian city is home of the car manufacturer Fiat ?
Turin,Rome,Pisa,Ravena

For 20 questions plus four answers for each question.

The reason I want to use an array is because I will eventually randomise the answer output positions so that people can not just memorise the locations of the correct answer for each question.
0
Turn Raw Data into a Real Career

There’s a growing demand for qualified analysts who can make sense of Big Data. With an MS in Data Analytics, you can become the data mining, management, mapping, and munging expert that today’s leading corporations desperately need.

 
Kent OlsenData Warehouse Architect / DBACommented:
Hi 3nigmatic,

You can get past the single line effect with just a small change to the printf() statement.

          while (fscanf(quiz_ptr, "%s", var[i]) != EOF) {
               printf("%s\n", var[i]);    // Notice that \n has been added to the format.
               i++;
          }

That will put the question and answer on separate lines.

My suggestion is that you build two arrays.  

char Questions[MAX_QUESTIONS][MAX_LENGTH];
char Answers[MAX_QUESTIONS][MAXLENGTH];

Then in the while loop, read the question then the list of answers.  Answers[0] will apply to Question[0], Answer[6] will apply to Question[6], etc.  Just pick any random number and you have both the question and answer list for that number.


Kent
0
 
3nigmaticAuthor Commented:
brettmjohnson,

Thanks for your suggestion I`m looking into how it works etc now.


kdo,

Adding \n to my printf statement does produce a new line, but every new word is on a new line.  This is why I am looking to use getline, or as suggested by brettmjohnson fgets [ which I have also been reading up on ].
0
 
3nigmaticAuthor Commented:
With a little modification I went with brettmjohnson's code:

void readquiz() {

     FILE *quiz_ptr;
     char *answs[4];
     char *sep = ",\r\n";
     char line[4096];
       int i;
       int tok;
       int count = 1;

     quiz_ptr = fopen("quiz.txt", "r");
     
     if(quiz_ptr != NULL) {
          while (fgets(line, sizeof(line), quiz_ptr)) {     /* read the next question */
                    printf("%d) ", count);
               fputs(line, stdout);     /* display question */

               if (fgets(line, sizeof(line), quiz_ptr)) {     /* read the answers */
                   /* parse the answers into an array */
                   for(i = 0, tok = strtok(line, sep); i < 4 && tok; i++, tok = strtok(NULL, sep))
                       answs[i] = tok;
                   /* display the answers */
                   printf("\ta) %s\n\tb) %s\n\tc) %s\n\td) %s\n\n", answs[0], answs[1], answs[2], answs[3]);
                           count ++;
               }
          }
              fclose(quiz_ptr);
     }
}

I am a little stuck as to what the variables tok & sep do though, can anyone explain ?

Thanks.
0
 
brettmjohnsonCommented:
> I am a little stuck as to what the variables tok & sep do though, can anyone explain ?

strtok() tokenizes (breaks up) the string (line) based upon the separator characters (delimiters) in sep.  tok is a pointer to the returned string fragment strtok found.  BTW, strtok() tokenizes in place, so it overwrites the found delimiter (',' or newline) in line with a NUL byte, then returns a pointer to the beginning of that substring, so to will always be a pointer to somewhere in the line buffer (except when  its NULL).  

One caution: strtok() is not thread-safe - it maintains internal state (of its current position in the string) in static local storage (hence passing NULL on subsequent calls).  If you need thread-safety, consider strtok_r() or strsep() instead.

Not also that the code is not robust (for the sake of simplicity and demonstration).   It does not tolerate malformed answers - missing or less than 4 choices.

What is the variable 'count' for?  I appears to be the number of questions+1, but is otherwise unused.
0
 
3nigmaticAuthor Commented:
Thanks Brett for the explination, still a little confused but I will work it out ... always good fun.

Err, as for the var count, as you stated, it is basicaly there just to number the questions and thats it.

Why do you ask, is there something wrong with the way I have done it ?
0
 
brettmjohnsonCommented:
I only asked about 'count' because it is apparently used outside the chunk of code you posted, but as as count of the number of questions ,it is off by one.  To correct the issue, initialize count to 0, not 1.

0
 
3nigmaticAuthor Commented:
If I was to set the var count = 0; though, it would show that I had just 19 questions when in fact there are 20.

Or am I missing your point here  ?
0
 
brettmjohnsonCommented:
You aren't really missing the point, you are just wrong.  
Walk through the code with test files that contain 0, 1, 2,  and 3 questions.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.