0

I am given a text file of movie showtime information. I have to format the information in a clean way. Right now I'm just trying to get all line's information saved into strings. However, when getting the movie's rating the array wont save the rating properly.

This is the main code.

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const int MAX_TITLE_CHARS = 44;  // Maximum length of movie titles
    const int LINE_LIMIT = 100;   // Maximum length of each line in the text file
    char line[LINE_LIMIT];
    char inputFileName[25];


    FILE *file;
    file = fopen("D:\\movies.txt", "r");

    char currentLine[LINE_LIMIT];
    char movieTitle[MAX_TITLE_CHARS];
    char movieTime[10];
    char movieRating[10];

    fgets(currentLine, LINE_LIMIT, file); // Get first file
    while(!feof(file)){

        sscanf(currentLine, "%[^,],%44[^,],%s", movieTime, movieTitle, movieRating);

        printf("%s\n", movieRating);
        fgets(currentLine, LINE_LIMIT, file); // Get next file

    }

    return 0;
}

This is the CVS file

16:40,Wonders of the World,G
20:00,Wonders of the World,G
19:00,Journey to Space ,PG-13
12:45,Buffalo Bill And The Indians or Sitting Bull's History Lesson,PG
15:00,Buffalo Bill And The Indians or Sitting Bull's History Lesson,PG
19:30,Buffalo Bill And The Indians or Sitting Bull's History Lesson,PG
10:00,Adventure of Lewis and Clark,PG-13
14:30,Adventure of Lewis and Clark,PG-13
19:00,Halloween,R

This prints out

G
G
PG-13
PG-13
PG-13
PG-13
PG-13
PG-13
R

I need it to be

G
G
PG-13
PG
PG
PG
PG-13
PG-13
R

I use Eclipse and when in the debugger, I see that when it encounters the first PG-13, it doesn't update at all until the R. I'm thinking maybe since PG and PG-13 have the same two starting characters perhaps it gets confused? I'm not sure. Any help is appreciated.

Petetunze
  • 35
  • 4
  • `while(!feof(file)){` --> [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/q/5431941/2410359). – chux - Reinstate Monica Mar 11 '22 at 23:33
  • @chux-ReinstateMonica Yeah I took out the `44` in `sscanf` and it works just fine. However, I need the movie title to print out a max of 44 characters and have padding with respect to the left. Right now I have `printf("%-44s |\n")` to print the movie name with a `|` but I need it also only read up to 44 characters. Thus, the Buffalo Bill needs to be `Buffalo Bill...Bull |`. How do I do that? – Petetunze Mar 11 '22 at 23:41
  • "I took out the 44 in sscanf and it works just fine." --> not just fine. Code is attempting to write outside `movieTitle[]`, which is UB. – chux - Reinstate Monica Mar 12 '22 at 01:39

3 Answers3

0

Your string 'Buffalo Bill...' is more than 44 characters. thus the sccanf statement reads up to that limit, it then looks for a ',', which doesn't exist 44 characters into the string and exits.

Because your new movieRating isn't being set, it just prints the previous value.

Hint: If you are looking for a work around, you can parse your string with something like strsep(). You can also just increase the size of your movie title.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Charles S
  • 26
  • 2
0

You are converting the line using the following line:

sscanf(currentLine, "%[^,],%44[^,],%s", movieTime, movieTitle, movieRating);

the function will read a string into movietTime until a ',' appears in the input, then it will read another string until either a ',' appears or 44 characters are read. This behavior is explained in the manual for sscanf:

...
An optional decimal integer which specifies the  maximum  field  width.
Reading of characters stops either when this maximum is reached or when
a nonmatching character is found, whichever happens first...

The lines with PG ratings have titles with 62 characters. Thus, it does not read the entire title, and does not find the comma. To fix this issue, you can either set MAX_TITLE_CHARS to a greater value or use the %m modifier to have sscanf dynamically allocate the string for you.

0

OP code had undefined behavior (UB) as the movieTitle[] was only big enough for 43 character + the terminating null character and OP used "%44[^,]" rather than the correct width limit of 43.

const int MAX_TITLE_CHARS = 44;  // Maximum length of movie     
...
 char movieTitle[MAX_TITLE_CHARS];

Other problems too that followed this UB.


Account for the '\n' of the line and a '\0' to form a string.

Never use while(feof(...)).

Test sscanf() results.

Limit printed title width with a precision.

const int LINE_LIMIT = 100; // Maximum length of each line in the text file
char line[LINE_LIMIT + 2 /* room for \n and \0 */];

while (fgets(currentLine, sizeof currentLine, file)) {
  // Either use a _width limit_ with `"%s"`, `"%[]"` or use a worse case size.
  char movieTime[10 + 1];  // 10 characters + \0
  char movieTitle[sizeof currentLine];
  char movieRating[sizeof currentLine];
  // Examples: 
  // Use a 10 width limit for the 11 char movieTime
  // Others: use a worst case size.
  if (sscanf(currentLine, " %10[^,], %[^,], %[^\n]", 
      movieTime, movieTitle, movieRating) != 3) {
    fprintf(stderr, "Failed to parse <%s>\n", currentLine);
    break;
  } 
  // Maximum length of movie titles _to print_
  const int MAX_TITLE_CHARS = 44;  
  printf("Title: %-.*s\n", MAX_TITLE_CHARS, movieTitle);
  printf("Rating: %s\n", movieRating);
}

Note that "Maximum length of each line" is unclear if the length includes the ending '\n'. In the C library, a line includes the '\n'.

A text stream is an ordered sequence of characters composed into lines, each line consisting of zero or more characters plus a terminating new-line character. Whether the last line requires a terminating new-line character is implementation-defined. C17dr § 7.21.2 2

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256