Erro na saída [RESOLVIDO]

1. Erro na saída [RESOLVIDO]

Pedro Victor
Nerdiarretado

(usa Arch Linux)

Enviado em 01/10/2018 - 23:43h

Pessoal, estou com um problema que no que entendi é uma besteira que sinceramente não consigo enxergar. O código em si não da erro nenhum porém quando vou colocar S ou N não executa nada e acaba o código

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

int main(void) {
char login[30];

char resposta;

printf("Digite seu login: ");
scanf("%s", &login);
if( login != "")

{
printf("Bem vindo ao sistema\n Deseja devolver livros s/n?\n ");
scanf("%s", &resposta);
if (resposta == "s")
{
printf("Quantos livros?");
}

else if (resposta == "n")
{
printf ("Volte sempre");
}

}
return 0;
}



  


2. MELHOR RESPOSTA

Hugo Torres
F9KILL

(usa Debian)

Enviado em 02/10/2018 - 00:59h

Para comparar strings em C use o método strcmp. Tambem para capturar as strings do teclado prefira usar o fgets, limpando o buffer de entrada para evitar erros com o fflush.
OBS: para receber as strigs não é necessário usar o simbolo & porque o primeiro elemento já é o endereço da variável, e para capturar caracteres use %c.

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

int main(void)
{
char login[30];
char resposta;

printf("Digite seu login: ");
fflush(stdin); fgets(login, 30, stdin);

if (strcmp(login, "") != 0) {
printf("\nBem vindo ao sistema\nDeseja devolver os livros [s]im [n]ao: ");
scanf("%c", &resposta);

if (resposta == 's') {
printf("Quantos livros?\n");
}
else if (resposta == 'n') {
printf("Volte sempre\n");
}
}
return 0;
}



3. Re: Erro na saída [RESOLVIDO]

Willian
ThePinkShark

(usa Slackware)

Enviado em 02/10/2018 - 00:38h

Compile ele usando:
gcc nomedoarquivo.c -o nomedoexecutavel

E verá que ele retorna 2 alertas. Eu estou faz um bom tempo sem brincar com C, mas acredito que seja fácil encontrar material sobre os alertas.


