-
Posts
6.526 -
Cadastrado em
-
Última visita
Tipo de conteúdo
Artigos
Selos
Livros
Cursos
Análises
Fórum
Tudo que arfneto postou
-
Apenas percorra a árvore, in-order e você vai receber os nós em ordem crescente. E aí apenas mostre os nós que tenham ao menos uma das árvores descendentes não nula, pulando os outros adicionado 0 minutos depois isso quer dizer apenas testar os dois ponteiros para os descendentes
-
C Trabalho : Criando um cofre virtual em linguagem C
arfneto respondeu ao tópico de Duarte2020 em C/C#/C++
Não tenho a pretensão de julgar minha própria postura. Esse é um forum de C, C# e C++, e tomo a liberdade de julgar essas coisas aqui, C, C++ e C# e técnicas associadas, estruturas de dados, sistemas operacionais, protocolos de comunicação e coisas assim. Se algo em relação à postura aqui de alguém me incomoda eu posso escrever algo no post, como fiz aqui com esse tópico. Ou posso escrever para o usuário, como também já fiz. Ou me queixar aos moderadores. Nada que envolva muito tempo ou pensar muito. Ou posso ser alvo dessas coisas, claro. Exemplo Tempos atrás durante uma folclórica discussão sobre o que seriam arquivos csv --- Um formato de intercâmbio consagrado há décadas e incorporado a produtos como Oracle DB, Excel, MySQL, Google Sheets, Lotus 123 e VisiCalc e todos os programas de mala direta do planeta --- um usuário, ao mostrar sua distinta convicção sobre esse assunto, me dirigiu uma mensagem dessas que julguei exagerada. Eu me queixei aos moderadores e a mensagem foi removida em como 15 minutos. Curiosamente era uma mensagem sua para mim @Mauro Britivaldo desfazendo de algo técnico que eu havia escrito e terminado por algo como "só rindo mesmo". Não sei julgar o que é senso comum. Descartes, o filósofo, escreveu na abertura do Discurso sobre o Método: Programas que funcionam também são às vezes ruins. Programas bem escritos por vezes não funcionam. Muitas vezes vemos programas bem escritos aqui --- a bem da verdade muitos podem ter sido copiados --- e que não funcionam. Já estive dos dois lados, escrevendo programas que acabaram ruins para substituir programas bem escritos e vice-versa. Como eu disse, recomendo humildade ao receber críticas que sequer são pessoais, em especial para quem está aprendendo ou expondo uma dúvida. Ouvir que algo não está bom --- e ler uma explicação grátis e voluntária logo a seguir de porque não está bom --- não devia ser uma situação conflitante, mas é só minha opinião. Escrevo sistemas há cerca de 40 anos e já vivi muitos desses cenários. Em especial quando há uma hierarquia e dinheiro envolvido pessoas são às vezes cruéis até. Mas não acho que seja o caso de um forum moderado. -
C Trabalho : Criando um cofre virtual em linguagem C
arfneto respondeu ao tópico de Duarte2020 em C/C#/C++
Provavelmente baixou depois de 2011, certo? apenas faça como está escrito na mensagem. Nas opções do compilador acrescente aquele parâmetro use option -std=c99, -std=gnu99, -std=c11 or -std=gnu11 to compile your code O forum é moderado. Você e/ou o autor podem se queixar usando o botão "denunciar". Recomendo ler o que postei no tópico #5 e quem sabe perceber até onde eu fui para ajudar o autor, mesmo depois da resposta dele e que tem o tom da sua. Eu postei várias opções de como resolver o problema. Expliquei em português, com detalhes. Mostrei programas, opções e resultados. Vou reproduzir um pedaço do parágrafo inicial apenas Acho que leu o que o autor escreveu Outros leitores não tem a mesma ideia. Veja o tópico seguinte @Mauro Britivaldo sugiro atentar para todo o conteúdo que eu postei nesse tópico, mesmo apesar de eu em particular ter achado grosseira a reação do autor e recomendar a todos uma certa humildade quando se está prendendo. Eu de fato julguei o programa ruim e tenho dito isso para muitos programas. Eu estou trancado em um escritório com vários computadores há semanas e tenho tido tempo para escrever em vários forums, voluntariamente. E tenho aprendido umas coisas de gente que diz que MEU programa está ruim. E eu agradeço de boa. Porque economiza meu tempo sempre que acontece -
Onde arrumou aquele trecho de programa então? É o enunciado? Nunca escreveu um programa em C? Tem um livro?
-
*str não é um ponteiro. Se str for um ponteiro então *str é o conteúdo. Essa distinção é essencial. No seu exemplo *str é um char e por isso se pode escrever (*str == ' ') Muito dessa confusão vem do fato de alguns (poucos) autores --- e muitos instrutores no BR pelo que vejo --- usarem esse estilo de declaração. Schildt infelizmente é um dos poucos autores que faz isso. Quando você declara uma variável está declarando um nome e colocar um * lá no meio ajuda a gerar confusão. Em especial quando se declara mais de uma variável na mesma linha, como int a, b, *c, coisa = -1; onde você declara 4 inteiros. Mas veja que nesta linha está declarando c e não *c Outros autores mais modernos e formais já indicam há décadas declarar uma variável por linha, em especial para iniciantes, e declarar o tipo do lado esquerdo e a variável do lado direito. Schildt escreve desde os '80 sobre C mas não compartilha dessa ideia. A razão da recomendação é formal e simples: veja no exemplo do livro que str é um ponteiro para char. Então qual o tipo a declarar de str? char*. Formalmente está declarando str e nunca *str Mas e o const? char* strA; const char* strB; Deixando assim claro que a variável é strA ou strB e são ambas ponteiros para char, a segunda declaração indica ao compilador que o valor NÃO pode ser alterado. Exemplos int N = 12; // 1 int* p = &N; // 2 const* pI = &N; // 3 const int* const pcI = &N; // 4 int* const pccI = &N; // 5 Veja esses exemplos e entenda que [1] N é int e vale 12 [2] p aponta para N então *p é um int e vale claro 12 [3] pI aponta para N e *pI vale 12. Mas como é const você não pode alterar o valor de N através dele. Mas você pode fazer pl apontar para outro int [4] pcI aponta para N e *pcI vale 12. Mas como é const você não pode alterar o valor de N através dele. E como é um ponteiro const você também não pode fazer pcI apontar para outro int [5] pccI aponta para N e *pccI vale 12. Você pode alterar o valor de N através dele. Mas você não pode fazer pccI apontar para outro int O particular caso de const char* O caso de char* é importante. Postei algo sobre isso ontem aqui mesmo eu acho. No exemplo do livro, se você declara void dash(char* texto){}; Dentro de dash() se pode escrever por exemplo if(texto[0] == 'a') texto[0] == 'A'; E nada tem demais. Converte um eventual 'a' na primeira posição para 'A'. No entanto se você chamar: dash("Problema"); seu programa já era. Na hora em que ele estiver rodando, quem sabe na máquina do professor ou do cara que te pagou pra escrever isso... too bad for you Mas se você declarar void dash(const char* texto){}; E tentar escrever aquele if() o programa não compila e o erro não vai poder aparecer depois. Tem outras razões também: ao saber que a área é constante o compilador pode otimizar várias coisas em relação a essa variáveis, sabendo que elas não vão mudar durante todo o tempo de vida da variável. O exemplo nada tem a ver com const. Rodou isso em seu computador?
-
Essa é uma expressão curiosa. gerar já estava bem, criar já estava bem. E se o programa vai ser executado num primeiro momento para gerar as cópias então se pode imaginar que todos menos 1 serão "filhos" do primeiro. A diferença entre eles é que o pid do pai é 0 para o próprio. Depois disso eles são o mesmo então basta somar se o ppid for diferente de zero
-
Não me leve a mal, mas talvez você devesse ver essas coisas de outro modo. Ainda pode ser cedo para você diferenciar "essa droga" de algo que você ainda não entende direito. streams são orientadas para texto mesmo. Por definição. E operam com buffers para eficiência. E são mesmo eficientes. Mas podem trabalhar com bytes. Não bits Aparentemente copiou seu programa do exemplo postado em http://www.cplusplus.com/reference/istream/istream/read/ e digitou em cima Mas talvez nem precise disso. Vou te mostrar outro exemplo, que eu escrevi agora mesmo, e é quase igual porque é pra fazer a mesma coisa Rode em sua máquina. O exemplo: copie [entrada] [saida] Claro que 'copie' é o nome do programa. E ele copia da entrada para a saída. Os dois parâmetros são opcionais, então você pode usar copie // tenta copiar 'teste.png' para 'copia.png' copie azul.txt // tenta copiar azul.txt para 'copia.png' copie azul.txt verde.bmp // tenta copiar 'azul.txt' para 'verde.bmp' O simples: se não der nenhum parâmetro na linha ele procura 'teste.png' no diretório corrente e copia para 'copia.png' no diretório corrente. Mas copia qualquer arquivo já que opera em fluxos --- streams --- binários. Como o exemplo que usou, aloco um buffer de tamanho variável. No caso 64k = 65536 bytes. Entenda que streams já operam com buffer então provavelmente estaria bem lendo byte a byte. Então o programa copia o arquivo de entrada para o arquivo de saída, em blocos de 64K. Ao final libera o bloco e fecha os arquivos Veja o loop de cópia: while (!in.eof()) { in.read(buffer, bloco); if (in.gcount()) { // leu algo cout << in.gcount() << endl; total = total + in.gcount(); out.write(buffer, in.gcount()); }; // if() }; // while() in.close(); out.close(); delete[] buffer; O simples. No seu caso ao invés de só copiar o conteúdo de buffer igualzinho para a saída você cria uma função de compressão e passa o resultado dela para o write. Algo assim int comprime(char* in, unsigned N, char* out); E escreve, supondo que comprime retorna o tamanho do buffer comprimido out.write( outro_buffer, comprime(buffer,in.gcount(),outro_buffer) ); Ou faz algo mais elaborado gravando em blocos na saída também. Porque 'teste.png'? Porque eu quis. Era um arquivo binário que tinha na minha pasta agora que eu fiz o programa. Mas o programa aceita parâmetros na linha de comando então copia de A pra B qualquer coisa. teste.png tem 109.080 bytes Rodando o exemplo 65536 43544 Copiados 109080 bytes de 'teste.png' para 'copia.png' O exemplo #include <iostream> #include <fstream> using namespace std; int main(int argc, char** argv) { constexpr std::streamsize bloco = 65'536; // 64K char* buffer = new char[bloco]; ifstream in; ofstream out; std::string entrada = "teste.png"; std::string saida = "copia.png"; if (argc > 2) saida = argv[2]; if (argc > 1) entrada = argv[1]; unsigned long total = 0; in.open( entrada, ios::binary | ios::in); if (!in) { cout << "Erro tentando abrir " << entrada; return -1; }; // if() out.open(saida, ios::binary | ios::out | ios::trunc ); if (!out) { cout << "Erro tentando criar " << saida; in.close(); return -2; }; // if() while (!in.eof()) { in.read(buffer, bloco); if (in.gcount()) { // leu algo cout << in.gcount() << endl; total = total + (long) in.gcount(); out.write(buffer, in.gcount()); }; // if() }; // while() in.close(); out.close(); delete[] buffer; cout << "Copiados " << total << " bytes de '" << entrada << "' para '" << saida << "'" << endl; return 0; }; É só um exemplo, sem qualquer pretensão de eficiência e tal. Espero que ajude.
-
C Trabalho : Criando um cofre virtual em linguagem C
arfneto respondeu ao tópico de Duarte2020 em C/C#/C++
Talvez não tenha lido a mensagem antes de copiar aqui... primeiro teria que compilar. Aí gerar um executável que você pode por exemplo levar para outra máquina e executar lá Pois é. Você postou essa mensagem em 2020. 1999 passou todinho. 2011 também. E você está usando um IDE configurado para a versão de C de 1998, algo como 22 anos atrás. Deve haver um bom número de razões para você usar versões mais modernas de C ou C++, liberadas nos últimos 22 anos. E um IDE mais moderno talvez. Seu IDE não mostrou também a clássica mensagem também, dizendo exatamente o que você deve fazer? Não tem uma versão em português? Apenas inclua exatamente o que está escrito aí, nas opções do compilador: -std=gnu11 por exemplo -
Você não vai "manipular os bits do arquivo". Vai procurar ler grandes partes do arquivo e vai manipular as variáveis na memória, por eficiência. Ainda que pudesse ler bits ainda seriam em campos conhecidos como variáveis. Usar streams é uma opção. Claro que não pode ler arquivos com ofstream, certo? Apenas ifstream. Não precisa necessariamente usar streams. Pode usar fopen() mesmo. O algoritmo que vai usar vai determinar como é melhor ler. Se vai compactar em blocos, tipo z-modem 8K nos anos 90, RLE, zip... De todo modo vai alocar buffers, arrays de tamanho adequado para ir montando a saída. E vai declarar buffers de entrada onde vai ler um número possivelmente maior de bytes, bem maior. E vai usar ponteiros para ir navegando na entrada e gerando a saída conforme os blocos compactados forem ficando prontos. Estou escrevendo de memória e espero que faça sentido. O simples é criar uma classe, digamos Compacta, e no construtor pode declarar os arquivos de entrada e saída e algum parâmetro eventual de configuração e campos de métrica, que é o que geralmente se faz.
-
C Na atribuição de um float = float + int/int;
arfneto respondeu ao tópico de Luiz Paulo Escobar em C/C#/C++
int main() { int n, i; float s; i = 1; printf("digite o N: \n"); scanf("%d", &n); do { s = s + 1/i; i++; } while (i <= n); printf("\nO S é: %.2f ", s); return(0); } Nesse primeiro caso começou errado ao tentar usar s do lado direito sem ter um valor inicial definido. Não deve ter compilado já aí. Não pode escrever s = s + 1/i; se ao entrar no loop o valor de s não era conhecido. Se i é inteiro como declarou e 1 é inteiro a divisão (1/i) vai ser feita considerando DOIS inteiros e vai dar 0,1 ou -1, certo? Só que você quer a fração. Então pode escrever por exemplo 1./i e terá uma divisão de float por int. Apenas colocando o ponto lá vai indicar de 1 é double, o float longo mas float. Talvez tenha um warning do compilador por isso. Mas vai funcionar. Ou pode escrever 1.f/i e assim oficialmente declarar 1.0 como float e não double. Ou pode converter o i usando um cast: 1/(float) i . Essa conversão explícita se chama cast e tem sempre esse formato em C ou C++. Pois é. Uma constante inteira não serve. devia ter declarado float. Sim. É perfeitamente possível. No entanto divisão de inteiro por inteiro dá um outro inteiro. E vai truncar os valores para o menor inteiro. Se for isso o que quer não há problema. Mas o compilador não vai saber quando você quer isso como fração e aí você deve usar uma das maneiras que te mostrei. -
C Função para cálculo de volume de uma esfera
arfneto respondeu ao tópico de DanielSantDev em C/C#/C++
Não entendi a razão dos #define e #if. Sua função deve retornar algo ou não servirá de nada. Quando você escreve result=esfera(raio); está imaginando que a função retornou um resultado. E curiosamente a função até tem uma variável float resultado, dentro dela. E tem o cálculo. Mas nada retorna. E assim que passar pela '}' na função aqueles valores deixam de existir. Pode usar assim float esfera(float x) { float resultado; resultado=(4*3.14((x*x)*x))/3; return resultado; } ou talvez algo mais simples como float esfera(float x) { return (4*3.14((x*x)*x))/3.; } Cuidado: não é '\' -
Eu não pretendia apresentar uma solução. em princípio. Tentava explicar uma aproximação para esse tipo de problema. Passou a fazer sentido mostrar o que eu tinha escrito depois do que eu expliquei e do que você questionou. "um pouco mais trabalhosa" é algo curioso. O autor do tópico apresentou um código mas estava em busca de uma solução. E o mais remotamente próximo de uma solução seria o que você postou? Alguns parágrafos de texto e umas telas de execução de algum programa que não apresentou? Isso parece competitivo, de novo, afinal é uma comparação. "um pouco menos trabalhosa" disse você. E se for o caso nem adianta. Você sequer apresentou uma solução, e não frequento o forum para competir. E você provavelmente não seria um oponente, fosse eu fazer isso. Você podia se expressar um pouco mais claramente, ou eu poderia ter uma compreensão mais criativa de suas construções verbais. Se está apenas tentando contradizer o que eu disse porque a chamada a scanf() que mostrei tem dois especificadores não entendo a relevância. De fato se "usa scanf() para devolver um número e aí se aplica o operador" como eu disse. O delimitador indica como prosseguir. Não parece relevante, assim como o fato de ter mais de 10 linhas ou não. O loop de controle no programa que mostrei é esse while ((n = scanf(sc_operandos, &operando, delim))==2) { res = opera(arq[0], operando, res, total); //printf("Operando %d: %d\n", 1 + total, operando); total += 1; if (delim[0] == '\n') break; }; e tem o sentido bastante claro e legível. Escrevi para iniciantes. E como planejado a chamada a scanf() devolve os operandos uma um. opera() é apenas um seletor de operando e eu mostrei que não precisaria estar aí, mas poderia. Postei o código sem a função também. Não sei onde você quer chegar. Eu escrevi e mostrei o que eu pretendia: uma opção usando essa rotina --- que eu não recomendo para isso --- e como usar em casos mais genéricos. Se está remoendo o fato de ter mais de 10 linhas ou de eu ter usado o delimitador para dirigir a próxima chamada a scanf() essa é uma técnica comum na prática. Espero ter ajudado alguém em algo
-
Eu te expliquei: é difícil ver exemplos de scanf() para esse tipo de caso do modo como eu expliquei. E por isso EU expliquei. Isso aqui é para ajudar mais pessoas. Pode ser útil para mais pessoas. Até você, que nunca tem dúvidas, poderia até de repente aprender algo. E eu também. Não é uma competição. É uma colaboração. Eu ao menos não iria competir exceto se pago. Não estou escrevendo somente para o autor. Minha intenção era explicar como usar scanf() para consumir a entrada com argumentos variáveis, o que você postou depois de eu ter escrito. Mas você não postou um programa que fizesse algo, apenas 3 linhas. Há grande diferença entre um post e outro. Pois é: não estou competindo com você ou ninguém. Mas postei detalhes, códigos e argumentos mais genéricos e que podem servir para outros casos Esse programa por exemplo trataria um linha com operador e um número arbitrário de operandos #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main(int argc, char** argv) { char operador[80]; char delimitador[4]; int n = scanf("%[+-/*]%c", operador, delimitador); if (n != 2) return -1; int operando = 0, total = 0, res = 0; while ( (n = scanf("%d%c", &operando, delimitador)) == 2) { // le e opera switch (operador[0]) { case '+': res = res + operando; break; case '-': if (total==0) res = operando; else res = res - operando; break; case '*': if (total == 0) res = operando; else res = res * operando; break; case '/': if (total == 0) res = operando; else res = res / operando; break; }; // switch() total += 1; if (delimitador[0] == '\n') break; }; if (total > 0) printf( "%d\n", res); return 0; }; // fim E mostraria para algumas testes + 1 2 3 4 teste 10 - 10 1 1 1 1 6 ---- * 1 2 3 4 5 120 ---- / 64 2 2 2 2 4 ---- / 64 64 Inicialmente havia uma função no loop e era algo assim while ((n = scanf(sc_operandos, &operando, delim))==2) { res = opera(arq[0], operando, res, total); total += 1; if (delim[0] == '\n') break; }; e é o loop de controle mesmo. O único. Era mais legível. E a função opera() era basicamente a operação em si. Mais legível que o código acima, e menos útil que o código original que era genérico sobre o uso de scanf() e tinha mais mensagens de acompanhamento int opera(char op, int A, int B, int ind) { // executa a operacao e retorna o total switch (op) { case '+': return(A + B); break; case '-': if (!ind) B = A, A = 0; return(B - A); break; case '*': if (!ind) B = 1; return(A * B); break; case '/': if (!ind) B = A, A = 1; return(B / A); break; }; // switch() return 0; }; // opera()
-
Isso é um exemplo e muita gente parece não entender scanf(). É mais útil como exemplo assim como escrevi "para controlar o loop". Talvez não tenha lido direito. Na verdade na solução que escrevi tem 5 linhas apenas. porque eu deixei a operação em uma função que tem umas 15... Mas não achei importante. E a função não controla o loop.
-
Pense bem, @Mauro Britivaldo o loop do programa que te mostrei vai trazer os operandos um a um.... E depois de ler o operador. Como você pode escrever que "nada tem a ver"? Pense mais. Eu só não quis postar uma solução para o problema mas achei que estava óbvia uma solução aí. Eu até escrevi tal solução, neste mesmo loop. Só não postei porque não vi solução do autor ou de ninguém aqui e escrevo para ajudar e não para aparecer. Espero que você tenha entendido o exemplo que postei e já terei ajudado. Usando esse loop a solução só não é absolutamente trivial porque a divisão precisa de um tratamento ou convenção diferente. Depois eu posto o código adicionado 2 minutos depois bem mais o que? um programa de 1 loop e 30 linhas não tem lugar pra muita coisa
-
Hum... Essa não é uma dúvida de C ou C++ ou C#. Seria para o forum de matemática e ensino fundamental: dividir um número positivo por outro jamais vai mudar o sinal...
-
não precisa ser uma função, mas é mais fácil assim Não precisa ser uma função. Pode programar isso em qualquer linguagem. É um algoritmo. Divide e vê em que metade está. Aí divide de novo até encontrar... Por isso deve estar ordenado. Talvez não devesse postar um link pra eu ou alguém ir acessar atrás do que é sua dúvida e pudesse apenas postar o enunciado você, aqui mesmo De todo modo, se precisa pesquisar num conjunto de casas ou encomendas e o conjunto for relativamente grande usar sort e busca binária não é uma opção incomum.
-
Precisa escolher o campo e classificar. Busca binária só funciona em conjuntos ordenados. A partir daí é só dividir e procurar e dividir...
-
não faz sentido. Que seria "passasse pelo zero" ? Na hora de rodar o while() a expressão é avaliada. Seja o que for. ZERO é falso. Só zero.
-
exato. É o que eu sempre tento explicar. Entrada pelo teclado é tudo menos isso. É o que o americano chama de free-form. O usuário pode digitar qualquer coisa. E já sai na tela! E move o cursor! E aí já era... scanf() é perfeita para coisas como consumir formulários, tabelas, arquivos csv e foi escrita para isso. Você já deve ter lido aqui quando eu escrevo sobre isso: scanf() significa scan formatted input. E vem desde os tempos em que ela residia na pasta /usr/bin do diretório do Ken Thompson na Bell. Nenhum programa de produção usaria scanf() para ler do teclado, porque é preciso ter controle do que está entrando. O que se faz é em geral ler letra a letra e não mostrar antes de ver se é o esperado. Ou com algum risco ler uma linha por vez. Sobre esse caso aqui por exemplo, veja uma possível aproximação com scanf() que vou deixar: O resultado antes: Entre operador [+-*/]: + Operador lido: '+' Lendo operandos: -1 2 -3 4 5 -6 7 8 9 -10 clube Operando 0: -1 Operando 1: 2 Operando 2: -3 Operando 3: 4 Operando 4: 5 Operando 5: -6 Operando 6: 7 Operando 7: 8 Operando 8: 9 Operando 9: -10 Lidos 10 operandos Para esse programa #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main(int argc, char** argv) { char arq[80]; char delim[4]; // delimitador int n = 0; const char* sc_operador = "%[+-/*]%c"; const char* sc_operandos = "%d%c"; printf("Entre operador [+-*/]: "); n = scanf( sc_operador, arq, delim); if (n != 2) { printf("Nao conseguiu ler operador\n"); return -1; }; printf("Operador lido: '%c'\n", arq[0]); int oper = 0; // operador int total = 0; printf("Lendo operandos: "); while ( (n = scanf( sc_operandos, &oper, delim)) == 2 ) { printf("Operando %d: %d\n", total, oper); total += 1; if (delim[0] == '\n') break; }; printf("\nLidos %d operandos\n", total); return 0; }; Não vou explicar linha a linha. Me pergunte se não entender algo. Escrevendo assim se pode ler o operador e depois ler todos os parâmetros na linha, e contar o total deles. Seria bem suficiente para um estudante ou um programa de teste. E até aceita alguns casos limite, como Entre operador [+-*/]: -*/-/-*+ Operador lido: '-' Lendo operandos: 101 233 3455 azul Operando 0: 101 Operando 1: 233 Operando 2: 3455 Lidos 3 operandos Caso em que o cara digitou vários operadores, e digitou "azul" ao final da linha Deixei os especificadores usados para scanf() no início do programa, para facilitar alterar e para poder ve-los juntos aqui, ao invés de deixar embutidos lá nas chamadas Sobre os especificadores para scanf() aqui const char* sc_operador = "%[+-/*]%c"; const char* sc_operandos = "%d%c"; Um especificador é algo que começa por % e não tem um % a seguir então aqui nos dois casos tem dois deles. Então isso é o que scanf() vai sair furiosamente tentando consumir da entrada, seja um vetor --- sscanf() --- arquivo ---fscanf() --- ou mesmo da entrada padrão --- scanf(). scanf() precisa ler algo, e cada "algo" termina por ENTER espaço ou TAB. E não desiste. E ao retornar vai retornar algo nesse caso igual a 0, 1 ou 2, porque esse é o total de dados que ela vai tentar consumir. E por isso eu sempre escrevo e ensino aqui para NUNCA deixar de ler esse valor de retorno. Porque o programa não volta sózinho e scanf() pode consumir outros dados e passar reto... o primeiro especificador aceita apenas os operadores, mas aceita um grupo deles e considera só o primeiro. Você pode limitar com %1[+-*/] onde o 1 é o tamanho máximo que você quer ler o segundo especificador lê um número e uma letra. Isso é importante porque a letra pode ser uma letra mesmo, ou espaço ou TAB ou ENTER. E se foi um ENTER vai sinalizar o fim da linha, que é o fim dos argumentos e o sinal pra sair do loop. Então para tomar a decisão certa é preciso ler o delimitador e saber como scanf() retornou Assim pode resolver a maioria dos casos para esse enunciado, tratando os argumentos de acordo. Claro, deveria esvaziar a entrada ao final do primeiro scanf() porque pode ter sobrado algo que vai comprometer a leitura dos operandos adiante. Claro, scanf() precisa ler algo para retornar quando tenta ler um número então se o cara teclar enter direto na entrada do primeiro scanf vai mudar de linha... scanf() é isso... Isso é só um exemplo para mostrar a mecânica disso. Não é exatamente uma solução para o problema e nem vou dizer que é a melhor, sequer uma boa maneira de fazer. Mas é assim que a rotina funciona e é o que estou tentando mostrar Como fazer essa m#$%a de ler dados com segurança então? O seguro é o conhecido: posiciona o cursor, tenta ler de um grupo de teclas esperado, mas não mostra a letra. Toca um beep e não move se veio algo diferente, tipo algo que não seja um operador no primeiro caso. Não move o cursor. Se foi uma tecla válida aceita e mostra e avança o cursor até ler o campo todo. Ao ler todos os campos fecha o formulário. TAB avança para o próximo campo, SHIFT TAB volta campo, ESC sai e assim era quando se liam coisas do terminal e não se podia deixar o usuário teclar qualquer coisa e zoar a tela. Usando scanf() a partir de um arquivo Para um arquivo de entrada assim +-* 1 2 3 4 5 6 7 8 9 10 Esse seria o resultado Entre operador [+-*/]: Operador lido: '+' Lendo operandos: 1 2 3 4 5 6 7 8 9 10 Lidos 10 operandos Desse programa #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main(int argc, char** argv) { char arq[80], delim[4]; int n = 0; FILE* ent = fopen("rpn.txt", "r"); printf("Entre operador [+-*/]: "); n = fscanf(ent, "%[+-/*]%c", arq, delim); if (n != 2) { printf("Nao conseguiu ler operador\n"); return -1; }; printf("Operador lido: '%c'\n", arq[0]); int oper = 0; int total = 0; printf("Lendo operandos: "); while ( (n = fscanf(ent, "%d%c", &oper, delim)) == 2) { printf(" %d", oper); total += 1; }; printf("\nLidos %d operandos\n", total); return 0; };
-
Não é uma boa maneira de expressar o que acontece nesse comando. Não é de uma letra que está falando: é de uma variável que tem um nome que é uma letra, 'x' no caso. Podia ter dezenas de letras e ia dar na mesma. E se fosse um número? Pois é: também podia ser qualquer número. Linguagens de programação são coisas super formais e são regidas por uma gramática descrita por uma notação própria. Não vou chatear ninguém aqui sequer tentando explicar isso, mas no caso do while vou reproduzir um pedaço da gramática <iteration-statement> ::= while ( <expression> ) <statement> | do <statement> while ( <expression> ) ; | for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement> no formato clássico conhecido como Backus-Naur form para os comandos for e while em C E você pode ver que dentro dos parenteses se espera uma expressão. Uma expressão é qualquer coisa que permita obter um resultado numérico. E nessa linguagem 0 é falso. Só zero. Assim você tem sua resposta: você pode ter qualquer coisa lá que se possa avaliar para um número. Uma condição lógica é avaliada em C para um número também: 0 se falso. E assim se fecha o círculo. while(x) funciona desde que x exista, seja uma variável ou uma constante. E é o mesmo que escrever while(x != 0).
-
Conseguiu reaver os caracteres perdidos?
-
Continuo curioso por saber qual a função de que está falando fez progressos?
-
Devia deixar o enunciado aqui ou ao menos um link para o enunciado... Pode ser que alguém possa te ajudar mas não tenha ideia do que é isso. Como eu off-topic const unsigned long long digits = 10000000000000000000ULL; Note que em C e C++ você pode escrever const unsigned long long digits = 10'000'000'000'000'000'000ULL; Como o "_" em java, esse é o separador de dígitos nessas linguagens Acho que não foi você que escreveu esse programa, certo? Não estaria usando um desses IDE antigos que vem configurados para o padrão da linguagem de 22 anos atrás, estaria? Tipo -std=c++98, o padrão da linguagem em 1998 onde auto por exemplo não estava disponível? Se for o caso mude para -std=c++17... ou ao ao menos -std=c++11 que já é suficiente para compilar isso. Eu acho, porque meu IDE só aceita a partir de c++14 então não dá pra testar agora.
-
SIM. É só isso Você não leu direito o que eu escrevi e como todos aqui parece não levar a sério a declaração de scanf() int scanf(const char *format, ...) Use o valor de retorno. E vai funcionar para a entrada esperada. Em relação a aceitar coisas estranhas na entrada entenda que scanf() não foi escrita para isso e quando você usa para ler do teclado sempre pode ter surpresas. scanf() foi escrita para ler entrada formatada. Se der tempo mais tarde eu posto um exemplo e talvez fique mais claro para todos Foi o que você escreveu
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