1

I have a problem with this program: I was able to make another draft program but it only reads the first three lines and stops. Unfortunately, the input file is not symmetrical so I should use while loops for some parts only to avoid repeating parts of the program. With strcpy I could copy the work done up to a certain point and then continue from that point on. I was trying but visual studio tells me to move the memory to the heap but I don't know how to do it ... Practically I should only extrapolate certain data from the input file and order them in an output file according to a precise line. I also know there's a problemi with char buf[200], rec[200] because I have to allocate much more memory...

  • [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – David Ranieri Jun 23 '20 at 10:15
  • I don't know to change what i've done... –  Jun 23 '20 at 10:15
  • Use `while (1)` or `for (;;)` and `break` the loop if one of the `fscanf`s returns something diiferent to 1 – David Ranieri Jun 23 '20 at 10:18
  • Can you help me please? –  Jun 23 '20 at 10:27
  • start checking with the debugger what happens when you use `buf` uninitialized. – David Ranieri Jun 23 '20 at 13:19
  • @David Ranieri I'll try what you suggested ... As far as memory allocation is concerned, how can I do it? Should I use malloc? –  Jun 23 '20 at 13:54
  • No, you don't need dynamic memory, since you are writing to a file a buffer large enough will suffice, but you should initialize your objects before reading them. I want to help but I'm not able to see a pattern in your source file :( – David Ranieri Jun 23 '20 at 13:59
  • Thank you again, I published a pattern of the source file , for example "session 1 (COPY MODE): number of sequences: 15 registration 1: characters given: CALOR registration 2: characters given: CARINO" you don't see it? –  Jun 23 '20 at 14:43
  • Hope you can help me now ahaha –  Jun 23 '20 at 14:44
  • The problem is that you don't follow the same rules in the sections, you want COPY MODE or ONLINE_FREE_MODE? you want given or recognized? You need a more solid design, `fscanf` has poor regex support. – David Ranieri Jun 23 '20 at 15:56
  • @David Ranieri the problem is that the input file is exactly that one, as I said unfortunately it isn't symmetrical so I have to do different loops during the scan. So I think I should save what the fscan does up to a certain point with strcpy and they start a new loop from that point forward to scan a new section... –  Jun 23 '20 at 16:15
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/216514/discussion-between-sandra-boccia-and-david-ranieri). –  Jun 23 '20 at 16:18
  • the duplicate is wrong for me, the problem is not about `feof` but how to extract the data from the non regular file – bruno Jun 25 '20 at 06:36

1 Answers1

0

the first time in

while ( !feof(fd) ) {
  fscanf(fd, "session %d (COPY MODE):\n\n", &session);

you call feof before any read so feof cannot work proprely, an easy change is to do

while (fscanf(fd, "session %d (COPY MODE):\n\n", &session) == 1) {

Out of that the mode can be something else that COPY MODE and the two \n after are not mandatory, you also do not check your next fscanf success and globaly the algorithm you use is wrong

A possible way to do the job also checking the validity of the input file is :

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

int main()
{
  FILE * fp = fopen("summary.txt", "r");
  
  if (fp == NULL) {
    perror("cannot open summary.txt");
    exit(1);
  }
  
  int session;
  char mode[64];
  const char * separator = "_____________________________________________";
  
  while (fscanf(fp, " session %d (%[^)]):", &session, mode) == 2) {
    if (strcmp(mode, "COPY MODE") && strcmp(mode,"ONLINE FREE MODE")) 
    {
       fprintf(stderr, "invalid file, invalid mode '%s'\n", mode);
       exit(1);
    }

    char line[64];
    char given[64];
    char recognized[64];
    int registration, registration_set = 0;
    int sequences, sequences_set = 0;
    
    for(;;) {
      /* read next line, bypass possible newline(s) before */
      if (fscanf(fp, " %63[^\n]", line) != 1) { 
        if (!feof(fp)) {
          perror("reading file");
          exit(1);
        }
        *line = 0;
      }
      else if (sscanf(line, "number of sequences: %d", &sequences) == 1) {
        sequences_set = 1;
        continue;
      }
      else if ((*given == 0) && 
               (sscanf(line, "characters given: %63s", given) == 1)) {
        if (!registration_set) {
          fprintf(stderr, 
                  "registration is missing before 'characters given: %s'\n",
                  given);
          exit(1);
        }
        if (!sequences_set) {
          fprintf(stderr, 
                  "sequences is missing before 'characters given: %s'\n",
                  given);
          exit(1);
        }
        continue;
      }
      else if ((*recognized == 0) &&
               (sscanf(line, "characters recognized: %63s", recognized) == 1)) {
        if (!*given) {
          fprintf(stderr, 
                  "given is missing before 'characters recognized: %s'\n",
                  recognized);
          exit(1);
        }
        continue;
      }
      
      if (registration_set) {
        if (!*given) {
          fputs("invalid file, given is missing\n", stderr);
          exit(1);
        }
        printf("%d %d %d %s %s\n", session, registration, sequences, given, recognized);
        
        if (!*line || !strcmp(line, separator))
          break;
      }
      
      if (sscanf(line, "registration %d:", &registration) != 1) {
        fprintf(stderr,
                "invalid file, 'registration <n>:' expected rather than '%s'\n",
                line);
        exit(1);
      }
      else {
        registration_set = 1;
        *given = *recognized = 0;
      }
    }
  }
  
  fclose(fp);
  return 0;
}

Note the space at the beginning of the format of the fscanf, that allows to bypass character considered to be space including the newline

Compilation and execution :

pi@raspberrypi:/tmp $ gcc -Wall c.c
pi@raspberrypi:/tmp $ cat summary.txt 
session 1 (COPY MODE):
number of sequences: 15
 
registration 1:
characters given: CALOR
 
registration 2:
characters given: CARINO
 
registration 3:
characters given: SUSHI
 

_____________________________________________
session 2 (COPY MODE):
registration 1:
number of sequences: 15
 
characters given: SUSHI
characters recognized: SUSHI
 
_____________________________________________
session 3 (ONLINE FREE MODE):
number of sequences: 15
 
registration 1:
 
characters given: PERA
characters recognized: PFRA
 
registration 2:
 
characters given: SALON
characters recognized: SALON
 
registration 3:
 
characters given: PERRO  
characters recognized: PERRO
 
_____________________________________________
session 4 (ONLINE FREE MODE):
 
registration 1:
number of sequences: 7
 
characters given: TORTUGA
characters recognized: TORTUGA
 
registration 2:
number of sequences: 4
 
characters given: ANAEROBIO
characters recognized: ANAERPBIO
 
registration 3:
number of sequences: 4
 
characters given: PAPELES
characters recognized: PAPELEX
pi@raspberrypi:/tmp $ ./a.out
1 1 15 CALOR 
1 2 15 CARINO 
1 3 15 SUSHI 
2 1 15 SUSHI SUSHI
3 1 15 PERA PFRA
3 2 15 SALON SALON
3 3 15 PERRO PERRO
4 1 7 TORTUGA TORTUGA
4 2 4 ANAEROBIO ANAERPBIO
4 3 4 PAPELES PAPELEX
pi@raspberrypi:/tmp $ 
bruno
  • 32,421
  • 7
  • 25
  • 37
  • Thank you very much! Can you just make it more simple please? It's a bit difficult for me to understand it all... –  Jun 24 '20 at 19:07
  • @SandraBoccia it can be a little simplified removing the tests checking the input file is correct, anyway to do that is not a good idea, I encourage you to *always* check the validity of the inputs – bruno Jun 24 '20 at 19:21
  • @SandraBoccia why did you edited my answer to remove the part compilation & execution ? (I rejected your edit) And why did you also edit your question to remove a large part of it ? (I rollback) – bruno Jun 24 '20 at 21:06