Ir para conteúdo
VictorCacciari

[Tutorial] system("pause") e fflush(stdin)

Recommended Posts

Outro adendo, que não é sobre fflush(stdin) e nem system, mas pelo menos fica tudo num tópico só e deixa mais fácil indicar o link: tipo de retorno da função main.

Segundo o C99:

 

"The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters ( int main(void) ) or with to parameters (refered to here as argc and argv, though any names may be used, as they are local to the function in which they are declared)"

 

"The return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified."

 

 

Frisando: Se o tipo de retorno do main não for compatível com int, o status de retorno p/ o ambiente não é especificado. Agora, os códigos:

isis@linux-45c9:~/src> cat tmain.c

float main(void) {

return 123.48F;

}

isis@linux-45c9:~/src> gcc tmain.c

tmain.c: In function main:

tmain.c:1: warning: return type of main is not int

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

195

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

195

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

195

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

195

isis@linux-45c9:~/src> cat tmain2.c

struct p {

int a;

int b;

char* q;

};

 

 

struct p main(void) {

struct p ts = {2,3, "ps axu"};

return ts;

}

isis@linux-45c9:~/src> ./a.out

Falha de segmentação

isis@linux-45c9:~/src> echo $?

139

isis@linux-45c9:~/src> ./a.out

Falha de segmentação

isis@linux-45c9:~/src> echo $?

139

isis@linux-45c9:~/src> ./a.out

Falha de segmentação

isis@linux-45c9:~/src> echo $?

139

isis@linux-45c9:~/src> ./a.out

Falha de segmentação

isis@linux-45c9:~/src> echo $?

139

 

isis@linux-45c9:~/src> cat tmain3.c

char main() {

return 'a';

}

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

97

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

97

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

97

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

97

isis@linux-45c9:~/src> cat tmain4.c

char * main() {

return "123123";

}

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

192

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

192

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

192

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

192

isis@linux-45c9:~/src> cat tmain5.c

void main() {

 

}

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

148

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

132

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

148

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

228

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

116

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

148

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

100

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

164

isis@linux-45c9:~/src> cat tmain6.c

void main() {

return;

}

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

52

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

148

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

244

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

164

isis@linux-45c9:~/src> ./a.out

isis@linux-45c9:~/src> echo $?

20

A partir desses pequenos programas, nota-se que o void main sem o return ocasiona um valor de retorno aleatório ao sistema operacional. Por que isso acontece? Veja o próximo programa:

 

 

 

isis@linux-45c9:~/src> cat tmain7.c

int main() {

return 90;

}

isis@linux-45c9:~/src> cat tmain7.s

.file "tmain7.c"

.text

.globl main

.type main, @function

main:

leal 4(%esp), ìx

andl $-16, %esp

pushl -4(ìx)

pushl ëp

movl %esp, ëp

pushl ìx

movl $90, êx

popl ìx

popl ëp

leal -4(ìx), %esp

ret

.size main, .-main

.ident "GCC: (SUSE Linux) 4.3.2 [gcc-4_3-branch revision 141291]"

.section .comment.SUSE.OPTs,"MS",@progbits,1

.ascii "ospwg"

.section .note.GNU-stack,"",@progbits

Note que o valor passado para a função return é colocado no registrador $eax, utilizado para armazenar valores de retorno de funções. No código assembly do void main não temos a presença da instrução movl para o $eax, ou seja, qualquer valor que esteja lá (por término de algum outro processo no sistema ou através de somas, já que o $eax também serve de registrador acumulador), vai ser retornado.

 

 

 

 

 

isis@linux-45c9:~/src> cat tmain6.s

.file "tmain6.c"

.text

.globl main

.type main, @function

main:

leal 4(%esp), ìx

andl $-16, %esp

pushl -4(ìx)

pushl ëp

movl %esp, ëp

pushl ìx

popl ìx

popl ëp

leal -4(ìx), %esp

ret

.size main, .-main

.ident "GCC: (SUSE Linux) 4.3.2 [gcc-4_3-branch revision 141291]"

.section .comment.SUSE.OPTs,"MS",@progbits,1

.ascii "ospwg"

