the ritchie programming programación programacion practica lenguaje language kernighan español dennis brian book c kernighan-and-ritchie

ritchie - Ejercicio 1-9 de K & R: muestra la entrada, reemplazando múltiples espacios en blanco por un solo espacio en blanco



the c programming language amazon (11)

He estado trabajando en algunos libros sobre C tratando de obtener mis piernas C (¡piernas marinas! ¡¡Consíguelo !!). Acabo de terminar el ejercicio 1-9 del libro de K & R, que para referencia es "escribir un programa para copiar su entrada a su salida, reemplazando cada cadena de uno o más espacios en blanco por un solo espacio en blanco". Tengo una pregunta sobre qué está pasando con mi código, aunque--

#include <stdio.h> //Copy input to output. Replace each string of multiple spaces with one single space int main(int argc, char *argv[]){ int ch, lch; // Variables to hold the current and last characters, respectively /* This loop should ''put'' the current char, then store the current char in lc, * loop back, ''get'' a new char and check if current and previous chars are both spaces. * If both are spaces, do nothing. Otherwise, ''put'' the current char */ for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){ if(ch == '' '' && lch == '' '') ; else putchar(ch); } return 0; }

Esto funciona principalmente, a excepción de la entrada del primer carácter. Por ejemplo, si la entrada de la primera línea es

"This is a test"

mi código de salida

"his is a test".

Después de dejar caer la primera entrada de caracteres, el programa funciona consistentemente para cumplir con las demandas del ejercicio.

¿Alguien puede darme una idea del error que cometí en mi ciclo que está causando el problema? Cualquier otro consejo es bienvenido también.


A menos que la tarea sea hacerlo con un bucle for, es mejor aprender el idioma si intenta obtener un código más limpio. Solo dígase a sí mismo lo que hace el código, compare, por ejemplo, el while-loop equivalente con el for-loop:

//initialize lch to prevent undefined behaviour //if the first character is a space, it will be printed lch = ''A''; // as long as you can read characters while((ch = getchar()) != EOF) { // if either the current character or the previous one is not a space if(ch!='' '' || lch!='' '') { //print it putchar(ch); } // remember the current for the next round lch = ch; }

Una vez que comprenda el constructo while, también puede convertirlo en el hacky for-loop, pero ¿por qué lo haría? El tiempo es más fácil de leer y al compilador no le importa porque compilará de la misma manera. (probablemente)


Aunque hay muchas respuestas correctas, déjame darte una pista de cómo podrías haberlo rastreado usando un depurador (gdb aquí):

Primero cambie el código para que se vea así (¡una afirmación por línea solamente!):

... for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){ ...

Ahora compílelo usando símbolos ( -g para gcc), luego ejecute el código usando un depurador:

gdb ./a.out

Pon un punto de ruptura en main() :

(gdb) break main

Comience el programa:

(gdb) run

Verlo parando en main() :

Breakpoint 1, main (argc=1, argv=0x7fffffffe448) at main.c:15 15 for(ch = getchar(); (gdb)

Paso a paso por el código:

(gdb) step

Use print ch desde la línea de comando gbd para inspeccionar las variables interesantes ( ch aquí) en varias etapas del código "en ejecución", mientras lo recorre.

Más detalles sobre cómo dirigir gbd aquí: http://beej.us/guide/bggdb/


Cambiar este ciclo

for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){ if(ch == '' '' && lch == '' '') ; else putchar(ch); }

de la siguiente manera

for( lch = EOF; ( ch = getchar() ) != EOF; lch = ch ) { if ( ch != '' '' || lch != '' '' ) putchar( ch ); }

De lo contrario, al comienzo del ciclo, lee un personaje dos veces.

También en mi opinión, la tarea describe otra tarea

"escriba un programa para copiar su entrada a su salida, reemplazando cada cadena de uno o más espacios en blanco por un solo espacio en blanco".

Debe reemplazar cada línea entera de espacios en blanco con un solo espacio en blanco. :) El ciclo que se muestra arriba no hace esta tarea.


El problema es que la primera iteración de su bucle llama a getchar dos veces: una al inicializar la variable ch y otra vez al verificar ch contra EOF .

Dejar caer ch = getchar() solucionará este problema:

for( lch = ''?'' ; (ch = getchar()) != EOF; lch = ch) { ... }

