2012-02-09 24 views
35

Ho lavorato su un piccolo esercizio per la mia classe CIS e sono molto confuso dai metodi che C usa per leggere da un file. Tutto ciò che devo veramente fare è leggere un file riga per riga e utilizzare le informazioni raccolte da ogni riga per fare alcune manipolazioni. Ho provato ad usare il metodo getline e altri senza fortuna. Il mio codice è attualmente la seguente:Passare attraverso un file di testo riga per riga in C

int main(char *argc, char* argv[]){ 
     const char *filename = argv[0]; 
     FILE *file = fopen(filename, "r"); 
     char *line = NULL; 

     while(!feof(file)){ 
     sscanf(line, filename, "%s"); 
     printf("%s\n", line); 
     } 
    return 1; 
} 

In questo momento io sono sempre un guasto seg con il metodo sscanf e io non so perché. Sono un monopolista e mi chiedo solo se ci fosse qualcosa di grande che mi mancava. Grazie

+1

Questo codice non deve anche compilare. 'sscanf (riga, nomefile,"% s ");' dovrebbe essere 'sscanf (riga, file,"% s ");' – Mawg

+0

Si noti che ['while (! feof (file))' è sempre sbagliato] (http : //stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong). –

+0

Possibile duplicato di [C leggere file riga per riga] (https://stackoverflow.com/questions/3501338/c-read-file-line-by-line) –

risposta

93

Così tanti problemi in così poche righe. Probabilmente me ne dimentico:

  • argv [0] è il nome del programma, non il primo argomento;
  • se si desidera leggere in una variabile, è necessario allocare la memoria
  • uno mai loop su feof, un loop su una funzione IO fino a quando non riesce, feof poi serve a determinare la causa del fallimento,
  • sscanf è lì per analizzare una riga, se vuoi analizzare un file, usa fscanf,
  • "% s" si fermerà al primo spazio come formato per la famiglia? scanf
  • per leggere una riga, lo standard funzione è fgets,
  • ritorno 1 dal guasto principale significa

Così

#include <stdio.h> 

int main(int argc, char* argv[]) 
{ 
    char const* const fileName = argv[1]; /* should check that argc > 1 */ 
    FILE* file = fopen(fileName, "r"); /* should check the result */ 
    char line[256]; 

    while (fgets(line, sizeof(line), file)) { 
     /* note that fgets don't strip the terminating \n, checking its 
      presence would allow to handle lines longer that sizeof(line) */ 
     printf("%s", line); 
    } 
    /* may check feof here to make a difference between eof and io failure -- network 
     timeout for instance */ 

    fclose(file); 

    return 0; 
} 
+19

non dimenticare 'fclose (file)' prima del ritorno . – vivisidea

+5

il 'fclose (file)' in realtà non è necessario, dal momento che sta accadendo in 'main' e chiuderà automaticamente tutti i buffer di file aperti. – Leandros

+11

@Leandros è sempre meglio essere al sicuro, che dispiaciuti! – Vallentin

6

per leggere una riga da un file, è necessario utilizzare la funzione fgets: Si legge una stringa dal file specificato fino a uno un carattere di nuova riga o EOF.

L'uso di sscanf nel codice non funzionerebbe affatto, come si usa filename come stringa di formato per la lettura da line in una stringa costante letterale %s.

Il motivo per SEGV è che si scrive nella memoria non allocata indicata da line.

2

In aggiunta alle altre risposte, in una libreria C recente (conforme a Posix 2008), è possibile utilizzare getline. Vedi this answer (in una domanda correlata).

3

Dire hai a che fare con qualche altro delimitatore, come ad esempio una scheda \t, invece di un ritorno a capo \n.

Un approccio più generale ai delimitatori è l'uso di getc(), che acquisisce un carattere alla volta.

Si noti che getc() restituisce un int, in modo che possiamo verificare l'uguaglianza con EOF.

secondo luogo, definiamo un array line[BUFFER_MAX_LENGTH] di tipo char, al fine di memorizzare fino a BUFFER_MAX_LENGTH-1 caratteri sullo stack (dobbiamo salvare quella dell'ultimo carattere di un personaggio \0 terminatore).

L'utilizzo di un array evita la necessità di utilizzare malloc e free per creare un puntatore di caratteri della lunghezza corretta nell'heap.

#define BUFFER_MAX_LENGTH 1024 

int main(int argc, char* argv[]) 
{ 
    FILE *file = NULL; 
    char line[BUFFER_MAX_LENGTH]; 
    int tempChar; 
    unsigned int tempCharIdx = 0U; 

    if (argc == 2) 
     file = fopen(argv[1], "r"); 
    else { 
     fprintf(stderr, "error: wrong number of arguments\n" 
         "usage: %s textfile\n", argv[0]); 
     return EXIT_FAILURE; 
    } 

    if (!file) { 
     fprintf(stderr, "error: could not open textfile: %s\n", argv[1]); 
     return EXIT_FAILURE; 
    } 

    /* get a character from the file pointer */ 
    while(tempChar = fgetc(file)) 
    { 
     /* avoid buffer overflow error */ 
     if (tempCharIdx == BUFFER_MAX_LENGTH) { 
      fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n"); 
      return EXIT_FAILURE; 
     } 

     /* test character value */ 
     if (tempChar == EOF) { 
      line[tempCharIdx] = '\0'; 
      fprintf(stdout, "%s\n", line); 
      break; 
     } 
     else if (tempChar == '\n') { 
      line[tempCharIdx] = '\0'; 
      tempCharIdx = 0U; 
      fprintf(stdout, "%s\n", line); 
      continue; 
     } 
     else 
      line[tempCharIdx++] = (char)tempChar; 
    } 

    return EXIT_SUCCESS; 
} 

Se è necessario utilizzare un char *, allora è ancora possibile utilizzare questo codice, ma si strdup() la matrice line[], una volta che è riempito con il valore di una riga di input. È necessario free questa stringa duplicato una volta che hai fatto con esso, o avrai una perdita di memoria:

#define BUFFER_MAX_LENGTH 1024 

int main(int argc, char* argv[]) 
{ 
    FILE *file = NULL; 
    char line[BUFFER_MAX_LENGTH]; 
    int tempChar; 
    unsigned int tempCharIdx = 0U; 
    char *dynamicLine = NULL; 

    if (argc == 2) 
     file = fopen(argv[1], "r"); 
    else { 
     fprintf(stderr, "error: wrong number of arguments\n" 
         "usage: %s textfile\n", argv[0]); 
     return EXIT_FAILURE; 
    } 

    if (!file) { 
     fprintf(stderr, "error: could not open textfile: %s\n", argv[1]); 
     return EXIT_FAILURE; 
    } 

    while(tempChar = fgetc(file)) 
    { 
     /* avoid buffer overflow error */ 
     if (tempCharIdx == BUFFER_MAX_LENGTH) { 
      fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n"); 
      return EXIT_FAILURE; 
     } 

     /* test character value */ 
     if (tempChar == EOF) { 
      line[tempCharIdx] = '\0'; 
      dynamicLine = strdup(line); 
      fprintf(stdout, "%s\n", dynamicLine); 
      free(dynamicLine); 
      dynamicLine = NULL; 
      break; 
     } 
     else if (tempChar == '\n') { 
      line[tempCharIdx] = '\0'; 
      tempCharIdx = 0U; 
      dynamicLine = strdup(line); 
      fprintf(stdout, "%s\n", dynamicLine); 
      free(dynamicLine); 
      dynamicLine = NULL; 
      continue; 
     } 
     else 
      line[tempCharIdx++] = (char)tempChar; 
    } 

    return EXIT_SUCCESS; 
} 
+1

Voterò "any" while (! Feof (file)) "anche se il caso si verifica una volta in una luna blu dove non è dannoso (nota che qui probabilmente non sarà mai stato vero, c'è una pausa per lasciare il ciclo in quel caso, 'while while (true)' funzionerebbe pure.) Ci sono troppi che pensano che sia l'idioma corretto. – AProgrammer

+0

Non avevo idea che fosse un problema. Mi piacerebbe davvero saperne di più su questo. Quali sono i problemi con quell'uso? –

+0

Ci sono molte domande su questo argomento, http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong per esempio. – AProgrammer

Problemi correlati