4. Re: Erro na saída [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 03/10/2018 - 17:24h

Sei que este tópico já foi marcado como resolvido, mas eu tinha escrito uma resposta ontem de manhã, que se perdeu devido a um instabilidade da rede no meu trabalho. Como, no entanto, eu acho que ela é útil para esclarecer e corrigir algumas coisas (inclusive na resposta já marcada como melhor resposta), segue agora, mesmo com atraso.

F9KILL escreveu:

Para comparar strings em C use o método strcmp. Tambem para capturar as strings do teclado prefira usar o fgets, limpando o buffer de entrada para evitar erros com o fflush.


O comportamento de fflush() “limpar” o buffer de entrada não é previsto pelo padrão da biblioteca do C (na verdade, a função só é definida para operar em streams de saída, não de entrada). Assim sendo, não é prudente a recomendação generalizada de usar fflush() com esse propósito.

Indo um pouco além, é até complicado definir o que seja “limpar”, porque, salvo algum acidente com o teclado, nada que aparece na entrada de dados surge como uma poeira ou sujeira que suja um móvel, mas sim porque foi colocado lá pelo sistema ou por quem tiver gerado os arquivos de entrada. Sabendo-se lidar devidamente com os dados presentes na entrada, operações de limpeza (ou, mais propriamente, de descarte) tendem a ser ou desnecessárias ou razoavelmente especializadas, para além do ponto de apenas descartar todos os caracteres até a marca de fim de linha.

OBS: para receber as strigs não é necessário usar o simbolo & porque o primeiro elemento já é o endereço da variável, e para capturar caracteres use %c.


Aqui a questão e mais forte do que não ser necessário. Aplicar o operador de obtenção de endereço é realmente errado. E é também incorreto dizer que “o primeiro elemento já é o endereço da variável”.

O que acontece de fato é que em quase todas as operações envolvendo arrays em C, o nome de um array com N elementos de um tipo de dados X tem um decaimento automático de tipo, de modo a produzir um valor cujo tipo é “ponteiro para dado do tipo X”, e tal valor corresponde ao endereço do primeiro elemento do array. Essa regra de decaimento de tipo tem apenas duas exceções em C, que são quando o array é usado como operando para o operador sizeof (que devolve o tamanho em bytes ocupado pelo array inteiro, contando-se todos os seus N elementos), e como operando do operador &, que obtém o endereço do array tomado como uma unidade de dados, devolvendo um valor que é do tipo “ponteiro para array com N elementos do tipo X” (que, como se pode ver, é diferente do tipo que seria produzido pelo decaimento do array para ponteiro).

O erro de uma construção como “scanf("%s", &char_array)” (além de problemas de segurança não discutidos aqui) é justamente a discrepância entre o tipo de dados produzido por “&char_array” (que provavelmente será “ponteiro para array de N caracteres”) e aquele que deveria ser passado como correspondência da conversão "%s" (“ponteiro para caráter”).

Muitas vezes esse erro acaba não aparecendo como um bug claramente disruptivo porque na maioria das vezes o valor absoluto (i.e. descontando-se o tipo de dados, ou tomando-se o valor como se fosse um valor inteiro) do endereço do array como um todo é igual ao do endereço de seu primeiro elemento. Por ser uma função que aceita quantidade variável de elementos, é difícil para um compilador conseguir detectar erro de tipo entre os argumentos passados a scanf(), a não ser que se crie código específico para o tratamento de scanf(), que tornaria sua compilação distinta de outras funções com características semelhantes.

Mesmo assim, é bom não confiar nessa coincidência numérica entre ponteiros para tipos de dados distintos. Algumas boas razões para isso são as seguintes:

  (1) Alguns compiladores efetivamente possuem o tratamento especializado para as famílias de funções de scanf() e printf(), e podem alertar sobre (ou mesmo impedir a compilação, indicando erro, por causa de) discrepâncias nos tipos dos argumentos correspondentes a determinadas conversões.

  (2) Existem casos em que se quer ler dados para uma posição diferente do início do array (por exemplo: já se ter um prefixo no início do array que se deseja preservar). Nesses casos é comum indicar esse deslocamento como “n+char_array”, que é sinônimo de “&char_array[n]”, mas muito diferente de “n+&char_array”.

  (3) É comum usar objetos declarados diretamente como ponteiros, em vez de como arrays, na expressão passada como argumento para scanf(); Nesses casos, é uma certeza praticamente absoluta que o valor absoluto do ponteiro p_char será diferente do valor absoluto de &p_char.

  (4) Algumas declarações com aparência de arrays criam, na verdade, ponteiros (particularmente quando aparecem na declaração de parâmetros de funções). Nesse caso, tem-se o mesmo problema descrito em (3).

Caso o programador sinta necessidade de uniformizar o uso de scanf(), requerendo sempre o operador &, ele pode optar por fazer, por exemplo, “scanf[("%s", &char_array[0])” ou “scanf("%s", &p_char[n])”, em lugar de “scanf[("%s", char_array)” ou “scanf("%s", n+p_char)”, respectivamente.

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

int main(void)
{
char login[30];
char resposta;

printf("Digite seu login: ");
fflush(stdin); fgets(login, 30, stdin);


O fflush(), além de contraindicado (ver acima), é desnecessário neste caso (pois é de se supor que a entrada esteja ainda não esteja com dados inconsistentes ou inesperados num programa que acabou de começar.

Além disso, esse valor constante 30 é um problema de organização de código. Se amanhã o usuário alterar o valor usado na declaração do array, ele teria de varrer o programa em busca de outras constantes que poderiam estar relacionadas.

Uma forma melhor de fazer seria a seguinte.
fgets(login, sizeof login, stdin) 


É interessante lembrar ainda que fgets() retém o caráter indicador de fim de linha (supondo que a linha coube no limite de caracteres a ler). Se, durante a execução, o usuário digitar “Paulo” e apertar a tecla Enter, o conteúdo do array será "Paulo\n". Se não se quiser manter esse '\n', deve-se explicitamente extirpá-lo com algo como o seguinte.
int l=strlen(login);
if(l>0 && login[l-1]=='\n')
login[--l]='\0'; // Substitui fim de linha por fim de string.


Existe o caso possível em que o usuário digita mais caracteres do que o tamanho máximo do array. Se isso ocorrer, os caracteres excedentes vão permanecer no buffer de entrada.
int l=strlen(login);
if(l>0){
if(login[l-1]=='\n')
login[--l]='\0';
else if(l==(sizeof login)-1){
// String digitada excedeu tamanho máximo.
// Descarta caracteres excedentes.
int c;
do
c=getchar();
while(c!='\n' && c!=EOF);
}
else{
// Linha curta, mas sem '\n'. Possível fim de dados prematuro.
// Algumas aplicações consideram isso um erro.
}
}



if (strcmp(login, "") != 0) {
printf("\nBem vindo ao sistema\nDeseja devolver os livros [s]im [n]ao: ");
scanf("%c", &resposta);


A operação de leitura acima é uma candidata a deixar “resíduos” no buffer de entrada.


if (resposta == 's') {
printf("Quantos livros?\n");
}
else if (resposta == 'n') {
printf("Volte sempre\n");
}
}
return 0;
}







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts