Pregunta

Estoy escribiendo un programa que se supone que lee dos cadenas que pueden contener saltos de línea y otros caracteres. Por lo tanto, estoy usando EOF (Ctrl-Z o Ctrl-D) para finalizar la cadena.

Esto funciona bien con la primera variable, pero con la segunda variable, sin embargo, esto parece ser problemático ya que aparentemente algo está atascado en el búfer de entrada y el usuario no puede escribir nada.

Traté de limpiar el búfer con while (getchar ()! = '\ n'); y varias variaciones similares, pero nada parece ayudar. Todos los intentos de limpieza han resultado en un bucle infinito, y sin limpieza, es imposible agregar la segunda variable.

Los caracteres para ambas variables se leen en un bucle como este: while ((c = getchar ())! = EOF) , lo que sugeriría que es EOF en lo que me he quedado atrapado mi búfer ¿O afecta el comportamiento del programa de alguna otra manera? ¿Hay algo mal con la lógica que estoy usando?

Estoy empezando a desesperarme un poco después de luchar con esto durante horas.

[edit: código agregado a continuación]

[edit 2: clearerr () parece hacer que esta solución EOF funcione después de todo.

Parece ejecutarse en su forma original como pretendía en Linux, ayer lo estaba intentando con Windows.]

código:

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

int main(void)
{
    int x = 0;
    int c;
    char a[100];
    char b[100];

    printf("Enter a: ");
    while((c = getchar()) != EOF)
    {
        a[x] = c;
        x++;
    }
    a[x] = '\0';
    x = 0;

    /*while (getchar() != '\n'); - the non-working loop*/

    printf("\nEnter b: ");
    while((c = getchar()) != EOF)
    {
        b[x] = c;
        x++;
    }
    b[x] = '\0';

    printf("\n\nResults:\na: %s\n", a);
    printf("b: %s\n", b);

    return(0);
}

[edit 3:]

Problema de memoria dinámica:

También se supone que mi programa maneja cadenas de más de 100 caracteres. Originalmente tenía la intención de resolver eso mediante la asignación dinámica de memoria, pero cuando tuve problemas con el bucle infinito descrito anteriormente y los bloqueos relacionados con la memoria, lo dejé fuera y cambié a char [100].

Creo que lo que probé fue en general algo como esto:

while((c = getchar()) != EOF)
{
  a = malloc(sizeof(char));
  a[x] = c;
  x++;
}

¿Es esa una forma posible (o sensata) de hacer eso? Estoy tratando de asignar más memoria para cada personaje que se maneja allí. Individualmente. Con un código como ese (este ejemplo contiene probablemente errores de sintaxis) Experimenté bloqueos, por lo que me parece que malloc podría no ser la función correcta aquí, o lo estoy intentando mal. Supongamos que incluso es posible.

¿Fue útil?

Solución

Después de recibir un EOF del terminal, no recibirá ningún dato adicional . No hay forma de deshacer la entrada: el final del archivo es, bueno, el final.

Por lo tanto, debe definir que cada variable se ingrese en una línea separada y que los usuarios presionen Intro en lugar de EOF. Aún debe verificar si ha recibido eof, porque eso significa que el usuario realmente escribió EOF y no verá nada más; en este caso, debe salir del bucle e imprimir un mensaje de error.

Otros consejos

EOF no es un carácter : es un valor especial que las funciones de entrada devuelven para indicar una condición , que el " finaliza de archivo " en ese flujo de entrada se ha alcanzado. Como Martin v. L & # 246; wis dice, una vez que "fin de archivo" se produce la condición, significa que no habrá más entradas disponibles en esa secuencia.

La confusión surge porque:

  • Muchos tipos de terminales reconocen una pulsación de tecla especial para señalar "fin de archivo" cuando el " archivo " es un terminal interactivo (por ejemplo, Ctrl-Z o Ctrl-D); y
  • El valor EOF es uno de los valores que puede devolver la familia de funciones getchar () .

Deberá usar un valor de carácter real para separar las entradas; el carácter nulo ASCII '\ 0' podría ser una buena opción, si eso no puede aparecer como un valor válido dentro del entradas ellos mismos.

Ejecuto el código en mi caja de Linux, aquí está el resultado:

Enter a: qwer
asdf<Ctrl-D><Ctrl-D>
Enter b: 123
456<Ctrl-D><Ctrl-D>

Results:
a: qwer
asdf
b: 123
456

Se necesitaban dos Ctrl-D porque el búfer de entrada del terminal no estaba vacío.

Puede usar el carácter nulo ( '\ 0' ) para separar las variables. Varias herramientas de UNIX (por ejemplo, find ) son capaces de separar sus elementos de salida de esta manera, lo que sugeriría que es un método bastante estándar.

Otra ventaja de esto es que puede leer la secuencia en un único búfer y luego crear una matriz de char * s para apuntar a las cadenas individuales, y cada cadena será correctamente '\ 0' -terminado sin que tenga que cambiar nada en el búfer manualmente. Esto significa menos sobrecarga de asignación de memoria, lo que puede hacer que su programa se ejecute notablemente más rápido dependiendo de cuántas variables esté leyendo. Por supuesto, esto solo es necesario si necesita mantener todas las variables en la memoria al mismo tiempo & # 8212; si está lidiando con ellos uno a la vez, no obtiene esta ventaja particular.

Lo que estás intentando es fundamentalmente imposible con EOF.

Aunque se comporta como tal de alguna manera, EOF no es un personaje en la secuencia sino una macro definida por el entorno que representa el final de la secuencia. No he visto tu código, pero supongo que lo que estás haciendo es algo como esto:

while ((c=getchar()) != EOF) {
    // do something
}
while ((c=getchar()) != EOF) {
    // do something else
}

Cuando escribe el carácter EOF la primera vez, para finalizar la primera cadena, la secuencia se cierra irrevocablemente. Es decir, el estado de la transmisión es que está cerrada.

Por lo tanto, el contenido del segundo ciclo while nunca se ejecuta.

En lugar de dejar de leer la entrada en EOF - que no es un carácter - deténgase en ENTER.

while((c = getchar()) != '\n')
{
    if (c == EOF) /* oops, something wrong, input terminated too soon! */;
    a[x] = c;
    x++;
}

EOF es una señal de que la entrada terminó. ¡Está casi garantizado que todas las entradas del usuario terminan con '\ n': esa es la última clave que escribe el usuario!


Editar: aún puede usar Ctrl-D y clearerr () para restablecer la secuencia de entrada.

#include <stdio.h>

int main(void) {
  char a[100], b[100];
  int c, k;

  printf("Enter a: "); fflush(stdout);
  k = 0;
  while ((k < 100) && ((c = getchar()) != EOF)) {
    a[k++] = c;
  }
  a[k] = 0;

  clearerr(stdin);

  printf("Enter b: "); fflush(stdout);
  k = 0;
  while ((k < 100) && ((c = getchar()) != EOF)) {
    b[k++] = c;
  }
  b[k] = 0;

  printf("a is [%s]; b is [%s]\n", a, b);
  return 0;
}
$ ./a.out
Enter a: two
lines (Ctrl+D right after the next ENTER)
Enter b: three
lines
now (ENTER + Ctrl+D)
a is [two
lines (Ctrl+D right after the next ENTER)
]; b is [three
lines
now (ENTER + Ctrl+D)
]
$
  

¿Cómo se ingresa nulo en el programa?

Puede implementar la función -print0 usando:

putchar(0);

Esto imprimirá un carácter nulo ASCII '\ 0' en sdtout.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top