Inacabado Posted July 15, 2018 at 02:10 PM Report #611323 Posted July 15, 2018 at 02:10 PM Andei á martelada para fazer este programa do Livro C Programming Language, mais tempo do que o que eu expectava. Problema: escreve um programa que faça o print de uma palavra por linha. condições: Não usar arrays e trabalhar apenas com: condições (if, else, else if); ciclos(for ou while); operadores(||,&&,!=,==)... enfim toda a matéria que se tem dada até aquela secção do primeiro capitulo do livro do conhecidissímo livro do Dennis Ritchie e Brian Kerningham. #include <stdio.h> #define IN 1 /*inside a word*/ #define OUT 0 /*outside a word*/ /*Write a program that prints its input one word per line*/ int main(void) { int c,state; state=OUT; while((c=getchar())!=EOF) { if(c!=' ' && c!='\t' && c!='\n') { state=IN; putchar(c); } else if(state==IN) { state=OUT; putchar('\n'); } } return 0; } Porreiro o código corre bem, mas e para lá chegar!?! Andei á porra e á massa com aquele primeiro if: if(c!=' ' && c!='\t' && c!='\n') ...porque eu estava naquela de utilizar o operador || em vez do && que fez finalmente o programa correr bem! Mas sinceramente, e esta é a razão deste post ainda não percebi a razão de o operador || em if(c!=' ' || c!='\t' || c!='\n') dar um comportamento inesperado! Alguém me pode dizer o que diferencia estes dois operadores para este caso especifico? Ou seja se estamos a analisar caracter a caracter em c com o getchar() qual é a diferença? Obrigado desde já e um agradecimento especial ao HHH que tanta ajuda tem dado, muitas vezes (eu incluído) sem o pessoal merecer...
PsySc0rpi0n Posted July 15, 2018 at 04:35 PM Report #611324 Posted July 15, 2018 at 04:35 PM (edited) Não sei se ajuda mas se fizeres o seguinte exercício: 2 == 3 || 3 == 2 consegues perceber qual o resultado? Ou seja, por extenso é algo como: 2 é igual a 3 OU 3 é igual a 2 ??? Ambas as afirmações são falsas, logo o resultado é falso, portanto o 'if' não é executado Agora: 2 == 3 || 3 == 3 Consegues perceber qual é o resultado? Ou seja, por extenso, é algo como: 2 é igual a 3 OU 3 é igual a 3? Bom aqui a da esquerda é falsa e a da direita é verdadeira. Se souveres o operador OU, sabes que desde que uma das verificações seja verdadeira, o resultado final é verdadeiro, logo o 'if' é executado! No caso específico é igual, ou seja, desde que apenas uma seja verdadeira, o 'if' será executado. Contrariamente, se usares o operador '&&', o 'if' só será executado, se e só se a totalidade das condições comparadas for verdadeira. Basta uma ser falsa para o resultado final ser falso. Outro exemplo que podes tomar é o equivalente mas com operadores binários: se considerarmos o '0' como falso, e o '1' como verdadeiro, temos: AND 0 0 --> 0 0 1 --> 0 1 0 --> 0 1 1 --> 1 Como vez, o resultado final só é 1, quando ambas as variáveis são verdadeiras. No OR 0 0 --> 0 0 1 -->1 1 0 --> 1 1 1 --> 1 Ou seja, basta apenas uma delas ser verdadeira para o resultado final ser verdadeiro. No caso do 'if' que apresentas, se eu o "disser" por extenso, era algo do género: Só salta (falha) o 'if' caso a variável 'c' não seja nenhum daqueles 3 caractéres. Fora isso, o 'if' é sempre executado Ajudei ou compliquei? Edited July 15, 2018 at 04:37 PM by PsySc0rpi0n 1 Report Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
Inacabado Posted July 15, 2018 at 05:43 PM Author Report #611325 Posted July 15, 2018 at 05:43 PM 29 minutos atrás, PsySc0rpi0n disse: No caso específico é igual, ou seja, desde que apenas uma seja verdadeira, o 'if' será executado. Contrariamente, se usares o operador '&&', o 'if' só será executado, se e só se a totalidade das condições comparadas for verdadeira. Basta uma ser falsa para o resultado final ser falso. Eu conheço genericamente as regras que apresentastes, o que não quer dizer que a tua explicação não seja em certa medida necessária, a qual agradeço: obrigado. No entanto neste caso vamos ver: no programa se entrares com uma stream de caracteres pelo teclado, por exemplo: abc[ ]abc[ ] [enter](abc, espaço,abc,espaço,enter), temos os seguintes comportamentos: para o programa com o : if(c!=' ' && c!='\t' && c!='\n') output: abc abc Porreiro... Já para o programa com os OU "||" para o mesmo input abc[ ]abc[ ]: if(c!=' ' || c!='\t' || c!='\n') temos o output: abc abc ... que não é o que se pretende! Quando passo a stream ao : while((c=getchar())!=EOF) cada caracter é processado 1 a 1 certo? Então qual a diferença entre usar && ou || se estou a "analisar" dentro do ciclo caracter a caracter e não um conjunto de caracteres? É esta a minha dúvida! Mas reconheço que pode haver aqui algo que eu não esteja teimosamente a ver, por isso o meu pedido de ajuda.
Inacabado Posted July 15, 2018 at 06:38 PM Author Report #611326 Posted July 15, 2018 at 06:38 PM Boas acho que já percebi e tem a ver com a explicação dada pelo PsySc0rpi0n que de tão óbvia que era eu menosprezei confesso. Eu não quero que apareçam espaços em branco, o objectivo aqui seria converte-los em '\n'. Isto para o objectivo superiror de apresentar uma palavra em cada linha. Com uma palavra a querer dizer um ou mais caracteres... Tenho mesmo que usar o operador condicional && e não ||. Naquele exemplo do abc[ ]abc[ ], eu não compreendia porque é que o espaço [ ] não era convertido em '\n' (no bloco else if) quando estava lá expresso no if, que só poderia imprimir qualquer caracter que não fosse '\n','\t' ou ' '. Ora ao chegar ao espaço ' ', o caracter é diferente de '\t' e de '\n', o que é o bastante para a condição ser verdadeira e por isso imprimir o espaço! Ás vezes desmereço estes pormenores que são o suficiente, por não serem assimilados de me empancar mais tempo do que aquele que previa. Obrigado PsySc0rpi0n!
PsySc0rpi0n Posted July 15, 2018 at 08:07 PM Report #611327 Posted July 15, 2018 at 08:07 PM Se eu percebi bem o que disseste no post anterior, acho que falaste em "converter". Mas o 'if' não está a converter espaços em caractéres de mudança de linha. Está apenas a verificar se o caractér presente na variável 'c' naquele momento é diferente de um espaço ' ', de uma tabulação '\t' ou de um caractér de mudança de linha '\n'. Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
Inacabado Posted July 15, 2018 at 09:02 PM Author Report #611329 Posted July 15, 2018 at 09:02 PM 47 minutos atrás, PsySc0rpi0n disse: Se eu percebi bem o que disseste no post anterior, acho que falaste em "converter". Mas o 'if' não está a converter espaços em caractéres de mudança de linha. Está apenas a verificar se o caractér presente na variável 'c' naquele momento é diferente de um espaço ' ', de uma tabulação '\t' ou de um caractér de mudança de linha '\n'. Não está directamente, mas obriga a entrar no próximo else if que vai fazer isso. Isto tem a ver com o facto de eu ter feito outra versão deste programa, esta: #include <stdio.h> /*write a program that prints its input one word per line*/ int main(void) { int c,spacePrev,charPrev; c=spacePrev=charPrev=0; while((c=getchar())!=EOF) { if(c==' '||c=='\t'||c=='\n'&&charPrev==0) ; if(spacePrev==0) { if(c==' '||c=='\t'&&charPrev==1) { c='\n'; spacePrev=1; putchar(c); } else { putchar(c); charPrev=1; } } else if(c==' '||c=='\t'&&spacePrev==1) ; else { putchar(c); spacePrev=0; } } return 0; } /* NOTA: Não estou nada orgulhoso deste programa, é código a mais para o problema que é.*/ ...que fazia isso mais directamente. No entanto um dos objectivos principáis era sempre esse. Peço desculpa pela imprecisão!
PsySc0rpi0n Posted July 15, 2018 at 09:09 PM Report #611330 Posted July 15, 2018 at 09:09 PM (edited) Qual é a versão do livro e qual é a página? Ou qual o número do exercício? Bom, assim sem ver o contexto do problema no livro, deixo aqui uma possível solução já que é mais ou menos como a que tens mas sem o else if e sem a variável state nem os defines. Não testei o teu código nem sei se faz o mesmo que o meu mas até acho que sim, pelo que não percebo bem qual a necessidade de teres usado a tal variável state e os defines. #include <stdio.h> int main(void){ char c; while((c = getchar()) != EOF){ if(c != ' ' && c != '\t' && c != '\n') putchar(c); else putchar('\n'); } return 0; } Edited July 15, 2018 at 09:43 PM by PsySc0rpi0n Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
Inacabado Posted July 15, 2018 at 10:42 PM Author Report #611333 Posted July 15, 2018 at 10:42 PM (edited) 1 hora atrás, PsySc0rpi0n disse: Qual é a versão do livro e qual é a página? Ou qual o número do exercício? Bom, assim sem ver o contexto do problema no livro, deixo aqui uma possível solução já que é mais ou menos como a que tens mas sem o else if e sem a variável state nem os defines. Não testei o teu código nem sei se faz o mesmo que o meu mas até acho que sim, pelo que não percebo bem qual a necessidade de teres usado a tal variável state e os defines. #include <stdio.h> int main(void){ char c; while((c = getchar()) != EOF){ if(c != ' ' && c != '\t' && c != '\n') putchar(c); else putchar('\n'); } return 0; } Essa solução não é estrita ao problema em questão. Entra com espaços primeiro e o que tens? O problema diz: uma palavra por linha! Se entras com espaços em primeiro, ficas com várias linhas relativas aos espaços entrados. Essas linhas têm que ser "comidas", não processadas, para que seja estritamente como diz o problema: "one word per line". E como é que fazes para não processar esses espaços? Por isso é que eu tive um trabalho dos diabos para chegar á solução, por isso é que foram precisas mais variáveis! Sem falsa modestia, ou falsa-humildade... Edited July 15, 2018 at 10:45 PM by Inacabado
Inacabado Posted July 15, 2018 at 10:51 PM Author Report #611334 Posted July 15, 2018 at 10:51 PM (edited) Ou seja, se for entrado um espaço antes de qualquer caracter, esse espaço tem que ser "comido"(é uma expressão minha!), não colocado qualquer '\n'. Se o espaço entrar mas imediatamente a seguir a um caracter, ai sim pode ser substituído por um '\n'!Esta é outra: se forem entrados vários espaços, uns a seguir aos outros, depois de uma stream de caracteres, tem que se descartar os espaços extra e só substituir o primeiro por '\n'. Isto tudo para o "one word per line", não "word"+espaços "per line" ou espaços per line e algumas words per line a seguir ou antes... A mim deu-me luta, este programa! Edited July 15, 2018 at 10:53 PM by Inacabado
HappyHippyHippo Posted July 16, 2018 at 09:58 AM Report #611339 Posted July 16, 2018 at 09:58 AM isto é um problema simples que está relacionado com uma coisa chamada FSM (Finite-State-Machine). Explicar o que são ou como funcinonam, deixo para o Google explicar senão não saia daqui hoje. No entanto, vou explicar este problema. Tu tens 3 estados, e vou dar o número 0, 1, 2 a cada uma destes estados: - 0 : Início - 1 : A ler espaços - 2 : A ler uma palavra Quando a máquina de estados é inicializada, é "setada" a zero (estado inicial). Neste estado, o processo de leitura de um caracter, pode levar para um dos outros dois estados : 1 ou 2 (ler espaços ou ler uma palavra). Após o passo inicial, podes estar acontecer estar no estado 1 (a ler espaços) onde ficarás sempre que lês um espaço, passando para o estado 2 (a ler uma palavra) no momento que lês um caracter. Se estiveres no estado 2 (a ler uma palavra), ficas sempre nesse estado até que lês um caracter que não é alpha-numérico. gráficamente seria algo deste género: +----------+ +----------+ | estado 0 |--(leu um espaço)--->| estado 1 |<--------------------+ +----------+ +----------+ --(leu um espaço)--+ | | A | | | | (leu um caracter) (leu um espaço) | | | | V | | +----------+ +-------(leu um caracter)->| estado 2 |<--------------------+ +----------+ -(leu um caracter)-+ A única coisa que não está especificada neste gráfico é a necessidade de fazer o output de nova linha quando mudas do estado 2 (ler palavra) para o estado 1 (ler caracter)conclusão, o código seria algo este género (coded on-the-fly): #include <stdio.h> #include <ctype.h> #define STATE_START 0 #define STATE_SPACE 1 #define STATE_WORD 2 int main(void) { int c, state = STATE_START; while((c = getchar()) != EOF) { switch (state) { case STATE_START: case STATE_SPACE: state = isalpha(c) ? STATE_WORD : STATE_SPACE; break; case STATE_WORD: state = isalpha(c) ? putchar(c), STATE_WORD : putchar('\n'), STATE_SPACE; break; } } return 0; } ps : no final nem foi preciso os && ou os ||, mas se queres perceber como isso funciona na realidade, é só dizer 1 Report IRC : sim, é algo que ainda existe >> #p@p Portugol Plus
Inacabado Posted July 16, 2018 at 05:32 PM Author Report #611351 Posted July 16, 2018 at 05:32 PM Certo, agora tente ler este pdf até ao capitulo 1.6(exclusive), e tente de novo fazer "on the fly", só com a matéria dada até essa altura! Acredito que consegue... Obrigado pela ilustração dos estados, não conhecia!
PsySc0rpi0n Posted July 16, 2018 at 06:01 PM Report #611352 Posted July 16, 2018 at 06:01 PM Ah ok. Mas se no teu caso funciona a versão que fizeste, então está bom! 🙂 Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
Inacabado Posted July 22, 2018 at 11:47 AM Author Report #611408 Posted July 22, 2018 at 11:47 AM (edited) Desculpem lá ser picuinhas, confesso que sou um pouco teimoso as vezes, seja bom ou seja mau... Estive a trabalhar naquela minha primeira versão do problema a que usa as variáveis charPrev e spacePrev, e aprimorei o código de maneira a ficar mais perto da perfeição: #include <stdio.h> /*write a program that prints its input one word per line*/ int main(void) { int c,charPrev; c=charPrev=0; while((c=getchar())!=EOF) { if(charPrev==0) { if(c!=' '&&c!='\t'&&c!='\n') { putchar(c); charPrev=1; } } else { if(c!=' '&&c!='\t'&&c!='\n') putchar(c); else { putchar('\n'); charPrev=0; } } } return 0; } ...muito menos linhas de código, menos variáveis, muito mais económico que a primeira versão, desta versão! Tenho agora duas versões para o mesmo problema: "write a program that prints its input one word per line". Abraço a todos Edited July 22, 2018 at 11:50 AM by Inacabado
HappyHippyHippo Posted July 23, 2018 at 01:35 PM Report #611420 Posted July 23, 2018 at 01:35 PM estou triste ... qual o problema da minha solução ? #include <stdio.h> #include <ctype.h> #define STATE_START 0 #define STATE_SPACE 1 #define STATE_WORD 2 int main(void) { int c, state = STATE_START; while((c = getchar()) != EOF) { switch (state) { case STATE_START: case STATE_SPACE: state = isalpha(c) ? (putchar(c), STATE_WORD) : STATE_SPACE; break; case STATE_WORD: state = isalpha(c) ? (putchar(c), STATE_WORD) : (putchar('\n'), STATE_SPACE); break; } } return 0; } IRC : sim, é algo que ainda existe >> #p@p Portugol Plus
Inacabado Posted July 23, 2018 at 06:29 PM Author Report #611423 Posted July 23, 2018 at 06:29 PM 4 horas atrás, HappyHippyHippo disse: estou triste ... qual o problema da minha solução ? vc está a ser sarcástico...hum? O que eu quis dizer foi, a ser rigoroso, não poderemos usar os elementos de programação que ainda não foram dados no primeiro capitulo deste livro! Por exemplo o switch não foi dado até aquele capitulo (capitulo 1), nem o operador ternário... Obviamente que fora disso a sua solução é no mínimo bastante elegante. Além do mais, para o seu nível de conhecimento, não estou apto a fazer-lhe reparos, obviamente... Abraço
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now