[Ajuda]Brincando com C [RESOLVIDO]

1. [Ajuda]Brincando com C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 24/03/2016 - 09:22h

Aee pessoal, primeiramente bom dia! :)
Bom, decidi começar a estudar C faz algum tempo, parei um tempo (esqueci algumas coisas), e agora estou com tempo para me dedicar 60%, porém estou meio atrapalhado aqui com comandos de controle de fluxo; especificamente o "if".
Escrevi um source simples para me familiarizar com C de novo, o "programa" recebe dados do usuário como nome e sobrenome, idade e data, recebe as strings e os inteiros com "scanf()" (uso strcat() para concatenar as strings) e por fim imprime nome e sobrenome com a variável nomecompleto, idade e data. Bom, muito simples...como eu disse, só para ir me familiarizando de novo.
Entretanto, quando uso o "if" para verificar os caracteres das strings nome e sobrenome , o programa não executa o bloco do "if" e continua a execução do resto do código normalmente, ignorando o if (não entendi). Segue o code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char nome[20],sobrenome[20];
int idade,data;

printf("Digite seu nome: ");
scanf("%[^\n]",&nome,&sobrenome);
char *nomecompleto = strcat(nome,sobrenome);
if(nome[0] == "\0" && sobrenome[0] == "\0"){
printf("\n\nERRO: Sem string no buffer");
exit(0);
}

printf("\nDigite sua idade e data de nascimento: ");
scanf("%d%d",&idade,&data);

if(idade <= 0 || idade >= 100 && data >= 2016 || data <= 1930){
printf("\n\nERRO: Dados invalidos");
exit(0);
}

else{
printf ("\nNome e sobrenome: %s",nomecompleto);
printf("\nIdade e data: %d, %d\n",idade,data);

}
return(0);
}

Desde já agradeço muito o intenção de ajudar com uma coisa tão simples, porém não achei nada que me ajudasse na internet, e as minhas tentativas de verificar as variáveis nome e sobrenome falharam, desculpa fazer alguém perder tempo com essa bobagem... mas não tem como aumentar o conhecimento sem questionar a praticar certo?


-------------------------------------------------------------------------------------------
Just bring us some beers, and then we can talk about our systems. :)



  


2. Re: [Ajuda]Brincando com C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 24/03/2016 - 10:20h

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

int main()
{

__fpurge(stdin);

char nome[20],sobrenome[20];
int idade,data;

printf("Digite seu nome: ");

scanf("%[^\n]",&nome);
__fpurge(stdin);

scanf("%[^\n]",&sobrenome);
__fpurge(stdin);

char *nomecompleto = strcat(nome,sobrenome);

if(nome[0] == '\0' && sobrenome[0] == '\0')
{
printf("\n\nERRO: Sem string no buffer");
exit(0);
}

printf("\nDigite sua idade e data de nascimento: ");

__fpurge(stdin);
scanf("%d%d",&idade);
__fpurge(stdin);
scanf("%d%d",&data);

if(idade <= 0 || idade >= 100 && data >= 2016 || data <= 1930)
{
printf("\n\nERRO: Dados invalidos");
exit(0);
}
else
{
printf ("\nNome e sobrenome: %s",nomecompleto);
printf("\nIdade e data: %d, %d\n",idade,data);
}

return(0);
}


Resolvi colocar o comando __fpurge(stdin) mas por algum motivo se comprta como um loop while.

Mais em http://www.cprogressivo.net/2012/12/Buffer--o-que-e-como-limpar-e-as-funcoes-fflush-e-fpurge.html

----------------------------------------------------------------------------------------------------------------
http://24.media.tumblr.com/tumblr_m62bwpSi291qdlh1io1_250.gif

# apt-get purge systemd (não é prá digitar isso!)

Encryption works. Properly implemented strong crypto systems are one of the few things that you can rely on. Unfortunately, endpoint security is so terrifically weak that NSA can frequently find ways around it. — Edward Snowden



3. Re: [Ajuda]Brincando com C

