-
Posts
6.526 -
Cadastrado em
-
Última visita
Tipo de conteúdo
Artigos
Selos
Livros
Cursos
Análises
Fórum
Tudo que arfneto postou
-
dirent funciona mais ou menos como está nese exemplo ai. Se está usando windows pode também usar _findfirst() / _findnext(). Estão documentadas em https://docs.microsoft.com/en-us/cpp/c-runtime-library/filename-search-functions?view=vs-2019 onde tem um programa exemplo que lista todos os arquivos .c no diretório corrente. Esse exemplo aqui: // crt_find.c // This program uses the 32-bit _find functions to print // a list of all files (and their attributes) with a .C extension // in the current directory. #include <stdio.h> #include <stdlib.h> #include <io.h> #include <time.h> int main( void ) { struct _finddata_t c_file; intptr_t hFile; // Find first .c file in current directory if( (hFile = _findfirst( "*.c", &c_file )) == -1L ) printf( "No *.c files in current directory!\n" ); else { printf( "Listing of .c files\n\n" ); printf( "RDO HID SYS ARC FILE DATE %25c SIZE\n", ' ' ); printf( "--- --- --- --- ---- ---- %25c ----\n", ' ' ); do { char buffer[30]; printf( ( c_file.attrib & _A_RDONLY ) ? " Y " : " N " ); printf( ( c_file.attrib & _A_HIDDEN ) ? " Y " : " N " ); printf( ( c_file.attrib & _A_SYSTEM ) ? " Y " : " N " ); printf( ( c_file.attrib & _A_ARCH ) ? " Y " : " N " ); ctime_s( buffer, _countof(buffer), &c_file.time_write ); printf( " %-12s %.24s %9ld\n", c_file.name, buffer, c_file.size ); } while( _findnext( hFile, &c_file ) == 0 ); _findclose( hFile ); } }
-
acho que entendeu perfeitamente. atente para as diferenças nas declarações da função e os comandos return correspondentes. e comece a escrever alguma das funções de seu programa usando esse esqueleto de programa aí... E poste de volta usando o botão <> para abrir uma janela onde você insere o programa ...
-
Você leu o trecho do livro que fala sobre funções? fez sentido pra você ou ficou com dúvidas? Esse é o resultado do programa que vem depois em main() vai chamar funcao a na funcao a em main() funcao_a() retornou 2 em main, vai chamar funcao b na funcao b parametros foram '128' e 'c' em main() funcao_b() retornou Eis o programa #include "stdio.h" int funcao_a() { printf("na funcao a\n"); return 2; }; // funcao_a() void funcao_b(int numero, char letra) { printf("na funcao b\n"); printf("parametros foram '%d' e '%c'\n", numero, letra); return; }; // funcao_a() int main(int argc, char** argv) { printf("em main() vai chamar funcao a\n"); int n = funcao_a(); printf("em main() funcao_a() retornou %d\n", n); printf("em main, vai chamar funcao b\n"); funcao_b(128,'c'); printf("em main() funcao_b() retornou\n"); return 0; } Ele cria e chama duas funções. Diga se isso é já natural pra você ou se tem alguma dúvida
-
Sabe escrever um loop que continua rodando durante um fgets()? Sem multithread? Seria brilhante. Pode postar um?
-
for, if e while são comandos e não funções. Seu curso tem um livro-texto? Qual é? Tem alguma apostila? Você tem algum livro? Já fez programas desse tipo? Conhece algo de estatística? O tal PDF tem 3 páginas apenas. Você poderia ter postado aqui não é?
-
Pois é. Isso é o que estou tentando te explicar: Como não existe isso aqui o programa para no scanf() ou no getc(0 ou no fgets() ou no fread()... Entenda isso: um programa comum para no read. Fica esperando o usu;ario teclar algo. Posso chamar as variáveis de meu programa de qualquer coisa, inclusive de buffer, mas isso não vai fazer com que elas sejam um buffer de i/o, de stream como o buffer de teclado ou o de printf() que são controlados pelo sistema operacional e assim criar uma "solução brilhante" para limpar o lixo do buffer do teclado. É o sistema operacional que coloca o ENTER no buffer. E uma leitura no seu programa faz ele parar. Até ter algo no buffer do sistema para ele copiar para a variável buffer do seu programa. Mas é o contrário o que estou fazendo. Tentado explicar aos leitores o que é um buffer do sistema e uma variável buffer. E como é vantagem você só ler se sabe se tem algo pra ser lido. Exemplo: um jogo de 6 comandos sobe desce esquerda direita atira encerra Pergunta: Como você faz um jogo desses rodar sem parar pra ler o comando?... Resposta: Você roda o jogo e só lê depois do cara ter teclado algo. Assim o read é satisfeito imediatamente e o jogo continua. Sua variável buffer, com ou sem o ENTER, de nada serviria. por sorte você não tem o dia todo. Não vou julgar se eu tenho paciência ou me julgar de qualquer modo. Mas meu pessoal diz isso às vezes. Vou separar algo antigo que dê pra usar em "slides" e postar aqui qualquer hora
-
dirent só vai te dar os nomes e a partir daí você chama suas coisas... Imagine uma função mágica que você chama assim char* proximo_arquivo(const char* Pasta); E uma função assim: int executa_acao(const char* arquivo); E a seguinte especificação: se você chama proximo_arquivo() com um valor diferente de "" é o nome da pasta e próximo arquivo vai preparar a lista de arquivos que tem nessa pasta e retornar digamos "12" se a pasta tiver 12 arquivos. E zero se não conseguir abrir a pasta. se você chama proximo_arquivo() com um valor "" então ela devolve o nome do proximo arquivo na pasta e aí você chama executa_acao() com o nome do tal arquivo e a fila anda. Notou que isso fecha o círculo? É só isso. Poda ser melhor, depois eu mostro um exemplo melhor. E você já pode testar isso com uma função fake que simula uma lsita de arquivos. Veja um exemplo: #include <stdio.h> #include <stdlib.h> #include <string.h> int executa_acao(const char*); const char* proximo_arquivo(const char*); int main(int argc, char** argv) { // testes const char* lista = proximo_arquivo(".\\teste"); if (lista == "") { printf("Nao conseguiu a lista de arquivos\n"); return 0; } printf("Lista retornou %s arquivos\n", lista); int N = atoi(lista); for (int i = 0; i < N; i += 1) { int res = executa_acao(proximo_arquivo("")); printf("acao() retornou %d\n", res); }; // for }; // main() const char* proximo_arquivo(const char* pasta) { static int N = -1; static const char testes[3][20] = { "a.txt", "b.txt", "c.txt" }; static const char* total = "3"; if (pasta == "") { N = N + 1; switch (N) { case 0: case 1: case 2: return testes[N]; break; default: return NULL; break; }; // switch() } else { printf("Montando lista para a pasta '%s'\n", pasta); N = -1; // aqui seria o caso de chamar // dirent e preencher uma lista // agora não preciso fazer nada exceto // marcar como iniciado }; // if() return total; } int executa_acao(const char* arquivo) { printf(" ==> executa acao para arquivo '%s'\n", arquivo); return 0; } Você pode criar uma pasta teste e colocar os arquivos lá e ir testando as ações enquanto não se entende com dirent. Confirme se entendeu. RODE esse programa. Entenda como pode ir progredindo... É tudo falso mas é tudo verdade. Por isso programação é interessante.
-
Não tentei ler o programa, mas qual a ideia de ENTER 2 VEZES? Se está tentando isso com uma achamada a pressione ENTER não vai rolar. Sua ideia do menu esta confusa sem necessidade. Talvez pudesse simplesmente limpar a tela ao entrar no menu uma unica vez. Ler a opção, tratar, e voltar. Só isso. adicionado 46 minutos depois É estranho dizer que sua própria ideia é brilhante. O "buffer" de que está lendo é uma variável do seu programa. Você já leu do stream e, ao invés de usar fscanf() que leria do buffer do stream, você usa sscanf() que e lê de uma variável do seu programa que você sabiamente chamou de buffer. Para que eu preciso disso: Eu te mostrei um exemplo. Mas vou repetir o caso mais simples: imagine que você não quer ler enquanto não tenha nada pra ler. Entenda isso. É importante. Essencial às vezes se seu programa NÃO FOR MULTI-THREAD. O caso mais simples: seu programa está rodando e é um jogo de console. A tela esta rodando algum tipo de animação. O usuário tem uns comandos, tipo movimento e tiro. E você pode ler os clássicos E S D X para os movimentos e ESPAÇO para atirar. Se você escrever um fread(), um scanf(), um getc(), um fgets() o programa vai PARAR pra ler o comando até o cara digitar algo. Você só quer ler o comando depois que souber que o cara digitou. Entenda isso. Se não entendeu escreva explicando onde está a dúvida desta vez. É um conceito importante. Você não pode parar a execução e ficar esperando. Também não pode ler para o seu "brilhante" buffer o que ainda não foi digitado. Para isso precisa da colaboração do sistema operacional. No windows pode usar a rotina que te mostrei. No Unix usa algo como ioctl() e faz algo similar. Eu escrevi soluções assim para Unix muitas vezes, mas não me lembro dos detalhes, mas tem algo na estrutura dos buffer do terminal que dava essa informação de que tem algo a ser lido. Sinceramente não me lembro. Não adianta nada ler para a sua variável buffer. Espero que tenha entendido agora. São coisas que acontecem em tempo real. Não dá pra ler antes no buffer que está dentro do seu programa porque ninguém digitou ainda. Seu programa segue um loop de execução e se o usuário digitou algo você vai lá e lê. Não pode ler antes de ele ter digitado. Mas às vezes não pode simplesmente escrever um scanf() e ficar esperando... Seu tom parece não estar sendo de muita cortesia. Vou explicar isso de novo também: SE FOSSE MULTI-THREAD seu programa poderia ter um loop de execução e outro de leitura e aí o de leitura poderia ficar parado. Entendeu agora? Como o programa, o nosso exemplo aqui, é um programa comum com uma sequência de execução só, sabe o que acontece se você chama um read: o programa para. Talvez possa mudar o tom. Não tenho uma solução perfeita. E já te disse que não se trata de lixo. Não sei se existe tal coisa de solução perfeita. Eu te mostrei as DUAS opções que se usa na prática e até com detalhe: Ler caracteres via getc() ou linhas via gets() e tratar em seu programa. Até citei o que o runtime faz montando o vetor de argv antes de acionar seu programa em C. E quando precisar usar em Windows PeekConsoleInput() para ver se tem algo pra ler e só ler se tiver. E no Linux/Mac ver a outra solução de que falei e não me lembro. E te falei da existência de ungetc() em todas as plataformas. Já que estou escrevendo, vou te dar um exemplo de que me lembrei agora. Nos '90 eu trabalhava em um sistema grande em UNIX para automação bancária e tinha uma situação em que máquinas especiais eram ligadas como terminais do Unix e o sistema era controlado por dois terminais de uso dos operadores das máquinas. Sempre que a máquina terminava um certo processo uma mensagem indicativa aparecia na tela e o operador tinha que ir até a máquina retirar um lote de documentos e voltar ao terminal para autorizar o reinício. Durante meses o pessoal pedia uma maneira de escolher um tempo para reinício e voltar sózinho a ler A MENOS que eles usassem algum comando, ao invés de sempre parar e eles terem que voltar ao terminal nem que fosse para teclar um ENTER. Já imaginou o cenário certo? O sistema era escrito em COBOL e minha solução foi escrever um read em C que substituía a leitura do COBOL e depois do tempo que cada operador podia programar em seu turno voltava a acionar as máquinas a menos que o operador digitasse um comando. Entendeu a diferença? Só lia quando ele tinha digitado algo. Sinto por isso. Se não entendeu mesmo o que expliquei ou ainda acha que quero criar polêmica. Eu te mostrei vários exemplos.
-
Então você conseguiu a explicação mas não conseguiu colocar em seu programa, certo? Vou ver se tenho um exemplo aqui
-
Você leu o código reordenado? Entendeu as diferenças? O que é o tal campo "ativo"? Viu que eu inseri na estrutura? Vai usar essa estrutura? Entendeu as notas sobre pressioneEnter( e flush()?
-
hey, reproduzir o enunciado não é uma pergunta objetiva. Objetivo é você dizer em que ponto disso tem um problema agora... Algo objetivo: void EliminarFuncionario(struct Funcionario funcionario[], int n); Esse trecho não está bom acabou de declarar i. Que acha que vai ter lá? ler um char com o especificador %d é quase certo de cancelar seu programa que é ativo? Não vi na declaração se não vai fazer nada se file == NULL retorne apenas. if (file == NULL) { printf("\n-->Nao foi possivel abrir o fecheiro\n\n"); return; } Pra que deslocar todo o seu programa pra direita? Dificultar a leitura? Considere declarar um typedef para struct Funcionario... Para que digitar isso toda hora? typedef struct { char categoria[20]; int Hora_Trabalhados; char nome[20]; char NIF[20]; float salario; } Funcionario; // Para não atrapalhar o bom funcionamento void menu(Funcionario funcionario[], int n); Essa construção é comum, mas devia ser evitada: Tudo isso é a mesma coisa. O prompt podia ser um parâmetro de pressioneEnter() não acha? Não seria original, já que o comum. E chamar flush(0 é supérfluo porque pressioneEnter() pode muito bem fazer isso. Limpar a tela e mostrar o menu novamente não sei... Precisaria ver o loop de execução de seu programa... Algo assim adicionado 16 minutos depois Considere seu programa assim: não mudei nada exceto o mínimo para compilar e aquele if() de que falei Coloquei um parametro em pressioneENTER() e um int ativo em Funcionario e mudei para um typedef. Mas não mudei nada da lógica. Parece um pouco confuso ainda. Considere as coisas que perguntei. Talvez prefira prosseguir com o programa assim como abaixo. Repito não mudei nada. Mas compila e as funções estão em ordem #include <conio.h> #include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> //Dados do funcionário typedef struct { int ativo; char categoria[20]; int Hora_Trabalhados; char nome[20]; char NIF[20]; float salario; } Funcionario; void EliminarFuncionario(Funcionario[], int); void flush(); void InserirFuncionario(Funcionario[], int); void menu(Funcionario[], int); void OrdenarFuncionario(Funcionario*, int); void pressioneEnter(const char*); int main() { setlocale(LC_ALL, "Portuguese"); Funcionario funcionario[100]; int n = 0; Funcionario* p = (Funcionario*) malloc(sizeof(Funcionario)); if (p == NULL) { printf("\n\t ERRO MEMÓRIA INSUFICIENTE!\n"); exit(1); //Terminar o programa } system("COLOR F0"); //Abertura do programa printf("\n\n\n\n\n\t\t\t....................................................................\n"); printf("\n\t\t\t\t----> SISTEMA DE REGISTO E CONTROLE DE FUNCIONÁRIO \n"); printf("\n\t\t\t.....................................................................\n\n\n\n\n"); printf("\n\t\t\t UNICV \n\n"); printf("\n\tPressione ENTER 2 vezes para iniciar->"); flush(); pressioneEnter(""); system("cls"); menu(funcionario, n); free(p); return 0; }; // main() void EliminarFuncionario(Funcionario funcionario[], int n) { FILE* file; //Abre o arquivo novamente para leitura file = fopen("funcionarios.txt", "r+"); if (file == NULL) { printf("\n-->Nao foi possivel abrir o fecheiro\n\n"); return; } int i = 0; int nif; char resp; printf("\n\tInforme o NIF do funcionario a ser Eliminado: "); scanf(" %d", &nif); //while (funcionario[i].NIF == nif) so para compilar while (funcionario[i].NIF[0] == nif) { if (funcionario[i].ativo == 1) { printf("\n\tNome: %s", funcionario[i].nome); printf("\n\tNIF: %s", funcionario[i].NIF); printf("\n\tSalario: %.1f $00", funcionario[i].salario); printf("\n\tCategoria: %s", funcionario[i].categoria); printf("\n\tHoras de trabalho: %d horas", funcionario[i].Hora_Trabalhados); printf("\n\n----------------------------------------------------------\n"); } printf("\n\tDeseja realmente eliminar o Funcionário? S/N:"); scanf(" %c", &resp); if ((resp == 'S') || (resp == 's')) { funcionario[i].ativo = 0; printf("\n\tFuncionário eliminado com sucesso\n"); break; } else { if ((resp == 'N') || (resp == 'n')) { printf("\tEliminação cancelada!\n"); break; } } i++; if (i > 99) printf("\n\n\t\tNIF não encontrado\n"); }; // while() fclose(file); pressioneEnter("\n\n\n\t\t\tPressione ENTER para Continuar->"); system("cls"); }; // EliminarFuncionario() void flush() { int c; /*Lê todos os caracteres até encontrar '\n' ou EOF:*/ while ((c = getchar()) != '\n' && c != EOF); }; // flush() void ImprimirFuncionarios(Funcionario funcionario[], int n) { FILE* file; file = fopen("C:\\Users\\alex\\Desktop\\ajuda\\funcionarios.txt", "r"); if (file == NULL) printf("\n-->Nao foi possivel abrir o fecheiro\n\n"); else { int i; printf("\n\n\n\t\t------- LISTA DOS FUNCIONÁRIOS ------\n\n"); for (i = 0; i < n; i++) { system("COLOR 0F"); fscanf(file, " %s", funcionario[i].nome); fscanf(file, " %s", funcionario[i].NIF); fscanf(file, " %f", &funcionario[i].salario); fscanf(file, " %s", funcionario[i].categoria); fscanf(file, " %d horas", &funcionario[i].Hora_Trabalhados); printf("\n\tNome: %s", funcionario[i].nome); printf("\n\tNIF: %s", funcionario[i].NIF); printf("\n\tSalario: %.1f $00", funcionario[i].salario); printf("\n\tCategoria: %s", funcionario[i].categoria); printf("\n\tHoras de trabalho: %d horas", funcionario[i].Hora_Trabalhados); printf("\n\n----------------------------------------------------------\n"); } } pressioneEnter(""); system("cls"); fclose(file); }; // ImprimirFuncionarios() void InserirFuncionario(Funcionario funcionario[], int n) { system("COLOR 0F"); FILE* file; // cria variável ponteiro para o arquivo file = fopen("funcionarios.txt", "w"); //abrindo o arquivo if (file == NULL) //testando se o arquivo foi realmente criado printf("\n-->Nao foi possivel abrir o fecheiro\n\n"); else { printf("\n\n\n\n\tUNICV \n\n"); printf("\n\n\n\t\tDigite o numero de Funcionarios que pretende registrar: "); scanf(" %i", &n); flush(); system("cls"); static int i = 0; int y = n + i; if (y > 99) menu(funcionario, n); printf("\n\n\n\t\t-------- INSCRIÇÃO DE FUNCIONÁRIO --------\n\n"); fprintf(file, "\n\n\t----- LISTA DOS FUNCIONÁRIOS ----\n\n"); fprintf(file, "\tNome NIF Salário Categoria Horas\n\n"); for (; i < y; i++) { system("COLOR 0B"); // para obter dados e armazenar no arquivo printf("\n\tDigite o nome do funcionário: "); scanf(" %s", funcionario[i].nome); flush(); printf("\n\tDigite o NIF do funcionário: "); scanf(" %s", funcionario[i].NIF); printf("\n\tDigite o salario do funcionario: "); scanf(" %f", &funcionario[i].salario); flush(); printf("\n\tDigite a categoria do funcionário: "); scanf(" %s", funcionario[i].categoria); printf("\n\tDigite a Hora trabalhados pelo funcionário: "); scanf(" %d", &funcionario[i].Hora_Trabalhados); printf("\n\n"); //A Escrevendo no arquivo fprintf(file, "\t%s \t %s \t %.1f \t %s\t %d\n", funcionario[i].nome, funcionario[i].NIF, funcionario[i].salario, funcionario[i].categoria, funcionario[i].Hora_Trabalhados); } printf("\n\t\t-------------------------<3--------------------------\n"); printf("\n\t Incritos com sucesso! \n\n\t Registado no fecheiro -> funcionarios.txt\n\n"); pressioneEnter("\n\n\n\t\t\tPressione ENTER para Continuar->"); system("cls"); menu(funcionario, y); } fclose(file); // para fechar o arquivo } void menu(Funcionario funcionario[], int n) { int op; do { system("COLOR 0F"); //Menu printf("\n\n\t\t\t\t---> SISTEMA DE REGISTO E CONTROLE DE FUNCIONÁRIO \n\n"); printf("\n\t\t* 1 ------- INSERIR OS FUNCIONÁRIOS E ENVIA-LOS PARA O FICHEIRO ------------------------ *\n"); printf("\n\t\t* 2 ------- IMPRIMIR A LISTA DOS FUNCIONÁRIOS DO FICHEIRO ------------------------------ *\n"); printf("\n\t\t* 3 ------- IMPRIMIR OS FUNCIONÁRIOS POR CATEGORIA ------------------------------------- *\n"); printf("\n\t\t* 4 ------- GASTO DA UNIVERSIDADE COM OS FUNCIONÁRIOS ---------------------------------- *\n"); printf("\n\t\t* 5 ------- CALCULAR O SALÁRIO DE UM FUNCIONÁRIO X EM FUNÇÃO DO SEU SALÁRIO POR HORA --- *\n"); printf("\n\t\t* 6 ------- ORDENAR FUNCIONÁRIO NA ORDEM CRESCENTE ------------------------------------- *\n"); printf("\n\t\t* 7 ------- IMPRIMIR OS FUNCIONÁRIOS COM SALÁRIO MAIOR QUE 75000$ ---------------------- *\n"); printf("\n\t\t* 8 ------- ELIMINAR UM FUNCIONÁRIO A PARTIR DO Nº DO NIF ------------------------------ *\n"); printf("\n\t\t* 0 ------- Sair\n\n"); printf("\n\tEscolha uma opcao: "); scanf(" %d", &op); printf("\n"); switch (op) { case 0: printf("\t\t\t\t\t\t\t\t\t\t-> Saindo... \n"); pressioneEnter("\tPressione ENTER para Sair->"); system("cls"); break; case 1: system("cls"); InserirFuncionario(funcionario, n); break; case 2: system("cls"); ImprimirFuncionarios(funcionario, n); break; case 6: system("cls"); OrdenarFuncionario(funcionario, n); break; case 8: system("cls"); EliminarFuncionario(funcionario, n); break; default: system("COLOR C0"); printf("\n\t\t\t\t*-*-*-*-- ERRO --> Numero INVALIDO!\n\n"); printf("\n\tPressione ENTER para Tentar Novamente->"); flush(); pressioneEnter(""); system("cls"); } } while (op != 0); } void OrdenarFuncionario(Funcionario* funcionario, int n) { int i, j; Funcionario aux; for (i = 1; i < n; i++) { aux = funcionario[i]; for (j = i; (j > 0) && (aux.salario < funcionario[j - 1].salario); j--) { funcionario[j] = funcionario[j - 1]; funcionario[j] = aux; } } printf("\n\n\n\t------- LISTA DOS FUNCIONÁRIOS POR ORDEM CRESCENTE ------\n\n"); for (i = 0; i < n; i++) { printf("\n\tNome: %s", funcionario[i].nome); printf("\n\tNIF: %s", funcionario[i].NIF); printf("\n\tSalario: %.1f $00", funcionario[i].salario); printf("\n\tCategoria: %s", funcionario[i].categoria); printf("\n\tHoras de trabalho: %d horas", funcionario[i].Hora_Trabalhados); printf("\n\n----------------------------------------------------------\n"); } printf("\n\n\n\t\t\tPressione ENTER para Continuar->"); flush(); pressioneEnter(""); system("cls"); } void pressioneEnter(const char* prompt) { char c; if(prompt != NULL) printf("%s", prompt); do { c = getc(stdin); } while (c != 13); }; // pressioneEnter() // fim
-
Copiei seu programa. Pergunte algo objetivo e vou olhar logo mais
-
Como está seu programa agora? Ainda precisa de algo? Isso foi o que eu perguntei. 3 vezes agora desde antes do almoço. Poste o programa como está agora e alguma dificuldade que tenha. Se se interessou por algo dessas "discussões meio paralelas" mas não compreendeu simplesmente como um ato de vingança "invada" a discussão paralela e pergunte algo
-
Notou o que perguntei antes do almoço? Mas você tem razão se acha que seu tópico foi "invadido" por discussões meio estranhas. Vou parar. Escreva com a situação atual adicionado 0 minutos depois isso. @Andrah
-
? Fico em dúvida se está falando sério. Chamar uma variável local de buffer e usar scanf() para ler dela não mostra nada. O prefixo s é de storage, como deve saber, em sscanf() Você apenas leu tudo para uma área intermediária que aproveitou para chamar de buffer. O buffer de que se fala na literatura e é alvo de setvbuf() é uma área de armazenamento do sistema. Talvez pudesse falar de ungetc() que de fato existe e faz isso... PeekConsoleInput() é outro bicho BOOL WINAPI PeekConsoleInput( _In_ HANDLE hConsoleInput, _Out_ PINPUT_RECORD lpBuffer, _In_ DWORD nLength, _Out_ LPDWORD lpNumberOfEventsRead ); E permite inspecionar o buffer antes de ler. Não tem nenhum paralelo com o que está dizendo. Você usa isso na prática quando seu programa está fazendo algo em um loop. Seu programa single-thread, comum. E você precisa ler da entrada. Mas não pode ler da entrada porque vai parar o programa. Então você usa essa função para só ler quando sabe que tem algo. Pense em um game por exemplo. Ler tudo para uma variável local que você chamou de buffer é folclórico, mas é diferente. Acho que entendeu. Ou não? Só que você já leu. Aí vai apontar toda a leitura de seu programa para essa outra variável. Que até tem o nome de buffer. E criou uma nova camada com o mesmo problema. E se seu programa for multi-thread então pode ter consumido uma entrada que não era para o particular thread que leu o buffer. E aí vai ter que criar uma nova camada em seu programa para alimentar isso. Pense bem. Está mesmo falando sério ou só me testando...
-
Se você sabe como imprimir os nomes, trata-se de uma ação. Apenas troque o código pela sua ação... Talvez devesse postar o código... Que explicação ficou faltando sobre dirent? Ela só vai te oferecer a lista de nomes dos arquivos mesmo. E se você já tem a tal ação não entendi o que falta.
-
Nesse caso acho que não dá pra ficar com o que diz https://en.cppreference.com/w/c/io/setbuf Não está correto. De todo modo essa parte é importante: This function may only be used after stream has been associated with an open file, but before any other operation (other than a failed call to setbuf/setvbuf). A common error is setting the buffer of stdin or stdout to an array whose lifetime ends before the program terminates E essa Do mesmo lugar. Esse acho que é "o mapa da mina". E atente para o "may" e entenda que isso não afeta o sistema operacional e então buffers como o do terminal xterm podem atuar antes do buffer usado por stdlib / STL... Eu me lembro de casos onde setbub(0 ou setvbuf(0 era importante. E eram casos de comunicação serial ou via TCP ou X.25. Sim X.25 dos tempos muito pré-internet setvbuf() faz sentido quando você precisa adequar o buffer de um fluxo --- stream --- para alguma realidade. E muitas dessas realidades são a razão de usar C ou C++ hoje em dia. Buffers de comunicação com chips ou com mainframes ou com bancos de dados, programas de comunicação e coisas assim. Um exemplo meio off-topic mas que vai dar um contexto de onde se precisa de algo desse tipo: se alguém usa ou usou o comando dd no Linux ou mesmo no Windows, pode ter visto os parâmetros ibs, obs e bs que são os tamanhos dos buffers usados. Isso tem um efeito digamos dramático nos tempo s de execução ao você tentar copiar por exemplo um arquivo de muitos gigabytes de um lugar para outro. E é muito fácil de testar os parâmetros e ver o quando muda no tempo de cópia. Tente duplicar um pen-drive Linux de 64GB e escolha um buffer pequeno... Muito bem, dd trabalha com arquivos, foi escrito em C e é um candidato a usar setvbuf() com boa razão. setvbuf() e stdin, stdout e stderr Não há razão para usar setvbuf() com os fluxos padrão 0,1 e 2 a menos que eles estejam redirecionados. Mesmo que o compilador aceite e o programador fique feliz por ter feito uma alteração mais íntima no comportamento do sistema. Provavelmente é inócuo. Em geral programas em C de produção não falam com esses fluxos. Talvez stderr para gravar log em algum caso. Mas é preciso entender que stdin, stdout e stderr, pensando em programas interativos, são coisas de velocidade absolutamente irrelevante. Hoje um processador de computador doméstico tem mais de 1.5 bilhão de transistores, um telefone tem 4 ou 8 núcleos e roda milhões de instruções por segundo. Esperar por um prompt ou colocar algo numa tela é irrelevante. Você usa isso --- setvbuf() --- por exemplo se vai redirecionar a saída padão de um Arduino para um display LCD e quer o buffer próximo do tamanho do buffer que o LCD usa. Assim o sistema faz um flush() automaticamente dos dados quando a mensagem está completa, ou situações similares. não há razão para isso funcionar em 0, 1 ou 2. Nem mesmo se pretende desabilitar buffering totalmente porque o sistema provavelmente vai ignorar. É algo chato pra testar e não compensa. Eu ao menos não tenho essa motivação a menos de algum cheque Vejam por exemplo o que a IBM diz no compilador dos mainframes de hoje em dia (Em https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/rtref/setbuf.htm) Ou a Microsoft Claro, setvbuf() é uma dessas rotinas. Em programas de hobby ou de estudantes não há razão para perder tempo com isso. A menos que esses fluxos sejam redirecionados, como em programas de cópia de arquivos que podem ser grandes, ou programas que falam com chips ou periféricos como o exemplo de que falei --- Arduino, Raspberry Pi... Meu palpite apenas adicionado 2 minutos depois Como está seu programa agora? Ainda precisa de algo?
-
Mas você entendeu que no exemplo que mostrei mesmo usando scanf() esses valores podem ser lidos e consumidos, inclusive o <ENTER>, imagino? No exemplo de 1234azul<ENTER> para ler o int e uma string? que ao usar fgts() o '\n' é consumido e faz parte da string? que ao usar getc() o '\n' vai ser obviamente consumido porque é a única maneira de saber que o int acabou de ser lido? Afinal a unidade é o caracter. Eu entendo o que quer dizer. E eu imagino ter noção do que é uma analogia. Apenas tentei ressaltar o aspecto formal da coisa: o sistema tem o que foi digitado e não é possível simplesmente descartar algo. E não é exatamente lixo ou descartável. O sistema não sabe como isso vai ser consumido. E te mostrei os exemplos. Imagine a entrada padrão sendo redirecionada ou isso sendo gravado para ser lido de novo. Se você excluir esse '\n' vai interferir no programa. É.Na época eu estava experimentando uma mudança de plataforma: do mainframe rodando OS/MVS e VM/CMS para o Unix. Quando saiu o tal "livro branco"do C, O livro de K&R, The C Programming Language, era super novidade e havia uma grande expectativa me conseguir um compilador para rodar no PDP-11 que eu podia usar de noite, e que nem rodava Unix ainda.O livro chegou muito antes. Mas logo a gente conseguiu um. E era mais uma opção então. Como sempre, dependia da necessidade. Mas no IBM se usava mesmo COBOL e FORTRAN e Assembler às vezes. E no mini-computador que é como a gente chamava na época rodava Pascal, FORTRAN e aquela nova linguagem C. E o moderno era o Pascal. Eu até tinha o Pascal User Manual and Report do prof. Dijkstra. Tenho até hoje eu acho e ficava junto com o tal livro branco. C não era inicialmente levado a sério. Mas logo mudou. Isso é uma longa história. Mas hoje estamos voltando exatamente àquele paradigma, com tudo "na nuvem" e os usuários em "terminais". Embora os terminais hoje tenham muitos recursos. Mesmo a virtualização já estava bem presente nos '80 com o VM/CMS. Você deve imaginar o que era VM nessa sigla. E nos 80 já havia uma versão de Pascal que rodava em máquinas virtuais com código interpretado, chamado pCode. Desenvolvido pela UCLA. Qualquer semelhança com a jvm é porque era a mesma coisa. Você podia escrever Interfaces em Pascal e depois desenvolver a tal Implementation. Igualzinho. Nos '80. Seria legal eu ter lido isso numa revista ou na WikiPedia. Isso indicaria que eu não sou assim tão veterano. Mas é de memória mesmo
-
Você escreveu esse código? Isso roda? Não pode usar threads? Seria mais portável e não dependeria de usar Unix/Linux... De todo modo é um problema interessante. É o primeiro que vão fazer com isso? Não fez nada com pipes ou semáforos ou alguma estrutura de sincronismo? Vi que é o primeiro trabalho, mas não teve nada antes? Seu programa está ainda um pouco longe de funcionar eu acho.
-
Bem, acho que ficou claro o que eu queria dizer. Não é o caso de repetir. "Deve ser descartado" porque scanf() usou como delimitador e parou de consumir a entrada porque essa é a mecânica dessa função. E nesse particular caso, que nesses programas de estudantes é o mais comum, pode não mais ser lido. Se a leitura fosse feita via fgets() o '\n' teria sido consumido. Se a leitura fosse feita via getc() tudo seria afinal consumido. No próprio exemplo usando scanf() para ler o int e uma string se o valor vem 1234string<enter> o scanf() leria tudo normalmente. Inclusive o ENTER. Não se pode afirmar que ele deveria ser descartado porque depende do contexto. Mesmo que se use apenas scanf()
-
Vou dizer então algo. Repetir talvez. o tal '\n' não é lixo. Exemplo: Se você digitou 1234azul<ENTER> isso está lá no buffer do teclado. O sistema não sabe como você vai ler. E você não leu ainda. Pode usar Peek e ver o que está lá, como eu disse. Não vou postar um exemplo aqui porque isso funciona bem com uma tela dinâmica onde você vê o buffer sendo consumido. Se eu postar um programa o leitor teria que rodar na máquina dele e suspeito que muitos sequer terminem de ler isso, quanto mais rodar um programa... Mas se alguém disser que vai ler/rodar eu escrevo um. Vou repetir: scanf() foi feita para... scan formatted input: ler entrada formatada. E é uma função genial, Economiza horas. Em coisas como ler um arquivo csv por exemplo, aqueles com campos separados por vírgulas. O teclado não é isso. As pessoas são incrivelmente criativas ao digitar, como se sabe. Depois vou mostrar um exemplo curto. De volta ao caso: o cara digitou isso: 1234azul<ENTER> e o sistema não sabe o que fazer com isso. Se você usou por exemplo: scanf("%d", digito); Então scanf() vai pegar os dígitos e ao encontrar o 'a' vai se dar por satisfeita. Não vai ler o 'a' porque não é pra ela. Podia ser o <ENTER>. Estamos falando de um sistema operacional. Se a próxima leitura for scanf("%s", linha); Adivinhe o que ela vai ler para a suposta string linha... Sim, vai ler "azul" e o buffer vai ficar vazio. Só alegria. Pergunta: e se o usuário queria de fato digito = 1234 e linha = "" (em branco) ? ia digitar o que? 1234<ENTER> Vai funcionar? Não. E aí mais um momento de fúria para o infeliz aluno. No mesmo exemplo Por outro lado, se o programa tivesse chamado fgets() para ler e não scanf(), o sistema não sabe nada disso. O buffer é o que está lá: 1234azul<ENTER> Usando fgets() char linha[80]; printf("[(fgets()] Entre com o numero e tecle ENTER: "); fgets(linha, 20, stdin); printf("fgets() leu %d caracteres\n", strlen(linha)); for (int i = 0; i < strlen(linha); i += 1) printf("%d ", linha[i]); printf("\n"); veja E lá está inclusive o <ENTER>, aquele 10 também conhecido por '\n' e nesse caso o <ENTER> que você disse que era lixo está aí e foi lido. Muito iniciante fica furioso porque fgets() lê o '\n' e coloca no fim da string porque pensa no imediato que é usar em um printf() mas os caras que escreveram isso é que são espertos: o tal <ENTER> faz parte da string e não do próximo campo a ser lido e simplesmente descartar seria uma decisão que poderia quebrar outros programas. E deixar lá é o que scanf() faz. A escolha é e tem que ser de quem lê. O '\n' não pode sumir. Exemplo: Você quer ler dois int. scanf() não foi feita para ler coisas do teclado, como eu já disse. Até o nome dela mostra para que foi escrita. Mas aparentemente os instrutores não gostam dos alunos ou querem que eles sofram e então ensinam a ler usando scanf(). Dez linhas de código depois e tem que explicar o que o infeliz que está tentando aprender ainda não tem fundamento para entender: às vezes tem a p$%%a do '&'. Às vezes não. Às vezes é um ponteiro às vezes não e o instrutor sequer qualificou direito o que é um ponteiro. Uma string é um endereço, um int precisa de &. Um inferno. Imagine um aluno do tipo que quase não existe: ele vai ler o manual e vê que scanf() tem uma máscara, como printf() com %isso ou %aquilo. Isso se chama especificador e eles são desa forma: %[*][tamanho][modificador]tipo Sério? E que eles tem uma série de "truques". E mesmo algumas coisas funcionam diferente do que está escrito, dependendo de você usar esse ou aquele compilador. É difícil entender isso. Porque é difícil mesmo. É para deixar o cara furioso. O simples fato de ler um char com %s e não %c cancela o programa do aluno. Você pode teclar duzentos ENTER na leitura do tal int e o programa zoa toda a tela. E o infeliz aluno caprichou para montar os prompts daquele cadastro chato com 5 campos e tal... Um espaço por engano na tal máscara pode zoar tudo. Ou pode ser a solução porque vai pular os espaços e seu programa vai cancelar porque o cara digitou uma letra. Aí alguém te diz que você pode usar uma lista de caracteres válidos ou inválidos, uma expressão regular como [^abcd] que tudo vai funcionar. Sério? Expressões regulares, ponteiros, espaços significativos? Pobre estudante. Não, scanf() não é para isso. Eu posso escrever uma expressão regular de meio metro, uma chamada a scanf() com 8 especificadores e fazer pose de guru, eu sei que é esperto tratar o retorno de scanf(). Posso citar várias possíveis máscaras para minimizar ou até resolver boa parte dos problemas. Mas é o meu caso. Eu programava em C nos anos 80 e já dizia isso. Mas e daí? Eu acho que não é o caminho. scanf() é frágil para isso. Ainda mais se você não trata o argumento de retorno, o que ninguém faz porque acho que ninguém ensina. De volta ao exemplo Mas então você escreve lá o simples printf("Entre com o numero e tecle ENTER: "); scanf("%d", &digito); printf("scanf() leu '%d'\n", digito); printf("\n"); printf("Entre com outro numero e tecle ENTER: "); scanf("%d", &digito); printf("Leu %d\n", digito); Normal certo? caso 1 Certinho! Muito bom. caso 2 E zoou tudo. Podia ao menos ter lido o 2 para o segundo número, né? Mas não leu e ainda passou reto pela segunda leitura. Isso não é lixo no buffer. É algo que foi teclado. O sistema não tem como saber o que é importante ou não. Com cuidado é possível usar máscaras com scanf() que descartam o fim da linha mas com o tempo fica claro que é melhor ou ler linha a linha com fgets() e tratar no programa, ou ler letra a letra com getc() e fazer a mesma coisa. Num programa o infeliz que está aprendendo quer ter controle e assim é muito mais simples. Você lê o que está lá. E trata. caso 3 Claro que a Apple diria que o usuário não soube usar o equipamento. Mas o cara teclou um monte de enter, um a depois o 12 e o sistema até leu o 12. E zoou toda a tela. E aí o cara quer aprender a usar o cursor, limpar a tela, usar coisas como posicionar o cursor e tal. Mas o problema não era esse. Ou era? Na prática o que a gente quer é ter controle. scanf() não é para isso no caso do teclado. O simples é ler tudo como string via fgets() ou tudo como char via getc() e seguir de acordo. Em alguns casos até usar PeekConsoleInput() no Windows. No Linux e no Mac acho que não tem equivalente. Ler tudo como string é o que faz o runtime para seu programa por exemplo, ao montar a lista de argumentos argv. E se sabe que funciona. Ler letra a letra é o mais seguro mas pode ser chato claro. Mas a lógica é a mesma de scanf() mas dentro do seu programa: você define por exemplo um conjunto de teclas possíveis, aceita só aquelas. Pode soar um beep quando não for o que você quer. E escreve uma função para cada caso. Ex: para ler um telefone você pode aceitar os dígitos e espaços e traços. Pode ter um '+' mas só no início e tal. Pode aceitar as letras como estão no teclado e substituir. Mas não vai aceitar outros símbolos. Para ler um inteiro pode ter um sinal, para ler um CPF você já pode ir calculando os dígitos enquanto lê. Em muitos casos você tem valores pré-existentes e pode mostrar uma lista deles, como nas pesquisas na web. Nada original. Na interface gráfica você cria um campo e o sistema tem umas regras de edição e você cria um botão que aceita o valor por exemplo. Mas num jogo é definido um universo de teclas e apenas essas. Não por acaso os computadores de crianças tem umas teclas mais gastas que as outras... Ou se pode usar scanf() Recomendo ao menos ler o valor de retorno... Resolve talvez metade dos problemas, porque muitas vezes scanf() não lê nada e diz que não leu nada, mas o programa "não ouve" e passa adiante... Como no exemplo acima
-
que significa? O que seria o "tecnicismo"?
-
while(n > 0) { printf("Numero digitado %d\n", n); } O que está escrito em seu programa: enquanto n for maior que zero imprima n e aí o seu programa, se n for maior que zero, fica imprimindo sem parar? Parece justo. Pode não ser o que você pretendia, mas certamente foi o que escreveu.
-
Tenho feito uma campanha aqui para explicar isso em meio milhão de tópicos. Não se trata de sujeira. E não é lixo de memória. São valores que foram digitados. Em geral tudo começa --- e muitas vezes termina --- pelo '\n' que encerrou a última leitura se você usa scanf(). Entenda que se o usuário entrou com 1234>ENTER> para entrar com um int e você usou scanf() para ler, quando você ler isso vai ter o seu int com 1234 e no buffer de entrada vai estar lá o solitário <ENTER> ou '\n' esperando para ser consumido. E é esse valor dependendo da máscara que usou em scanf() numa próxima leitura, que vai zoar toda a entrada: scanf() vai pegar esse <ENTER> e dar por resolvida a próxima leitura, Só que não leu nada e como parece que tem uma lei que impede tratar o retorno de scanf() ou usar outra rotina para ler do teclado --- a confusão está feita. Se você vai ler vários campos então vai zoar tudo.... scanf() não foi escrita para isso. E o valor de retorno é para ser usado. Se não fez sentido o que eu expliquei, experimente no Windows usar PeekConsoleInput() que mostra o que tem no buffer da console ANTES de você ler, ou pergunte e tento mostrar um exemplo melhor.
-
Não é uma boa definição. E não funciona para stdin. Alguns compiladores fazem isso mas o padrão da linguagem estabelece claramente que fflush() só está defindo para fluxos --- streams --- de saída e que o comportamento para o caso de streams de entrada é indefinido. O propósito de fflush() não é limpar nada: é enviar as coisas que estão esperando para ser enviadas. Isso acontece porque o sistema, por razões de eficiência, usa buffers e armazena valores em buffers para enviar quando achar que é hora. E às vezes você quer que descarregue --- flush --- numa certa hora ao invés de ficar esperando. E aí usa fflush() que não vai limpar nada. Vai transmitir. Como um printf() por exemplo. Se não entendeu pergunte de novo e mostro um exemplo mais elaborado. E no caso de stdin --- o fluxo padrão de entrada --- não se está falando nem de memória nem de "lixo". O que você quer fazer é ler e desprezar o que tem no buffer de teclado PORQUE ALGUÉM TECLOU e descartar. Em geral o que você quer é apenas ler e descartar o '\n' que encerrou a última leitura. E talvez alguma bobagem que o usuário digitou num scanf() para ler um número. Mais uma vez, se não entendeu pergunte de novo e mostro um exemplo mais elaborado. Uma rotina como essa abaixo teria o efeito que você quer e não dependeria de estar usando um certo compilador void flush() { int ch = 0; do { ch = getc(stdin); } while ((ch != '\n') && (ch != EOF)); }; // flush() scanf() é int scanf(const char *format, ...) scanf() retorna um int com o número de itens lidos. Use. É melhor para você e leva a programas mais sólidos... scanf() é uma rotina "ativa" que pode "comer" linhas e linhas de sua entrada por exemplo. E na verdade não escrita para ler valores do teclado. Foi escrita por um grande programador e para ler entrada formatada. scan formatted input era o objetivo e deu o nome a ela
Sobre o Clube do Hardware
No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais
Direitos autorais
Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais