Estoy trabajando en los ejercicios del primer capítulo de El lenguaje de programación C y, aunque entiendo la mayor parte de lo que se dice y se muestra, hay un ejemplo que no entiendo.
En 1.9, se muestra una función para devolver la longitud de una línea mientras se establece una matriz de caracteres, pasada como argumento, al contenido.
int get_line(char s[], int lim) { int c, i, l; for (i = 0, l = 0; (c = getchar()) != EOF && c != '\n'; ++i) { if (i < lim - 1) s[l++] = c; } if (c == '\n') if (l < lim - 1) s[l++] = c; s[l] = '\0'; return l; } Lo que no entiendo es por qué necesitamos esto: if (c == '\n') {...} . ¿No se podría combinar esto en el ciclo for? ¿Dónde verificamos explícitamente que c no es igual a '\n' ? Tengo problemas para comprender por qué esto debe ser una condición externa.
¡Cualquier arrojar luz sería útil! ¡Gracias!
Se sale del ciclo for si c es igual a EOF o c es igual a '\n' . Por lo tanto, inmediatamente después del ciclo for , si desea saber qué valor tiene c , debe probar.
es por eso que necesitamos esto:
if (c == '\n') {...}.
get_line() es estructuralmente:
get_line() { initialize while get, A not true and B not true perform X if B perform X finalize El ciclo se cierra bajo 2 condiciones. Con uno de esos ( c == '\n' ), todavía queremos realizar X en algún lugar , ya que es parte del objetivo de la función.
¿No se podría combinar esto en el ciclo for?
Podría combinarse, pero luego tenemos 2 ubicaciones que salen del ciclo.
Las pautas de codificación típicas promueven una sola ubicación para salir del bucle. Si dejamos de lado ese objetivo, entonces:
get_line() { initialize while get, A not true perform X if B quit the loop finalizeComo se muestra a continuación, con el mismo número de comprobaciones de condiciones, pero con 2 puntos de salida de bucle.
int get_line(char s[], int lim) { int c, i, l; for (i = 0, l = 0; (c = getchar()) != EOF; ++i) { if (i < lim - 1) s[l++] = c; if (c == '\n') break; } s[l] = '\0'; return l; } Podríamos torcer el código para obtener los 2 controles en la misma línea y no tener ese molesto después del ciclo if (c == '\n') . Estilísticamente esto puede ser más difícil de seguir.
int get_line(char s[], int lim) { int c, i, l; for (i = 0, l = 0, c = 0; c != '\n' && (c = getchar()) != EOF; ++i) { if (i < lim - 1) s[l++] = c; } s[l] = '\0'; return l; }Por último, el código podría usar mejoras:
No hay necesidad de contadores de índice i y l . Uno es suficiente.
El tamaño de matriz y el índice utilizan mejor el tipo size_t . Advertencia: size_t es un tipo sin firmar .
El uso de un parámetro de tamaño inicial permite un mejor análisis de código estático y código de autodocumentación: el lim se relaciona con s[] .
Evite las matemáticas en los parámetros de entrada para no incurrir en desbordamiento. Tenemos más control de rango en objetos locales.
Cuidado cuando lim está en un extremo o cero.
En lugar de asignar después de la declaración, cuando sea práctico, inicialice. Por ejemplo int i = 0;
get_line() { initialize while B not true, get, A not true perform X finalizeo
#include <stdio.h> #include <stdlib.h> size_t get_line(size_t size, char s[size]) { int ch = 0; size_t i = 0; while (ch != '\n' && (ch = getchar()) != EOF) { if (i + 1 < size) s[i++] = (char) ch; } // size might have been pathologically 0, so no room for \0 if (i < size) { s[i] = '\0'; } return i; }Si quieres ponerlo en el bucle, tienes que hacer algo así:
int get_line(char s[], int lim) { int c, i, l; for (i = 0, l = 0; (c = getchar()) != EOF; ++i) { if ((i < lim - 1) && (c != '\n')) s[l++] = c; else if (c == '\n') { if (l < lim - 1) s[l++] = c; break; } } s[l] = '\0'; return l; } Entonces, como puede ver, envolver la condición dentro del ciclo, llevó a más controles de condiciones y una declaración de break .