Perfil removido
removido

(usa Nenhuma)

Enviado em 24/03/2016 - 11:04h

Tentei com __fpurge() também não funcionou nesse caso.

Enfim, não consegui verificar se o primeiro caractere da string era nulo com "== '\0'", então apenas alterei a condição do if para verificar a quantidade de caracteres, ficando "<= 0". Não era o que eu queria, na verdade eu quero verificar se o primeiro caractere é nulo, e não se a quantidade de caracteres da string é menor ou igual a zero, porém eu vou tentar outros métodos, talvez com um if dentro do for para contar os caracteres e verificar se é nulo o primeiro caractere da string. Anyway...

Obrigado pela atenção mano listeiro_037, me fez pensar melhor... e realmente me ajudou bastante, valeu.
[]'s


-------------------------------------------------------------------------------------------
Just bring us some beers, and then we can talk about our systems. :)



4. Re: [Ajuda]Brincando com C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 24/03/2016 - 11:09h

Blz.

Tem uma diferença entre '\0' e "\0".

A primeira é um único caractere e a segunda são dois caracteres: '\0' '\0'.

Apesar de que na leitura o sistema deva para no primeiro.

Mesmo assim é errado comparar mais de um caractere com ==.

O correto seria com strcmp().

----------------------------------------------------------------------------------------------------------------
http://24.media.tumblr.com/tumblr_m62bwpSi291qdlh1io1_250.gif

# apt-get purge systemd (não é prá digitar isso!)

Encryption works. Properly implemented strong crypto systems are one of the few things that you can rely on. Unfortunately, endpoint security is so terrifically weak that NSA can frequently find ways around it. — Edward Snowden



5. Re: [Ajuda]Brincando com C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 24/03/2016 - 11:23h

Ahh, acho que entendi então, talvez seja algum conflito por comparar mais de um caractere com o mesmo operador na mesma condição, isso?
Eu andei lendo sobre strcmp() antes, acho que é minha solução para strings.

thanks one more time ;)


-------------------------------------------------------------------------------------------
Just bring us some beers, and then we can talk about our systems. :)