.section .note.GNU-stack,"",@progbits

 

isis@linux-45c9:~/src> gcc -S tmain5.c

tmain5.c: In function main:

tmain5.c:1: warning: return type of main is not int

isis@linux-45c9:~/src> cat tmain5.s

.file "tmain5.c"

.text

.globl main

.type main, @function

main:

leal 4(%esp), ìx

andl $-16, %esp

pushl -4(ìx)

pushl ëp

movl %esp, ëp

pushl ìx

popl ìx

popl ëp

leal -4(ìx), %esp

ret

.size main, .-main

.ident "GCC: (SUSE Linux) 4.3.2 [gcc-4_3-branch revision 141291]"

.section .comment.SUSE.OPTs,"MS",@progbits,1

.ascii "ospwg"

.section .note.GNU-stack,"",@progbits

  • +1 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
Como contornar?

Por que não devemos usar fflush(stdin) se ele "funciona" direito??

Na documentação da função está escrito: "effect undefined for input streams".

Se nem eles (que escreveram a função) sabem o que acontece, nós, simples mortais happy.gif, muito menos!

Não é que não sabem o que acontece.

"effect undefined for input streams" Quer dizer que fflush pode ser diferente dependendo do sistema operacional. Ou seja, no windows ela pode limpar o buffer e mandar para o kernel, mas no linux pode apenas mandar o buffer para o kernel. Este é o problema dessa função em relação as outras.

 

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Estou começando a aprende C, e aprendi usando "System("pause")" e "fflush(stdin)". Pra mim esse tópico foi de GRANDE utilidade, agradeço ^^

Editado por CITH

Compartilhar este post


Link para o post
Compartilhar em outros sites

VictorCacciari

 

Eu estou tendo problemas com o buffer usando o delimitador de string. Veja no seguinte código:

#include <stdio.h>

int main()
{
    char Test[99];

    do
    {
        scanf(" %3s",Test);
        printf("%s\n",Test);

    } while( 1 );
}

Eu desejo coletar apenas 3 caracteres da string digitada, e está saindo como planejado, mas o resto da string que não foi coletada fica no buffer, ocasionando o problema que você já deve ter percebido. :upset:
Utilizando o fflush(stdin) resolve, mas estou abolindo essa função da minha vida, o que eu devo fazer? Se puder me ajudar agradeço muito.

Editado por CITH

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá! Como estão? Sou novo no fórum.

Me apresento... Podem me chamar vango.

 

Achei bem interessante este tema, e também esta potente ferramenta que é o fórum.

Vou deixar uma forma há mais para que não tenham problemas com o buffer.

 

A solução que eu proponho não vi em nenhum outro post assim me perdoem se faço duplo post, não é minha intenção:

 

Se vamos ler 2 char seguidos ou um char e uma string ou vice-versa, com 2 scanfs seguidos, a solução do "%c%*c" não está nada mal. Uma forma há mais de obter o mesmo resultado é por um espaço andes do especificador %c antes de ler o segundo char no segundo scanf, ou %s se for uma string. Entendeu?

Deixo um exemplo:

char a;
char b;
printf("Entre uma letra: ");
scanf( "%c", &a );
printf("Entre uma letra: ");
scanf( " %c", &b ); // <---NOTE o ESPAÇO ANTES DO %c entre " e % ISSO evita ter que por %*c no scanf anterior, o que faz é IGNORAR A ULTIMA LETRA que é '\n' sempre =)

Fácil né?

 

Espero que sirva de algo, o para alguém, já que é uma forma pouco corrente de evitar que entre lixo no buffer.

scanf( " %c", &b ); teria o mesmo efeito que por o especificador %*c no scanf anterior scanf( "%c%*c", &a );

 

Sorte! :thumbsup:

Editado por GBecker

Compartilhar este post


Link para o post
Compartilhar em outros sites

Para limpar o stdin recomendo o uso de uma das funções abaixo:

void limpa_linha() {
    scanf("%*[^\n]");
    scanf("%*c");
}

ou essa:

void fflush_stdin() {
    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF);
}

O uso do comando fflush(stdin); não é nada recomendado para limpar o stdin, ou "buffer de entrada"

  • +1 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.