Tenga en cuenta que necesita lch con cualquier valor que no sea espacio.


En la declaración for-loop, estás teniendo el error.

for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){...}

Aquí, está almacenando el primer carácter en ch, y luego nuevamente probando si (ch! = EOF) leyendo nuevamente la entrada de caracteres.

Elimine ch=getchar() de la declaración de inicialización; déjalo estar en la segunda parte.

for(;(ch = getchar()) != EOF; lch = ch){...}

Además, deberá inicializar su lch antes de ejecutarlo ya que lch no tendrá ningún valor almacenado antes de hacer una comparación en la primera iteración del ciclo. Por lo tanto, supongamos que lch=0 se inicializa primero.

for(lch = 0; (ch = getchar()) != EOF; lch = ch){...}

Considere habilitar advertencias en su compilador, probablemente detectaría y advertiría sobre este problema, por lo que podría solucionarlo.

Lo anterior resolvería tu problema.

(Gracias a Blue Moon e Hyde por ayudarme a modificar la respuesta).


Está llamando a getchar() una vez antes de que comience el ciclo, luego una vez por iteración en la condición de. El primer personaje que recuperas queda descartado.

También debe inicializar lch antes de lch , antes de compararlo. Según lo que quieras hacer cuando el primer carácter de tu cadena sea un espacio:

  • Al establecerlo en '' '' se recortará el espacio libre al "pre-emparejarlo".
  • Establecerlo en cualquier otra cosa tratará el espacio delantero normalmente.

Su encabezado de bucle se convierte (en el segundo caso):

for(lch = ''a'' /*arbitrary*/; (ch = getchar()) != EOF; lch = ch)

Gracias a shekar suman por el mano a mano sobre el lch no lch .


Esto funcionó para mí

#include <stdio.h> int main(int arg, char *argv[]){ char c = 0; long blank = 0; long tab = 0; while((c=getchar())!= EOF){ if(c == '' ''){ ++blank; } if(c != '' ''){ if(blank>1){ printf("%c", '' ''); blank = 0; printf("%c", c); } else{ printf("%c", c); } } } //end of while return 0; }


Hay tres partes en una declaración for : inicialización, condición e incremento. Estas partes están separadas por los dos puntos y comas.

Es muy confuso cuando la condición de parte de una declaración tiene efectos secundarios. Los efectos secundarios pertenecen a la parte de incremento:

for (ch = getchar(); ch != EOF; lch = ch, ch = getchar())

Y, como otros han indicado, lch tiene que ser inicializado, entonces:

int lch = ''a'';

Y, finalmente, aunque esto no afecta la corrección del programa, invertiría la prueba if :

if (ch != '' '' || lch != '' '') putchar(ch);


Hubo un cambio menor de @elessar. La línea 12 tuvo que cambiarse de (en blanco> 1) a (en blanco> = 1) porque la anterior no imprimirá espacios en blanco.

#include <stdio.h> int main(int arg, char *argv[]){ char c = 0; long blank = 0; long tab = 0; while((c=getchar())!= EOF){ if(c == '' ''){ ++blank; } if(c != '' ''){ if(blank>=1){ printf("%c", '' ''); blank = 0; printf("%c", c); } else{ printf("%c", c); } } } //end of while return 0; }


Llamarás a getchar dos veces en la inicialización del bucle:

for(ch = getchar(); (ch = getchar()) != EOF; lch = ch)

En su lugar, debe llamarlo una vez en la inicialización (para obtener una primera char) y luego al final de la iteración (para obtener los siguientes caracteres):

int ch, lch = 0; // avoid using uninitialized variable for(ch = getchar(); ch != EOF; lch = ch) { if(ch == '' '' && lch == '' '') ; else putchar(ch); ch = getchar(); }

UPD: Gracias Blue Moon y shekhar suman por señalar el problema con lch


Sí, lo que está sucediendo es que cuando declaras tu declaración, primero inicializas el ch con

for( ch= getchar();

Entonces, en este momento, obtienes tu primer carácter (T) y el puntero avanza una posición hasta el siguiente carácter (h)

luego obtienes nuevamente el char con (ch = getchar()) !=EOF;

intente cambiar for (ch= getchar(); y use for (ch= '''' ; lugar.

Espero que lo arregle.