6. Re: [Ajuda]Brincando com C [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 24/03/2016 - 13:46h

Cristhoffer94 escreveu:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){


Se aqui fosse C++, estaria certo. Como é C, o certo seria você dizer “int main(void)” (ou “int main(int argc, char **argv)”, se você quiser receber argumentos do sistema operacional, mas não acho que seja o caso).

	char nome[20],sobrenome[20];
int idade,data;

printf("Digite seu nome: ");
scanf("%[^\n]",&nome,&sobrenome);


Aqui você cometeu mais de um erro.

Em primeiro lugar, você só colocou uma conversão “%[”, mas passou dois argumentos onde esperava receber os valores resultantes. Se você quer trocar nome e sobrenome, precisa de duas conversões.

Além disso, quando você aplicou o operador & aos nomes dos arrays nome e sobrenome, você fez com que o tipo dos ponteiros passados a scanf() fosse “ponteiro para array com 20 elementos do tipo char”, em lugar de simplesmente ser um ponteiro para caracteres, que é o que se deve usar com as conversões “%s”, “%[” ou “%c”. Um compilador configurado para detectar e alarmar incompatibilidade de tipos nos parâmetros de scanf() não vai gostar desse uso, e tampouco deveria você se satisfazer com ele, mesmo que o endereço do array como um todo coincida numericamente com o endereço de seu primeiro elemento. (Lembre-se que o nome de um array para elementos do tipo X é interpretado como se designasse ponteiro para dado do tipo X em qualquer expressão, exceto no momento de declaração do array ou quando se usam os operadores & ou sizeof).

Na prática, por causa desses erros o conteúdo de ambos os arrays é indeterminado (possivelmente nome até recebe alguma coisa válida, e sobrenome provavelmente permanece inalterado, mas como sua declaração não atribuiu valores iniciais, pode conter qualquer coisa).

Adicionalmente, convém você aprender desde cedo a se proteger de erros. Uma providência que você pode tomar é testar o valor de retorno de scanf(), até porque alguns sistemas/ambientes têm sido configurados para reclamar caso esse valor seja ignorado (Ubuntu, por exemplo).

Outra providência, particularmente mais relevante durante a leitura de strings, é limitar a quantidade máxima de caracteres que as conversões “%s” e “%[” aceitam preencher. O que você acha que pode acontecer se o usuário digitar um nome com mais de dezenove caracteres, sendo que você alocou strings que podem conter apenas vinte caracteres (incluindo o byte nulo que termina a string)?

scanf() está muito longe de ser uma função simples. Recomendo fortemente uma leitura bem cautelosa de sua documentação (e a manpage de scanf que vem com o Linux é muito boa, por sinal).

	char *nomecompleto = strcat(nome,sobrenome);
if(nome[0] == "\0" && sobrenome[0] == "\0"){
printf("\n\nERRO: Sem string no buffer");


Ao sinalizar erros, use escrita em stderr (e.g. frpintf(stderr, "Mensagem de erro\n")). Além disso, acostume-se a colocar uma quebra de linha ("\n") no final da mensagem, para evitar que texto gerado pelo sistema operacional após o término do seu programa não saia na mesma linha que o texto que você imprimir.

		exit(0); 


Por convenção, código de saída zero significa que o programa executou sem problemas. Para indicar erros no código de saída, retorne um valor não-nulo.

	}

printf("\nDigite sua idade e data de nascimento: ");
scanf("%d%d",&idade,&data);


Você fala em data, mas espera que o usuário digite o número de um annum domini. Cuidado com os termos: “data” pode induzir seu usuário a digitar algo como “24/03/2016” (data de hoje, 24 de março de 2016), que claramente não é o que o seu programa deseja.

	
if(idade <= 0 || idade >= 100 && data >= 2016 || data <= 1930){
printf("\n\nERRO: Dados invalidos");
exit(0);


Valem aqui os mesmos comentários feitos acima sobre formatação de saída e convenção sobre código de retorno.

	}

else{
printf ("\nNome e sobrenome: %s",nomecompleto);
printf("\nIdade e data: %d, %d\n",idade,data);


Novamente, acostume-se a terminar suas saídas sempre com uma marca de fim de linha.

Além do aspecto de misturar com texto gerado pelo sistema operacional, lembrei agora de outro detalhe: muitos programas orientados a texto, como wc, grep, sed, awk e até o próprio GCC, não consideram como válida uma linha em que falte a marca de fim de linha. Desse modo, se você redirecionar a saída do programa para outro programa, ou mesmo para um arquivo que depois seja aberto por outro programa, a falta do terminador da última linha pode fazer uma diferença crucial.


}
return(0);


return é um comando que não requer o uso de parênteses. Você poderia dizer tão-somente “return 0;”.

} 



7. Re: [Ajuda]Brincando com C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 24/03/2016 - 15:11h

Havia coisas que eu realmente não lembrava, como stderr para sinalizar erros, e valores não nulos nas saídas (isso eu realmente tinha esquecido), porém você falou sobre coisas que eu ainda não tinha lido.
Bom; eu vou prestar mais atenção na minha escrita, e nos erros básicos como passar dois argumentos para uma conversão.

E eu vou tomar mais cuidado com meus termos sim, é que esse source é o primeiro que eu escrevo em anos a titulo de teste/estudo mesmo, não me importei muito com o nome das variáveis, e sobre as quebras de linha foi relaxamento mesmo... vou me acostumar.

Em relação a leitura de strings, "especificar o numero máximo de caracteres" você quis dizer a quantidade máxima de caracteres na declaração da variável ou na conversão do scanf() mesmo? e no caso de strings não se usa o operador "&"? Bom, eu vou parar de perguntar e ler mais sobre funções de entrada e saída.

E vou ler de novo também com mais calma e atenção o seu texto quando estiver em casa, de qualquer modo; obrigado pela ajuda e pelo esclarecimento nos erros. Valeu pela atenção mano, poderia ter ignorado :)

-------------------------------------------------------------------------------------------
Just bring us some beers, and then we can talk about our systems. :)



8. Re: [Ajuda]Brincando com C [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 24/03/2016 - 15:58h

Cristhoffer94 escreveu:

Em relação a leitura de strings, "especificar o numero máximo de caracteres" você quis dizer a quantidade máxima de caracteres na declaração da variável ou na conversão do scanf() mesmo? e no caso de strings não se usa o operador "&"? Bom, eu vou parar de perguntar e ler mais sobre funções de entrada e saída.


Na chamada a scanf(), as conversões “%s” e “%[” correspondem a argumentos do tipo ponteiro de caracteres, e esses ponteiros indicam a posição inicial onde os caracteres recebidos serão armazenados, com os caracteres sucessivos recebidos pela conversão armazenados em posições sucessivas da memória após essa posição inicial. Se você não especificar um limite na hora de chamar a função, ela vai prosseguir colocando caracteres nessas posições sucessivas até encontrar um caráter delimitador na entrada provida pelo usuário. Como você não tem como garantir quais caracteres o usuário vai prover, não tem como saber de antemão quantos caracteres terá de reservar.

Para não depender do “bom comportamento” do usuário, você pode e deve limitar a quantidade máxima de caracteres consumidos pelas conversões de strings.

No seu programa, você declarou arrays com tamanho de 20 caracteres. Como strings têm de ter um byte nulo para marcar o fim da string, seus arrays, ao serem usados como strings, podem possuir no máximo 19 caracteres não-nulos, e 20º byte terá, nesse caso, de ser necessariamente nulo.

Para garantir isso após uma leitura de string feita com scanf(), você poderia fazer o seguinte.

char nome[20];
/* ... */
if(scanf("%19[^\n]", nome)!=1){
fprintf(stderr, "Erro de leitura.\n");
}


Com esse código acima, se o usuário digitar mais de 20 caracteres antes de apertar a tecla <Enter>, a leitura vai parar após o 19º caráter, e nome[19] receberá o byte nulo.


9. Re: [Ajuda]Brincando com C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 24/03/2016 - 18:36h

Agora apareceu uma dúvida:

Seja L uma string de 10 posições. Então ela seria representada por caracteres armazenados no intervalo 0..9. Caracter 10 é nulo.

{'a','b','c','d','e','f','g','h','i','j','\0'}

Não era assim L[10] = '\0' ?

----------------------------------------------------------------------------------------------------------------
http://24.media.tumblr.com/tumblr_m62bwpSi291qdlh1io1_250.gif

# apt-get purge systemd (não é prá digitar isso!)

Encryption works. Properly implemented strong crypto systems are one of the few things that you can rely on. Unfortunately, endpoint security is so terrifically weak that NSA can frequently find ways around it. — Edward Snowden



10. Re: [Ajuda]Brincando com C [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 25/03/2016 - 08:00h

listeiro_037 escreveu:

Agora apareceu uma dúvida:

Seja L uma string de 10 posições. Então ela seria representada por caracteres armazenados no intervalo 0..9. Caracter 10 é nulo.

{'a','b','c','d','e','f','g','h','i','j','\0'}

Não era assim L[10] = '\0' ?


Não. O byte nulo tem de estar dentro do espaço reservado.


Vamos por partes.

Se você declarar

char L[10] 


você terá um array com dez elementos do tipo char.

Uma primeira coisa que é interessante você notar é que esse array não necessariamente será usado como string. Você pode querer um array para guardar um conjunto de dez caracteres que, fora o fato de estarem no mesmo conjunto, não têm necessariamente relação uns com os outros. Qualquer dos dez elementos pode ter qualquer valor.

Mas você também pode usar um array de caracteres para armazenar strings. Nesse caso, haverá uma relação semântica entre os elementos (do nosso ponto de vista, não da linguagem) e haverá também um conjunto de restrições aplicadas ao array.

A primeira restrição é que a representação de strings como arrays de caracteres é puramente convencional, seguida por um conjunto de funções da biblioteca padrão, mas sem suporte nativo da linguagem. O único elemento sintático nativo da linguagem e relacionado a strings é a expressão de contantes literais na forma de texto delimitado por aspas.

A segunda, que é parte da convenção de representação, é que cada string exige a presença de um caráter terminador, cujo valor é o de um byte nulo.

A terceira, decorrente da segunda, é que a string não pode conter caracteres terminadores como parte do conteúdo representado. Isso implica, por exemplo, que eu não posso ter um byte nulo no meio de dois outros caracteres não-nulos, e querer que esses três bytes sejam manipulados como uma string com tamanho de três caracteres. Não serão, porque ao encontrar o byte nulo na segunda posição, todas as funções de strings entenderão que a string acabou ali, e a terceira posição nunca será examinada.

A quarta, que confunde muitas pessoas, é que o byte nulo tem de ser gravado junto com a string, mas não é considerado parte do seu conteúdo. Em outras palavras, ele ocupa espaço no array, mas não é levado em consideração pelas funções que medem o comprimento da string. O código abaixo mostra isso.

char str[]="Teste";
// Mesmo que ``char str[6]={'T', 'e', 's', 't', 'e', '\0'};´´

printf("sizeof str: %zd\n", sizeof str); // Imprime 6
printf("strlen(str): %zd\n", strlen(str)); // Imprime 5

str[2]='\0'; // str agora tem {'T', 'e', '\0', 't', 'e', '\0'}
printf("sizeof str: %zd\n", sizeof str); // Imprime 6
printf("strlen(str): %zd\n", strlen(str)); // Imprime 2

char str2[5]="Teste"; // Erro de compilação: array menor que constante literal (5<6)



11. Re: [Ajuda]Brincando com C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 25/03/2016 - 23:41h

Eu montei o seguinte código, igual na prática:

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

int main() {

char str[]="Teste";
// Mesmo que ``char str[6]={'T', 'e', 's', 't', 'e', '\0'};´´

printf("sizeof str: %zd\n", sizeof str); // Imprime 6
printf("strlen(str): %zd\n", strlen(str)); // Imprime 5

str[2]='\0'; // str agora tem {'T', 'e', '\0', 't', 'e', '\0'}
printf("sizeof str: %zd\n", sizeof str); // Imprime 6
printf("strlen(str): %zd\n", strlen(str)); // Imprime 2

char str2[5]="Teste"; // Erro de compilação: array menor que constante literal (5<6)
printf("sizeof str2: %zd\n", sizeof str2);
printf("strlen(str2): %zd\n", strlen(str2));

return 0;

}


Não teve erro de compilação no gcc. A saída também sem erro foi:

sizeof str: 6
strlen(str): 5
sizeof str: 6
strlen(str): 2
sizeof str2: 5
strlen(str2): 5


----------------------------------------------------------------------------------------------------------------
http://24.media.tumblr.com/tumblr_m62bwpSi291qdlh1io1_250.gif

# apt-get purge systemd (não é prá digitar isso!)

Encryption works. Properly implemented strong crypto systems are one of the few things that you can rely on. Unfortunately, endpoint security is so terrifically weak that NSA can frequently find ways around it. — Edward Snowden



12. Re: [Ajuda]Brincando com C [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 26/03/2016 - 00:55h

listeiro_037 escreveu:

Não teve erro de compilação no gcc.


Você tem razão. Eu confundi C com C++ aqui. Pode testar: o mesmo código, em C++, não vai.

E, mesmo em C, o array str2 deixa de ser string, pois falta o caráter '\0'. Além disso, se você passar o tamanho declarado de str2 de 5 para 4 (ou menor), ele vai passar a dar o mesmo erro de compilação também (não mais por perder o '\0', mas por truncar também dados visíveis).



01 02



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts