2012-02-09 19 views
35

He estado trabajando en un pequeño ejercicio para mi clase CIS y estoy muy confundido por los métodos que C usa para leer desde un archivo. Todo lo que realmente necesito hacer es leer un archivo línea por línea y usar la información obtenida de cada línea para hacer algunas manipulaciones. Intenté usar el método getline y otros sin suerte. Mi código es actualmente de la siguiente manera:Pasando por un archivo de texto línea por línea en 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; 
} 

En este momento me estoy haciendo una falla seg con el método sscanf y no estoy seguro de por qué. Soy un novato total de C y me pregunto si había algo importante que me faltaba. Gracias

+1

Este código no debería ni siquiera compilar. 'sscanf (línea, nombre de archivo,"% s ");' debe ser 'sscanf (línea, archivo,"% s ");' – Mawg

+0

Tenga en cuenta que ['while (! feof (archivo))' siempre es incorrecto] (http : //stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong). –

+0

Posible duplicado de [C leer archivo línea por línea] (https://stackoverflow.com/questions/3501338/c-read-file-line-by-line) –

Respuesta

93

Tantos problemas en tan pocas líneas. Probablemente me olvide algo:

  • argv [0] es el nombre del programa, no el primer argumento;
  • si desea leer en una variable, tiene que asignar su memoria
  • uno nunca lazadas en feof, uno bucles en una función de IO hasta que falla, feof sirve entonces para determinar el motivo del fallo,
  • sscanf está ahí para analizar una línea, si desea analizar un archivo, use fscanf,
  • "% s" se detendrá en el primer espacio como formato para la familia? scanf
  • para leer una línea, el estándar la función es fgets,
  • que vuelve 1 del medio principal falla

Así

#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

no se olvide 'fclose (archivo)' antes de regresar . – vivisidea

+5

el 'fclose (archivo)' en realidad no es necesario, ya que está sucediendo en 'main' y cerrará automáticamente todos los búferes de archivos abiertos. – Leandros

+11

@Leandros siempre es mejor estar seguro, que lo siento! – Vallentin

6

para leer una línea de un archivo, se debe utilizar la función fgets: Lee una cadena desde el archivo especificado hasta bien un carácter de nueva línea o EOF.

El uso de sscanf en el código no funcionaría en absoluto, y cuando se utiliza filename como su cadena de formato para la lectura de line en una cadena constante literal %s.

El motivo de SEGV es que escribe en la memoria no asignada apuntada por line.

2

Además de las otras respuestas, en una biblioteca C reciente (compatible con Posix 2008), puede usar getline. Ver this answer (a una pregunta relacionada).

3

Digamos que está tratando con algún otro delimitador, tal como una lengüeta \t, en lugar de una nueva línea \n.

Un enfoque más general de los delimitadores es el uso de getc(), que toma un carácter a la vez.

Tenga en cuenta que getc() devuelve int, por lo que podemos probar la igualdad con EOF.

En segundo lugar, definimos un array de tipo line[BUFFER_MAX_LENGTH]char, con el fin de almacenar hasta BUFFER_MAX_LENGTH-1 caracteres en la pila (tenemos que salvar lo último carácter de un personaje \0 terminador).

El uso de una matriz evita la necesidad de utilizar malloc y free para crear un puntero de carácter de la longitud correcta en el montón.

#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; 
} 

Si tiene que usar un char *, a continuación, puede seguir utilizando este código, pero strdup() la matriz line[], una vez que se llena con el valor de una línea de entrada. Debe free esta cadena duplicada una vez que haya terminado con él, o tendrá que obtener una pérdida de 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

Voy a votar abajo cualquier 'while (! Feof (archivo))' incluso el caso que ocurre una vez que es una luna azul donde no está dañado (Tenga en cuenta que aquí probablemente nunca haya sido cierto, hay un descanso para abandonar el ciclo en ese caso, 'while (true)' funcionaría también.) Hay demasiados que piensan que es el modismo correcto. – AProgrammer

+0

No tenía idea de que era un problema. Sinceramente, me gustaría aprender más sobre esto. ¿Cuáles son los problemas con ese uso? –

+0

Hay muchas preguntas en las que surgió esto, http://stackoverflow.com/questions/5431941/while-feof-file-is- allways- wrong por ejemplo. – AProgrammer

Cuestiones relacionadas