Dúvida com código simples [RESOLVIDO]

1. Dúvida com código simples [RESOLVIDO]

douglas
dsbonafe

(usa Fedora)

Enviado em 02/09/2014 - 13:45h

Senhores, criei um código que realiza a leitura de um conjunto de nomes de pessoas e os armazena numa matriz denominada Nome[][], utilizando ponteiros. A intenção é apresentar uma utilidade dos ponteiros de forma evidente como apontador. A leitura é finalizada quando a palavra "fim" é digitada.
Entretanto, ao compilar com o gcc e executar no prompt do Windows, ele entra num loop maluco.

Segue o código.
Desde já, grato.


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

int main(int argc, char** argv){
char Nome[100][30], *Pnome;
Pnome = &Nome[0][0];
printf("\n Digite um nome. Para finalizar digite fim: \t");
scanf("%[^\n]", Pnome);
while(strcmp(strlwr(Pnome), "fim") != 0){
printf("\n Digite o proximo nome. Para finalizar, fim:\t");
scanf("%[^\n]", Pnome);
}
printf("\n *** Dados Lidos: ");
Pnome = &Nome[0][0];
while(strcmp(strlwr(Pnome), "fim") !=0){
printf("\n\t%s", Pnome);
Pnome+=30;
}
printf("\n\n Fim do programa!");
return 0;
}



  


2. Solução

douglas
dsbonafe

(usa Fedora)

Enviado em 02/09/2014 - 17:01h

Não existe mais essa entrada no scanf. Isso é antigo.


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

int main(int argc, char** argv){
char Nome[100][30], *Pnome;
Pnome = &Nome[0][0];
printf("\n Digite um nome. Para finalizar digite fim: \t");
scanf("%s", Pnome);
while(strcmp(strlwr(Pnome), "fim") != 0){
printf("\n Digite o proximo nome. Para finalizar, fim:\t");
scanf("%s", Pnome);
}
printf("\n *** Dados Lidos: ");
Pnome = &Nome[0][0];
while(strcmp(strlwr(Pnome), "fim") !=0){
printf("\n\t%s", Pnome);
Pnome+=30;
}
printf("\n\n Fim do programa!");
return 0;
}



3. Re: Dúvida com código simples [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 02/09/2014 - 18:24h

dsbonafe escreveu:

Não existe mais essa entrada no scanf. Isso é antigo.


Errado. O formatador “%[...]” em scanf() existe, sim, e é extremamente útil. Se você trocar por “%s”, não vai conseguir ler nomes com espaços.

O problema é que, do jeito como você estava fazendo antes, você não consumia o '\n' no final da linha, e como suas leituras só podiam consumir o que não fosse '\n', o programa realmente entrava em loop.

A forma correta (e completa, você pode não querer tratar todos os casos) de fazer seria o seguinte.

char *Pnome;
int tamanho, tamanho_com_nl;

/* ... */

/*
scanf() retorna no número de conversões bem sucedidas. No caso abaixo, só
há uma conversão ("%29[^\n]"), de modo que o valor de retorno tem de ser igual
a 1. Essa conversão tem o tamanho máximo limitado a 29 caracteres, de modo a
caber nos 30 bytes de cada nome, incluindo o byte nulo após os 29 caracteres
do nome (o byte nulo é gravado na 30ª posição se a string exceder 29 caracteres).

O primeiro "%n" serve para informar o número de caracteres consumidos do buffer
de entrada logo após a conversão da string. O "%*c" serve para consumir o pró-
ximo caráter, que supomos ser um '\n', mas sem o atribur a uma variável. O "%n"
seguinte é um outro medidor de caracteres consumidos, após o consumo do suposto
'\n'. Ele pode ser usado para identificar a falta do '\n', principalmente ao
final do fluxo de entrada.

Note que "%n" não é contado como conversão de entrada, mesmo com scanf() fazendo
atribuição de valores às variáveis apontadas pelos respectivos ponteiros.
*/
if(scanf("%29[^\n]%n%*c%n", Pnome, &tamanho, &tamanho_com_nl)==1){
/* Leitura OK. */
if(tamanho_com_nl>tamanho){
/* '\n' presente e consumido. */
}
else{
/* '\n' ausente. Possível final prematuro do arquivo. */
}
}
else {
/* Erro de leitura */
}



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

int main(int argc, char** argv){
char Nome[100][30], *Pnome;
Pnome = &Nome[0][0];
printf("\n Digite um nome. Para finalizar digite fim: \t");
scanf("%s", Pnome);
while(strcmp(strlwr(Pnome), "fim") != 0){
printf("\n Digite o proximo nome. Para finalizar, fim:\t");
scanf("%s", Pnome);
}
printf("\n *** Dados Lidos: ");
Pnome = &Nome[0][0];
while(strcmp(strlwr(Pnome), "fim") !=0){
printf("\n\t%s", Pnome);
Pnome+=30;
}
printf("\n\n Fim do programa!");
return 0;
}


O que não existe, pelo menos de acordo com os padrões ISO C e ISO C++, é strlwr(). Isso parece ser um Microsoftismo. E feio: seu digitar o nome "Paulo", essa função vai mudar a string lida para "paulo".

Posso estar muito cego, mas não estou vendo, no loop de leitura, alguma coisa para passar Pnome de um nome para o próximo (algo como o “Pnome+=30”, que existe no loop de impressão). Em todo caso, eu diria que é mais elegante e a prova de erros converter mesmo esse incremento para “Pnome+=sizeof Nome[0]”: desse modo, se você mudar a largura máxima do nome na hora de declarar Nome, não terá de localizar todas as ocorrências de 30 no programa, decidir quais delas se referem a nomes, e alterar as que identificar que o fazem.

Não esqueça de imprimir um '\n' depois da última mensagem do programa. Caso contrário, após o programa terminar, a última linha pode embolar com o prompt do shell ou alguma outra coisa que seja impressa no console por outro programa.