2010-10-13 12 views
5
struct DVDInfo *ReadStruct(void) { 
    struct DVDInfo *infoPtr; 
    int    num; 
    char   line[ kMaxLineLength ]; 
    char   *result; 

    infoPtr = malloc(sizeof(struct DVDInfo)); 

    if (NULL == infoPtr) { 
     printf("Out of memory!!! Goodbye!\n"); 
     exit(0); 
    } 

    printf("Enter DVD Title: "); 
    result = fgets(line, kMaxLineLength, stdin); 
    line[ strlen(line) - 1 ] = '\0'; 
    infoPtr->title = MallocAndCopy(line); 

    printf("Enter DVD comment: "); 
    result = fgets(line, kMaxLineLength, stdin); 
    line[ strlen(line) - 1 ] = '\0'; 
    infoPtr->comment = MallocAndCopy(line); 

    do { 
     printf("Enter DVD Rating (1-10): "); 
     scanf("%d", &num); 
     Flush(); 
    } 
    while ((num < 1) || (num > 10)); 

    infoPtr->rating = num; 

    printf("\n----------\n"); 

    return(infoPtr); 
} 

Hice una pregunta diferente sobre este código en otro hilo en stackoverflow pero no quería doblarlo: ¿por qué se agrega el cero de finalización al final de estos archivos leídos por fgets? Fgets agrega el cero de finalización de todos modos, ¿no es esto exagerado?fgets naturalmente pone un cero de finalización en C?

+2

C ha de desbordamiento del búfer suficientes oportunidades como es. Uno debería animar cuando las funciones se toman el tiempo para asegurar que una cadena termine correctamente. (Una cadena en C * debe * terminar con un NUL para ser una cadena válida, por definición en C.) –

+2

Sí, es excesivo. –

Respuesta

2

fgets escribe un terminador nulo en el búfer que proporciona (si especifica el tamaño del búfer como mayor que 0). De lo contrario, no podría llamar a strlen() en él, strlen() espera una cadena, y si no se termina, no es una cadena.

Estás preguntando por

line[ strlen(line) - 1 ] = '\0'; 

Esto quita el último carácter de line Si usted ha leído una línea, que reemplaza el último carácter, presumiblemente un \ n con un terminador nulo.

Ten en cuenta que solo tienes que leer una línea, p. su buffer line ahora contiene la cadena "Hello \ n" (la \ n es solo la secuencia de escape aquí, en realidad es solo 1 carácter, no 2)

strlen ("Hello \ n") es 6 y 6 1 es 5, por lo que el índice de 5. se sustituye por 0

"Hello\n" 
    ^
     | 
     Add 0 terminator 

Resultado: "Hola"

Sólo tenga cuidado:

  • no desea hacer la línea [strlen (línea) - 1] = '\ 0'; en una cadena vacía, en ese caso terminarás haciendo la línea [-1].
  • Debería comprobar si los fracasos suceden. No desea buscar en line si los errores fallaron y no escribió nada en el búfer.
  • Es posible que desee comprobar si realmente se leyó una línea completa. SI la línea que lees es más grande que kMaxLineLength, o p. Ej. si la última "línea" en el archivo no tiene un \ n finalizado, strlen (línea) -1 no será \ n (nueva línea).
+1

Su última viñeta también debe dar cuenta de la última línea de un archivo sin una línea nueva posterior. – jamesdlin

3

En general, reemplaza el carácter de nueva línea que se suma a la cadena con un carácter NUL. En todos los casos, los fgets terminarán en NUL.

Ver: http://www.opengroup.org/onlinepubs/009695399/functions/fgets.html

+0

fgets siempre termina con un 0; –

+2

no siempre. Si pasas la longitud como 0 entonces no lo hará. Caso de esquina loco sin embargo. – JaredPar

1

Su

result = fgets(line, kMaxLineLength, stdin); 

está bien ya que el tamaño de la línea es kMaxLineLength.

fgets lee como mucho uno menos que size personajes de stream y los almacena en la memoria intermedia ...

1

El line[ strlen(line) - 1 ] = '\0'; son innecesarias (e inseguro — strlen() no va a funcionar correctamente si el ISN cadena' t ya terminado en nul). fgets() anulará el búfer. Además, debe verificar que result != NULL antes de intentar copiar line. fgets() devuelve NULL al final del archivo o si se produce un error.

+1

+1 para verificar el valor de retorno de 'fgets'. – pmg

1

Sí, es exagerado.

Una sugerencia para que sea más robusto frente a la podredumbre de código ... cambiar

result = fgets(line, kMaxLineLength, stdin); 

a

result = fgets(line, sizeof(line), stdin);