Ir ao conteúdo

arfneto

Membro Pleno
  • Posts

    6.518
  • Cadastrado em

  • Última visita

Tópicos solucionados

  1. O post de arfneto em Imprimir Fila (de ponteiros) Invertida // função foi marcado como solução   
    O clássico para inverter a fila é uma pilha. LIFO.
     
    Mas sendo uma fila porque não manter ponteiros para frente e para trás, um ponteiro para o início e outro para o fim da fila, mais um contador para o total de nós e um limite de alocação, dentro da própria estrutura fila? E o que faz C++ e java por exemplo.
    adicionado 11 minutos depois O clássico é usar um apilha FIFO. 
     
    Mas se está usando uma fila porque não incluir já na estrutura ponteiros para trás, e um ponteiro para o início e o fim. E uma variável com a contagem de nós e outra com o limite de alocação, nos moldes do que faz java e C++? 
  2. O post de arfneto em Fila de Prioridade em C foi marcado como solução   
    Você leu o código nos links que eu te mandei? entendeu? baixou os programas?
    adicionado 1 minuto depois 🔍
  3. O post de arfneto em Acumular valores em uma variável foi marcado como solução   
    float vm, metro, seg; float d=0, t=0; while ((metro > -1) && (seg > -1)){  
    inicialize metro e seg declare uma variável por linha teste com os valores exatos que estão no enunciado if ((metro == 0) && (seg == 0)){ d += metro t += seg vm = (d/t) * 3.6; printf("Velocidade média: %.2f km/h.\n", vm); }  
    Você misturou as duas condições. Quando for zero imprime, quando não for apenas acumula
  4. O post de arfneto em Acumular valores em uma variável foi marcado como solução   
    float vm, metro, seg; float d=0, t=0; while ((metro > -1) && (seg > -1)){  
    inicialize metro e seg declare uma variável por linha teste com os valores exatos que estão no enunciado if ((metro == 0) && (seg == 0)){ d += metro t += seg vm = (d/t) * 3.6; printf("Velocidade média: %.2f km/h.\n", vm); }  
    Você misturou as duas condições. Quando for zero imprime, quando não for apenas acumula
  5. O post de arfneto em lista de prioridade em c foi marcado como solução   
    typedef struct aux { int id;//Chave float prioridade; struct aux* ant; struct aux* prox; } ELEMENTO, * PONT; typedef struct { int maxElementos; //Armazena os dados PONT fila; //Elementos que fica na fila PONT* arranjo; //Armazena os ponteiros } FILADEPRIORIDADE, * PFILA;  
    Do modo como declarou fica muito difícil de ler. Considere que está declarando dois tipos por exemplo, ELEMENTO e PONT, só que um é ponteiro e outro não, para o mesmo tipo de estrutura. Isso é complicado, difícil de ler e arriscado. Mesmo chamando de PONT  Em geral não se faz isso, apesar de que a Microsoft tem essa convenção há décadas  de usar LP isso e aquilo por exemplo.
     
    Mas compare
     
    #include <stdio.h> #include <stdlib.h> #include <time.h> typedef struct aux { int id;//Chave float prioridade; struct aux* ant; struct aux* prox; } NODE; typedef struct { int maximo; //Armazena os dados int size; NODE* inicio; } FilaDePrioridade; int main(void) { FilaDePrioridade porque = { 500,0,NULL }; // 1 FilaDePrioridade fila = // 2 { .inicio = NULL, .size = 0, .maximo = 1000 }; FilaDePrioridade outra; // 3 outra.inicio = NULL; outra.maximo = 50; outra.size = 0; FilaDePrioridade* pFila = &porque; }; // main()  
    E talvez ache mais fácil de ler: Não há tipos para ponteiros então não há o que procurar ou aprender: se é um ponteiro está na declaração da variável e não na declaração da estrutura ou do tipo ou no nome. Fique a vontade para achar bobagem o que eu expliquei.
     
    De volta a programa: A função
     
    bool inserirElemento(PFILA f, int id, float prioridade);  
    tem um grande problema: o que é PFILA? É FILADEPRIORIDADE*. Então o valor entra em inserirElemento() mas não sai nunca mais. E se alterar o inicio da lista ele vai se perder. E se não passar o início da lista não vai achar o lugar para inserir. Então... não funciona.
     
    Por isso o usual é declarar
     
    PFILA    inserirElemento(PFILA f, int id, float prioridade);  e retornar sempre o endereço de início. Claro, vale o mesmo para apagar ou criar ou qualquer operação.
     
    Outra opção é passar o endereço do ponteiro, declarando
     
        int    inserirElemento(PFILA*  f, int id, float prioridade);  
    É menos flexível, menos legível e provavelmente mais seguro.
     
    Um pouco de formalidade
     
    Entenda que a fila de prioridade é uma estrutura em si. E pode ser implementada usando qualquer coisa, desde que resolva --- encapsulamento é o termo --- e uma lista ligada serve para isso. 
     
    Mas uma lista ligada não é uma fila de prioridade. Sua estrutura fica meio híbrida assim: meio lista ligada meio fila de prioridade. A bem da verdade o comum é usar um array e uma estrutura chamada heap para implementar isso.
     
    E em geral os nodes em sua lista ligada seriam algo assim
     
    typedef struct aux { void* item; struct aux* ant; struct aux* prox; } NODE; // ou algo como typedef struct aux { ITEM item; struct aux* ant; struct aux* prox; } NODE;  
    Porque? simples: você quer que a lista ligada funcione para qualquer coisa. Então a lista é de item e você põe um endereço apenas. Assim não precisa sequer compilar o código quando usa uma lista ligada.
     
    E como seria com a prioridade?
     
    Você acerta a prioridade na rotina de inserção apenas. Coloca o cara na fila no lugar de acordo com a prioridade, usando uma função de comparação na rotina de inserção para a lista.
     
    Mais um palpite
     
    Poste um código inteiro compilável para ajudar os outros aqui a ajudarem você.
     
    TL;DR 

    No seu programa o ponteiro para inserir() é uma variável local e não retorna para main() então não vai inserir nada.
  6. O post de arfneto em Criar janela e botão continuar/codeblocks foi marcado como solução   
    Não, não está. Está criando um rpg em C++.
     
    E está usando o Code::Blocks para criar o programa em C++. É uma distinção importante.
     
     
    Está imaginando que o jogo vá ser usado de dentro de uma janela do ambiente de desenvolvimento e não faz sentido. O seu programa em C++ vai gerar um arquivo executável. E no mundo normal ele seria associado a um ícone e um atalho. E alguém para jogar clica no ícone e a coisa anda.
     
    Não deve imaginar que alguém vá compilar seu programa a cada vez que for rodar o jogo. Não é prático.
     
     
    Pois é: você não deve misturar código e texto. Vai ficar impossível de gerenciar e muito chato para programar e corrigir. Não se mistura essas coisas.

    Veja isso de seu programa:
    cout<< "\nQuentin: Mas isso é assunto pra quando você melhorar, não há nada\ que você possa fazer a não ser melhorar"<<endl; cout<< "Ginug: Com essa chuva lá fora, não há muito que se possa fazer.."<<endl; cout<< "Quentin: É bom ver que está bem, tenho uns assuntos para re\ solver, nesse caso, Ginug poderia fazer a genileza de chamar Mildga, \ ela vai querer ver "<< nome_personagem << "."<<endl; cout<< "Ginug: Sim, claro, (sarcástico) eu ando muito atarefado\ mesmo, com essa chuva ae fora ainda.."<<endl; cout<< "\nOs dois se despedem, você está sozinho no quarto, isso te\ faz pensar um pouco no ocorrido, tu não sente tristeza ou angústia por não ter\ lembranças, porém sente medo de ter perdido algo importante..."<<endl; cout<< "Um momento se passa, logo após uma mulher de cabelos longos\ e pretos aparece na porta, ela carrega uma bolsa na cintura, em suas botas há barro\ por conta da chuva, ela te encara por um momento."<<endl; cout<< "\nNPC3: Vejo que está melhor, me chamo Mildga, fui eu quem ajudou com os ferimentos, sinceramente não acho que teria sobrevivido caso, (como era mesmo\ o nome dele...)Quentin! isso, caso Quentin não tivesse te encontrado.."<<endl; cout<< "E então posso dar uma olhada? aliás como se chama?"<<endl; cout<< "\nVocê explica o ocorrido a Mildga enquanto\ ela tira suas faixas, tu ainda sente um pouco de dor, olha sua\ barriga (parte inferior direita) e\ percebe três riscos como fosse realmente uma garra que tivesse causado o ferimento"<<endl; cout<< "Mildga faz os curativos necessários e pede pra você repousar."<<endl; cout<< "\nMildga: É uma pena, infelizemnte tudo \ que posso fazer por você é isso, vou enviar um garoto, a saber seu nome é \ Griffin, ele te auxiliará no que for preciso, inclusive a respeito da comida,\ aquele rapaz fez questão"<<endl; cout<< "de deixar tudo pago, Quentin, isso."<<endl; cout<< "\nMomentos mais tarde um garoto aparece..."<<endl; cout<< "\nNPC4: Olá, me chamo Griffin, Mildga me disse pra vir\ e te destrair, ela disse que vai me dar umas moedas depois, mas a verdade\ é que eu queria as moedas ontem, hoje não tem mais suco de groselha..aaahh"<<endl; cout<< "Griffin: Ah! É verdade que uma fera te atacou? como ela\ era? eu nunca vi uma fera antes, mas quando eu crescer eu vou ser\ um grande cavaleiro!"<<endl; Note que em C++ você pode continuar qualquer linha terminando com '\'' e digitando na próxima linha. Isso dentro de strings. Assim evita essas linhas extra longas ruins de ler, em especial numa janela do programa fraquinho do forum.
     
    Mas compare com a mesma coisa:
    #A0128# Quentin: Mas isso é assunto pra quando você melhorar, não há nada que você possa fazer a não ser melhorar Ginug: Com essa chuva lá fora, não há muito que se possa fazer... Quentin: É bom ver que está bem, tenho uns assuntos para resolver, nesse caso, Ginug poderia fazer a gentileza de chamar Mildga, ela vai querer ver "<< nome_personagem >>" Ginug: Sim, claro, (sarcástico) eu ando muito atarefado mesmo, com essa chuva ae fora ainda... Os dois se despedem, você está sozinho no quarto, isso te faz pensar um pouco no ocorrido, tu não sente tristeza ou angústia por não ter lembranças, porém sente medo de ter perdido algo importante... Um momento se passa, logo após uma mulher de cabelos longos e pretos aparece na porta, ela carrega uma bolsa na cintura, em suas botas há barro por conta da chuva, ela te encara por um momento. NPC3: Vejo que está melhor, me chamo Mildga, fui eu quem ajudou com os ferimentos, sinceramente não acho que teria sobrevivido caso, (como era mesmo o nome dele...) Quentin! isso, caso Quentin não tivesse te encontrado... E então posso dar uma olhada? aliás como se chama? Você explica o ocorrido a Mildga enquanto ela tira suas faixas, tu ainda sente um pouco de dor, olha sua barriga (parte inferior direita) e percebe três riscos como fosse realmente uma garra que tivesse causado o ferimento Mildga faz os curativos necessários e pede pra você repousar. Mildga: É uma pena, infelizemente tudo que posso fazer por você é isso, vou enviar um garoto, a saber seu nome é Griffin, ele te auxiliará no que for preciso, inclusive a respeito da comida, aquele rapaz fez questão de deixar tudo pago, Quentin, isso. Momentos mais tarde um garoto aparece... NPC4: Olá, me chamo Griffin, Mildga me disse pra vir e te distrair, ela disse que vai me dar umas moedas depois, mas a verdade é que eu queria as moedas ontem, hoje não tem mais suco de groselha..aaahh Griffin: Ah! É verdade que uma fera te atacou? como ela era? eu nunca vi uma fera antes, mas quando eu crescer eu vou ser um grande cavaleiro! Na prática você separa os diálogos por blocos numerados, que vem da memória ou do banco de dados, e são parte dos dados e que ficam separados do programa. Assim você pode ter todo o texto disponível para formatar, corrigir, usar um corretor ortográfico e tal. E não precisa mudar o programa porque mudou uma frase que estava errada. No programa só tem chamadas a uma classe. Texto por exemplo, onde tem um método
    int mostra_local(string local); e você chamaria com
    mostra_local("#0128#"); // por exemplo E a classe trocaria os campos por exemplo "<<valor>>" pelo certo no contexto do jogo. Do  modo como está fazendo rapidamente vai ficar impossível de controlar.
  7. O post de arfneto em Exceção gerada em 0x7C23F244 (ucrtbased.dll) em TrabalhoMatriz.exe: 0xC0000005: foi marcado como solução   
    Preste atenção: "%.2s" é uma constante. Um literal. 5 bytes somente leitura. Não pode passar isso para uma função que espera char*, o endereço onde colocar os dados. Claro que vai cancelar...
  8. O post de arfneto em o que está errado nessa função foi marcado como solução   
    Ah tá!
     
    E de onde vem essa conclusão?
     
    Está mesmo lendo o que eu escrevo?
     
    Depois de tudo que te expliquei, não acha que poderia ter escrito ao menos 
    printf("CreateToolhelp32Snapshot error: %s\n\n", GetLastError()); Não ficou nem um pouco curioso sobre que erro seria esse?
     
    Como já te expliquei, programar com essas API não é nada criativo. É chato. Só preencher formulários representados por estruturas. Só que o resultado é praticamente certo. Essas coisas não dão erro. Se dão não é provavelmente um programa nosso de 10 linhas que vai achar. Muito menos resolver.
     
    Mas você tem que ter disciplina e entender os paradigmas. Dois apenas, eu acho. Não sou autoridade no entanto.
     
     
     
    Leu mesmo essa parte? Porque continua fazendo exatamente a mesma coisa?
     
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, window_thread);  
    Nem mesmo essa bobagem de usar em uma linha só depois de eu ter te mostrado e imagino de você ter visto que vai forçar uma barra de scroll horizontal e sumir com o fim da linha?
     
    HANDLE hSnap = CreateToolhelp32Snapshot ( TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, window_thread ); Não percebe mesmo a diferença?
     
    E agora que está na tela pode voltar a ler o que eu te disse sobre window_thread? Em especial aquela parte em letrinhas mais pretas? 
    adicionado 1 minuto depois  
    Sei. 
     
    Rodou o programa --- exatamente como te mostrei --- em sua máquina?
     
    Não aprendeu nadinha?
  9. O post de arfneto em Printf não mostra valor armazenado da String foi marcado como solução   
    Está claro que a string de saída vai ter o mesmo tamanho que a de entrada. Mas do jeito que você escreveu precisa colocar um zero lá no fim de 'contrario'
      fgets() foi escrita para você poder ler e já copiar a string para outro lugar. Isso quer dizer que fgets() lê a string inteira, incluído o '\n' do final. Isso é bom, desde que você tenha lido o manual ou queira fazer o normal que é gravar em outro lugar com fputs() por exemplo. Aí você gosta de ter o '\n' lá porque se fgets() o tirasse você teria que por de volta linha por linha ou ia ficar tudo grudado na saída em uma linha só.
    Só que aqui você não pode copiar a partir do último valor em str[] porque é garantido que é um '\n', e isso é bom. Mesmo que não tenha um newline lá para ler fgets() vai colocar um automaticamente. Isso porque muitas vezes a última linha de um arquivo texto não tem o '\n'e aí ficaria um tratamento especial a toa. É mais simples assim e está escrito em todo manual que eu já vi até hoje. Como você só quer ler a string, não pode começar a inverter pela última posição dela.
    Exemplo: se a linha era 'azul\n' fgets() leu exatamente assim:  'a' 'z' 'u' 'l' '\n' E o primeiro que você quer copiar é o 'l' e a posição dele é (strlen(str) - 2). Esse é o maior problema de seu programa
     
    Você precisa terminar a string de saída com um zero. Uma string em C é isso. Você sabe que ela vai ter o mesmo comprimento da string de entrada, exceto o '\n' e então faça isso: coloque um zero lá ou não vai funcionar e vai imprimir um monte de lixo na tela até achar um zero... Algo simples assim resolve: int c = strlen(str) - 2; // primeiro indice a copiar contrario[c + 1] = 0; E você copia de str para contrario até c ser menor que zero
      Quando você mostra uma string que pode espaços sugiro sempre mostrar entre algum delimitador, afinal não dá pra ver os espaços. Algo simples como '%s' no printf()
      se você não está usando um compilador medieval pode declarar int i=0 dentro do for apenas
      para imprimir str[] você deve tirar o '\n'de lá. Pode usar o simples  str[strlen(str) - 1] = 0; Compare com o EXEMPLO #include <stdio.h> main() { char str[30], contrario[30]; printf("Digite uma palavra: "); fgets(str, 30, stdin); int c = strlen(str) - 2; // primeiro indice a copiar contrario[c + 1] = 0; str[strlen(str) - 1] = 0; printf("\nValor recebido: '%s'\n", str); for (int i = 0; c >= 0; i+=1, c-=1 ) contrario[i] = str[c]; printf("String ao contrario: '%s'\n\n", contrario); } que mostra para 'azul'
     
    Digite uma palavra: azul Valor recebido: 'azul' String ao contrario: 'luza'  
    adicionado 16 minutos depois Não seria justo não incluir o clássico exemplo de inverter a string usando recursão  
     
    Veja que nesse caso só precisa de uma variável, a string em si. E precisa daquela jogada no final da entrada apenas para poder mostrar a string inicial sem pular de linha por causa do '\n' no final.
    #include <stdio.h> void inverte(char*); main() { char str[30]; printf("Digite uma palavra: "); fgets(str, 30, stdin); str[strlen(str) - 1] = 0; printf("\nValor recebido: '%s'\n", str); printf("String ao contrario: '"); inverte(str); printf("'\n"); }; void inverte(char* str) { if ((str[0] == 0) || (str[0] == '\n')) return; inverte(str + 1); printf("%c", *str); }; O resultado, claro, é o mesmo.
  10. O post de arfneto em estou tentando rodar uma string em um for, mas não vai foi marcado como solução   
    main() { char str[15]; int i; printf("Digite um nome: "); scanf("%s", str); for(i=0;i<10;i++); { printf("valor do elemento %d da string = %c\n",i,str[i]); } } Imagino que a partir de todas as sugestões que recebeu já tenha entendido o que houve com seu programa e tenha feito ele funcionar  
     
    Mas vou deixar uma análise do que você escreveu e umas notas a mais
     
    int i;
     
    Como está aprendendo é uma boa hora para novos costumes. Sempre inicialize as variáveis. No caso de uma variável que só vai ser usada como índice em um loop, desde 1990 se pode declarar a variável no próprio comando for, escrevendo
    for(int i=0; i<10;i++); E se tivesse escrito assim não teria errado no seu programa: ao encontrar o ';' terminaria o for e então o printf()
       printf("valor do elemento %d da string = %c\n",i,str[i]); ia dar erro. A variável 'i' que só deveria existir dentro do loop não estaria declarada. E você teria notado o ';' ou não ia conseguir compilar o programa. Erros de compilação são muito melhores que erros de execução, como você viu aqui.
     
    scanf()
     
    scanf() é problemática para ler coisas do teclado. Essa função foi escrita para ler entrada formatada --- scan formatted input --- e a entrada pelo teclado não é nada formatada. O usuário tem 105 teclas ou mais de liberdade para digitar qualquer m#$d@. Evite usar. É possível mas só vai te dar dor de cabeça.  Entenda também que scanf() retorna um valor e você deveria tratar isso. Muitas vezes ela não lê nada e se você não testar não vai saber. Muitas vezes ela não lê tudo e logo depois você vai saber.
    E você pode limitar o tamanho de cada campo a ser lido, usando o tamanho como em %14s no seu exemplo.
     
    for(i=0;i<10;i++);

    Em programas não é assim incomum esse comando estar certo. Mas entenda que ';' indica o final do comando em C. De qualquer comando. Uma maneira de diminuir a chance de você digitar isso por engano é escrever o loop sempre já com as chaves e depois digitar dentro...
    for( ;; ){ }; Se não precisar das chaves depois você apaga. Mas assim não vai esquecer delas ou colocar o ';' no lugar errado...
    Acho que entendeu.
    Se ficou curioso por isso poder estar certo, entenda que o comando for tem 3 partes, todas opcionais, separadas por dois ';' esses sim obrigatórios. Muitas vezes a lógica do loop está toda contida aí e não sobra nada para ficar dentro das  { } e elas podem ser então omitidas e fica só o ';'
     
    Em seu programa pode ler até 14 letras, já que str é char[15] e tem que ter espaço para o zero no fim. Mas usou o limite de 10 fixo no loop. E se o cara digitar apenas 2? Ou 13? Ou teclar ENTER direto?
     
    Na verdade você quer rodar o loop para mostrar o que tem na string e isso vai até o zero final, exclusive. Quase todo mundo iria rodar strlen(str) para ver o tamanho da string. E você pode fazer isso e ficar seguro de que o loop estará dentro dos limites do que foi digitado. Como você está começando agora pode ser boa hora de evitar também esse hábito. strlen() é uma função. Um pedaço de código escrito por alguém e que vai ser chamado, como scanf(). e vai retornar um valor, como scanf(). E tem um custo chamar uma função. E não é pequeno, em especial em um programa... pequeno  E no seu caso ela vai ser chamada uma vez para cada letra. Pense nisso. Dentro do loop o tamanho da string pode ser alterado afinal.
     
    E você não precisa nesse caso saber o tamanho da string: só quer mostrar o que tem dentro e ela termina com um zero. Isso quer dizer que você pode escrever
        for (int i = 0; str[i] != 0; i++) simplesmente, já que o zero marca o fim da string.

    i++

    Evite essa construção.

    Pode usar:
    ++i i++ i+=1 i = i + 1 Não faltam opções. Por razões históricas esse operador pós- é o mais usado. Mas é o menos esperto. O i++ ou i-- indica que a operação vai ser feita depois de o operando ser usado. Pesquise isso.

    Esse trecho de programa
    int j = 2; int k = 3; printf("j = %d j++ = %d k = %d e ++k = %d\n", j, j++, k, ++k); printf("k = %d\n", k); Mostra
    j = 3 j++ = 2 k = 4 e ++k = 4 k = 4 Não escreva essas coisas. É só um exemplo. Mas entenda que toda vez que escreve isso o compilador salva e usa o valor da variável para depois fazer a soma. Use ++x se gosta desses, porque aí a operação é executada direto no operando.
     
    printf("valor do elemento %d da string = %c\n",i,str[i]);  
    Você está tentando mostrar algo que pode estar em branco, é uma string afinal. Se acostume a usar nesses casos um delimitador, tipo '%c' e assim saberá que está funcionando mesmo que na posição tenha um espaço ou um TAB por exemplo.
    Escreva por exemplo
            printf("valor do elemento %d da string = '%c'\n", i, str[i]);
    Seu programa um pouco diferente
    #include <stdio.h> int main(void) { char str[15]; printf("Digite um nome: "); scanf("%14s", str); for (int i = 0; str[i] != 0; i++) printf("valor do elemento %d da string = '%c'\n", i, str[i]); } Mostra
    Digite um nome: abcdeABCDE1234 valor do elemento 0 da string = 'a' valor do elemento 1 da string = 'b' valor do elemento 2 da string = 'c' valor do elemento 3 da string = 'd' valor do elemento 4 da string = 'e' valor do elemento 5 da string = 'A' valor do elemento 6 da string = 'B' valor do elemento 7 da string = 'C' valor do elemento 8 da string = 'D' valor do elemento 9 da string = 'E' valor do elemento 10 da string = '1' valor do elemento 11 da string = '2' valor do elemento 12 da string = '3' valor do elemento 13 da string = '4' Pressione qualquer tecla para continuar. . .
     
     
    Não evite enquanto não entender  
    De todo modo é bobagem. 
    Use scanf() quando a entrada for formatada, como ler uma tabela ou um arquivo csv. Use fgets() para ler linhas e fgetc() para ler letras sempre que sua lógica permitir.
    No "mundo profissional" não se lê valores do teclado para mostrar na tela desde os 90. Quanto são poucos argumentos são passados direto na linha de comando, como um MKDIR c:\teste no Windows. Quando são muitos e tem uma tela mesmo, e não tem MESMO jeito de usar uma interface gráfica, o que se faz é separar teclado e tela: 
    você uma tecla por vez mas não mostra se for algo válido aí sim você mostra e avança o cursor se for inválido você apaga e pisca a tela ou toca um bip e continua Usando scanf() sempre tem chance de zoar a tela. fgetc() e fgets() são mais seguras nesse aspecto mas não 100%
     

     
    Não, não vai apagar um enter.
     
    O que está entre colchetes é uma lista dos caracteres que serão aceitos por scanf() para montar o campo. [1234] aceita só esses números, por exemplo. Mas se o primeiro caracter for ^ inverte o significado e passa a ser a lista dos caracteres que NÃO são aceitos. [ ^1234] vai ler em str até o primeiro desses dígitos aparecer: se o cara digitar 1234x scanf() vai ler "1234" em str. E vai retornar 1 o que deveria er lido e tratado pelo programa como eu expliquei. E vai deixar o 'x' lá para ser lido depois.
     
    Então esse especificador que mostrou lê tudo que vier, até o ENTER, exclusive. Porque a lista tem só o '\n'.
    Só que se o cara digitar ENTER direto scanf() não vai ler nada. Vai retornar zero só que você não está testando, como ninguém aparentemente testa. E eu programa vai imprimir um monte de bobagens provavelmente.
     
     
     
  11. O post de arfneto em Design de programa em C foi marcado como solução   
    Esse é o visual típico dos programas de console dos anos 80.
    Até as cores são familiares.  
    Hoje em dia temos muito mais opções. Unicode tem hoje pouco mais de 1.1 milhão de cacteres.
     
    Um pouco de história
     
    Naquela época a tabela ASCII, que tinha ganho minúsculas poucos anos antes, foi estendida, e alguns caracteres foram criados antes do valor 32, o espaço, e depois de 127, o DELETE. Antes de espaço só ficavam caracteres de controle, como só ETX ACK NAK e tal, e eles só tinham sentido para o pessoal de telecomunicação. Não havia TCP/IP ou internet. Comunicação aí era em geral via linhas telefônicas e modems. E a comunicação era sinalizada por esses caracteres. ACK era a resposta positiva, NAK pedia retransmissão e coisas assim. Hoje não mudou tanto assim. Só tem mais camadas.
     
    Foi então criado o conceito de CodePage no Windows e uma das primeiras foi a da IBM, 437, e ela tinha alguns caracteres especias que todo mundo passou a usar. Estavam abaixo de 32 e depois de 127 claro, e a tabela ASCII cresceu de 7 para 8 bits.
     
    Alguns desses caracteres eram para desenho. Veja abaixo:
     

     
    Com eles se podia ter dois tipos de caixa, com linhas simples ou duplas. E as intersecções. Era o máximo  porque antes só tinha barra ponto , traços e a imaginação. E apareceram algumas letrinhas novas no lugar dos caracteres de controle
     

     
    Veja o 16 acima. É o que está no menu que mostrou. Aqui tem a página toda para ver:  https://en.wikipedia.org/wiki/Code_page_437#Character_set 
     
    De volta ao programa
     
     
    Não precisa ser nada assíncrono porque o programa está sempre lendo.  Veja que na imagem que postou está lendo uma matrícula. Na tela principal estaria lendo apenas 10 coisas: F1..F4 1..4 TAB ou ESC. E se entrar em um menu vai estar lendo dados relativos ao menu então vai poder tratar ESC ou TAB ou qualquer coisa. Esse tipo de programa está sempre lendo.
     
    Em geral o que se faz hoje nos programas de console nada mudou. A lógica é simples:
    separa a leitura da exibição. Você lê as teclas e aceita só as que fazem sentido. Mas não mostra e não move o cursor de jeito nenhum. Se for inválida pode enviar aquele clássico BEEP, o BEL o ASCII 7. Para o óbvio efeito. Note que o Beep até outro dia ia para o alto-falante do PC   Se for o caso de mostrar, como a matrícula no exemplo, e o caracter for válido, aí sim você mostra a letra e avança o cursor  Se for uma tecla de função ou um TAB você age de acordo e move o cursor. O clássico persiste até hoje na web: TAB avança campo, shift TAB volta o campo. E o formulário tem essa noção de TAB Order. É assim em java, em DELPHI, em dotNet curses era uma biblioteca que ajudava bem a fazer esse tipo de coisa. Depois evoluiu para ncurses e está disponível até hoje. Não sei como é ncurses em Windows, nem se roda. Era uma coisa de Unix quando eu usava. O grande lance era que o Unix --- Linux OSX Android -- não tem essa noção de console que tem no Windows, e curses evitava que você tivesse que guardar a imagem da tela você mesmo. Porque alguém faria isso? Simples: se o terminal desligasse e ligasse de novo sumia tudo, mas o programa estava normal. No Windows não. Acende tudo igualzinho. Na verdade hoje o padrão do Windows é de pouco mais de 9000 linhas de memória.
     
    Esse programa mostra esses caracteres. Os abaixo de 32 são um pesadelo e é melhor nem tentar a menos de um pagamento ou uma aposta ou uma nota.
     
     
     
     
    Dias atrás acho que eu postei um programa que faz essa "leitura assíncrona" como falou. É a solução para games, claro, porque você não pode usar um simples read() como deve imaginar.
     
    Se tem interesse em ver me avise e eu procuro por ele. A lógica é simples. E não é assíncrono na verdade: você usa PeekConsole Input() e lê o buffer de teclado antes de ler via read() ou scanf() ou getc(0 ou sei lá. E então você age de acordo. Isso no Windows. Se tem algo para ler você já sabe o que é e pode até apagar
    Só que o programa continua rodando. Acho que deu pra entender.
     
    No Linux é diferente: você manipula o tty, o terminal, usando acho que ioctl() e muda o timeout de leitura para 0. Asim o read sempre retorna na hora, tendo ou não algo pra ler.
     
    Acho que eu também devo ter algum exemplo, mas nunca postei nada aqui relativo a Unix/Linux então teria que ver.  
     
     
     
     
  12. O post de arfneto em Problema em ordenação de registro (por parametro) bubble sort foi marcado como solução   
    Acho que eu te falei um certo número de vezes, e te mostrei códigos completos e exemplos, como em 

    E eu imaginei que tinha entendido que é sempre um atraso colocar menus e ler coisas do teclado em programas que ainda não estão prontos. Imagino que tenha referências que julgue melhores que a minha simples sugestão. Professores e livros que digam o contrário 🤔 talvez.
     
    Mas eu estou certo e aqui está você com o programa igualzinho de volta
     
    Sobre a função ordena()
     

     
    Pois é. A cada vez que vai testar você fica aí sentado inventando esses dados?
     
    Chegou a digitar os 30 alguma vez? 
    int ordenar (Cadastro* cad) { int i, j; Cliente troca; for (i = 0; i < 28; i++) { for (j = i + 1; j < 29; j++) { ...  
    Se o usuário --- você --- estiver meio sem paciência e digitar apenas DOIS valores, que acha que vai rolar com esses loop com valores fixos em 28 e 29?
     
    Para que você acha que eram as variáveis cad->limite e cad->total?
     
    int novoCadastro(Cadastro* cad) { Cliente modelo1 = { .codigo = 12, .nome = "cliente 12" }; Cliente modelo2 = { 13,"cliente 13" }; cad->cl[0] = modelo1; cad->cl[1] = modelo2; cad->cl[2] = modelo2; cad->cl[3] = modelo1; cad->total = 4; cad->limite = 30; return 4; }; Sobre essa função acima eu te mostrei com detalhes e achei que você tinha entendido, já que nada mais perguntou.
     
    E aí pergunto eu: porque razão não testou a função 
    int ordenar(Cadastro* cad) que escreveu com esse cadastro e editando nele direto com outros valores, para testar sua função em minutos ao invés de dias?
     
    Se recorda de ter aí um programa completo que roda isso?
     
    Não entendeu mesmo que seria só chamar
    Cadastro cad; novoCadastro(&cad); // ja vem preenchido imprimirLista(&cad); // mostra ainda fora de ordem ordena(&cad); imprimirLista(&cad); // mostra depois de ordenar ??
     
  13. O post de arfneto em Quero que um procedimento preencha o vetor de struct. foi marcado como solução   
    Pode até escrever assim, mas não é comum. Quando se acessa a estrutura por endereço se usa ->. Mas claro que se cad é um ponteiro (*cad) é o valor e então pode usar '.' Já *cad é o que se chama de instância da estrutura apontada por cad.
     
     
    Ao menos não estava usando o Code::Blocks.  
    Muito importante isso que fez, porque a versão de 1989 é, digamos, de 1989. E não dá pra imaginar que nada tenha melhorado depois. E melhorou muito.
     
     
    Não tenho a menor ideia do que possa ser isso. Pode explicar de outro modo? Que seria "cpp no meio"?
     
     
    Imagino que já saiba agora porque eu te mostrei um exemplo. E retornar void como eu disse em geral é um desperdício ou um erro mesmo. Veja que você pode por exemplo ter uma função 
    Cliente* fabrica(); que faz o contrário: não tem argumentos, mas a cada vez que você chama ela cria e devolve um item de cadastro completo. Muito conveniente, porque pode ser um registro de teste ou um de verdade e faz toda a diferença no desenvolvimento e na produção.
     
     
    Pois é: talvez devesse mudar desses ambientes mais antigos... CLion da jetbrains é sensacional. VS Code da Microsoft é muito bom, Visual Studio é o padrão no planeta. Eclipse é legal. Evite o Dev-C++. E se não te pagarem bem ou te apontarem uma arma ou te obrigarem de algum modo, evite o Code::Blocks.
     
    Quanto a isso:
     

     
    Isso É um exemplo! Pra que vai procurar um exemplo de um exemplo?
     
    O que não entendeu? Basta ler o código: um cadastro tem um vetor de clientes.  limite marca, digamos, o limite: quantos cabem. total marca quantos tem dentro. Em geral se usa ao invés de Cliente[30] que está fixo, um vetor de clientes e você aloca dinamicamente e poe o quanto alocou em limite. Porque? Bem, digamos que se alocou 40 então 40 é o limite e total é zero já que não nenhum ainda, ao criar. É só isso: uma abstração da realidade. 
     
    E cada Cliente[] é um... Cliente. Acho que já imaginava. Assim tem no exemplo 30 clientes e cada cliente tem esses 4 campos... email, nome, telefone e codigo.
     
    E como acessar eu te mostrei também. Não acho que precise de outro exemplo da mesma coisa. Como preencher eu também te mostrei.
     
     
    As duas coisas. Assim você define um tipo e não precisa ficar repetindo struct toda hora. Mas também fica livre para mudar a definição do campo sem ter que mexer no resto do programa
     
     
     
    Exato. porque a realidade é assim: o cadastro tem clientes. Então ao invés de usar um vetor de clientes você passa um cadastro e põe os clientes dentro. E aí pode passar outras coisas, como o total de caras que tem dentro, o máximo que pode ter , o nome da loja, endereço e coisas assim. Pode ter um vetor de cadastros para todas as lojas, por exemplo, e mesmo assim não ter que mexer nas funções nem declarar um monte de variáveis. Isso é algo chamado na literatura de encapsulamento.
     

     
    Desse modo você pode inicializar só algumas variáveis da struct, as que precisa para o teste, e em qualquer ordem. É muito mais prático. Como deve ter visto, com o ponto você define o campo e depois dá o valor. Cliente é assim:
    typedef struct { int codigo; char nome[31]; int telefone; char email[51]; } Cliente; Então se você só quer preencher o vetor pra testar a função de cadastro sem perder tempo lendo da tela pode só criar isso
    modelo1 e modelo2
     
    Cliente modelo2 = { 13,"cliente 13" }; //por que aqui está sem o .codigo e .nome Esse é o modo tradicional de inicializar, onde você põe os valores na ordem em que foram declarados na struct. Usando o ponto como antes você pode escrever em qualquer ordem, claro, já está dizendo o nome do campo...
     
    Exemplo mais enjoado, e muito mais útil

    Imagine que você quer criar um cadastro de teste com 3 clientes para testar seu programa. E tem lá a rotina novoCadastro() como antes.
    Você pode declarar um cadastro com 3 caras e preencher direto:
    Cadastro teste = { .cl[2] = { 13, "cliente 2", 2, "email" }, // o terceiro cliente .limite = 30, .total = 3, // os campos de controle fora de ordem .cl[1] = { -9813, "cliente um", 2, "email sdslk" }, // o segundo cliente .cl[0] = { .email = "[email protected]", .nome = "Jhonny Cash", .telefone = 912348765, .codigo = 3245 } // o primeiro cliente com os valores fora de ordem }; Você só escreve o que você quer e o compilador se vira. Muito prático e se usa assim há décadas. Não sei porque não ensinam há décadas...
     
    Veja o exemplo usando isso:
    Cadastro teste = { .cl[2] = { 13, "cliente 2", 2, "email" }, // o terceiro cliente .limite = 30, .total = 3, // os campos de controle fora de ordem .cl[1] = { -9813, "cliente um", 2, "email sdslk" }, // o segundo cliente .cl[0] = { .email = "[email protected]", .nome = "Jhonny Cash", .telefone = 912348765, .codigo = 3245 } // o primeiro cliente com os valores fora de ordem }; imprimirLista(&teste); E veja o que mostra:
    cadastro tem 3 de 30 clientes: 3245 -9813 13 Quer mostrar os detalhes do cadastro? Muda imprimirLista(). Entende como é muito mais produtivo?
     
    O exemplo todo
     
    adicionado 1 minuto depois
     
     
    Isso eu não entendi. Pode explicar qual o problema?
     
     
  14. O post de arfneto em Alguém pra me ajudar? foi marcado como solução   
    Você disse que nem tinha ideia do que significava 🤔
     
    Você tem dois tipos de entrada
    as que entram com um valor as que pedem uma resposta Se vier na ordem errada pode ser que não tenha dados suficientes e precise desprezar algo
     
    Tem muitas maneiras de implementar isso. Uma seria usar uma tabela simples acumular os valores logo no inicio, algo tipo
    typedef struct { char* token; int v_credito; int v_unidade; } Token; typedef struct { int N; Token T[300]; } Tabela; int main(int argc, char** argv) { Tabela T; T.N = 0; // ... }; E aí você vai preenchendo conforme receba dados, mais ou menos como o compilador faz com as variáveis.
    E quando vem uma consulta você pesquisa na tabela e vai somando os valores conforme a unidade pedida.
     
    Pode ler uma linha inteira com fgets() e separar os tokens com  strtok(), pode usar fscanf() ou mesmo usar fgetc(). Eu postei um programa em C ontem que usa essa última opção, pode ser um exemplo porque ele faz exatamente isso: um parser. É mais complicado lá porque é um algoritmo recursivo, mas mude a rotina insere() lá e ela vai montar sua tabela sem gastar mais que uns minutos pra alterar...
     
    Claro, as outras opções também funcionam.
     
     
     
     
  15. O post de arfneto em Dificuldade para acentuação com arquivo .txt foi marcado como solução   
    Precisa realmente disso? Se não faz parte do enunciado passe um filtro no txt e deixe apenas as letras. Isso é um inferno e não tem fim. E não acrescenta nada ao software de locadora e ao algoritmo em si.
     
    Mas se precisa mesmo disso defina a página de código em uso para uma que tenha essas letras, como a 850 ou 65001 usando SetConsoleOutputCP(850) por exemplo como descrita em https://en.wikipedia.org/wiki/Code_page_850
     
    O certo é usar no início do programa GetConsoleOutputCP(void); e salvar o valor. Aí você chama SetConsoleOutputCP(850) e ao final do programa restaura chamando o que salvou, como 
    int pagina = GetConsoleOutputCP(void); SetConsoleOutputCP(850); ... SetConsoleOutputCP(pagina); // ao final Deve ser só isso. 
  16. O post de arfneto em É possível fazer o teste lógico de comparação de uma cadeia de char no while? foi marcado como solução   
    Na verdade não.
     
    O determinante é a declaração:
    char nome_comodo[30]; Tanto em C quanto em C++. nome_comodo é um ponteiro para char, e assim *nome_comodo é um char. E é o que temos.
     
    Em C++ tem a classe string e a classe string_view, e a aí você pode comparar diretamente strings porque nelas o operador '==' foi redefinido e para essa classe ele  incorpora a funcionalidade de strcmp() de varrer a string até o '\0' e ir comparando.
     
    Para comparar assim em C++ teria que declarar nome_comodo como string e rever o resto do programa.
     
    nome_comodo é um ponteiro para char e só pode ser comparado com outro ponteiro para char, em C ou C++.

    Exemplo (em C++ ou C)
    char nome_comodo[30] = { "teste" }; // [1] char* pChar = nome_comodo; char* outrop = NULL; if (pChar == nome_comodo) if (outrop == pChar) *(pChar + 1) = 'E'; Em C++ o igual em [1] é opcional e não recomendado. Está aqui exatamente pela razão que faz ele existir: portabilidade com código em C.
     
    Veja aí que nome_comodo vale "teste". Mas você só pode fazer comparações como essas aí. Comparando com outros ponteiros para char. O código não faz sentido: é um exemplo que digitei no meio de meu programa
     

     
    Essa deveria ir para o forum de lógica.

    Porque não funciona: duas coisas diferentes não podem ser iguais a uma terceira. A terceira coisa aqui seria o valor zero. Se a condição A for verdade a condição B será falsa e se a condição A for falsa a condição B poderá ser verdade, e assim ( A ou B ) será sempre verdade...
     
    Acompanhe:
    se nome_comodo for "fim" a primeira é falsa e a segunda é verdadeira e então a expressão A ou B é verdade se nome_comodo for "FIM" a primeira é verdadeira e a segunda é falsa, então a expressão A ou B é verdade se nome_comodo não for nem "fim" nem "FIM" as duas condições A e B são verdade e a expressão (A ou B ) é verdade A outra condição, A e B verdadeiro é impossível, como eu disse no início  Então a expressão escrita assim é sempre verdadeira e o while() nunca termina...
     
  17. O post de arfneto em Função para cálculo de volume de uma esfera foi marcado como solução   
    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 é '\'
     
  18. O post de arfneto em Imprimir .bmp com transparência? Windows API foi marcado como solução   
    🤔 A gente sempre desconhece mais do conhece...
     
    BOOL InvalidateRect( HWND hWnd, const RECT *lpRect, BOOL bErase ); Estou escrevendo sem pensar muito, mas talvez deva chamar essa rotina pra avisar o sistema de que algo mudou na janela, se isso não aconteceu por si
  19. O post de arfneto em Substituir dados em arquivo binário (c++) foi marcado como solução   
    Então alterou o  [10] para [20]. Muito bem. Era essencial porque iria corromper o nome, como deve ter visto.
     
    Sobre as diferenças, digitando em cima de seu programa vou postar um programa em C++ que faz isso. No fundo é o seu programa com as correções que incluiu, e usando a outra linguagem. Pode ser útil a outros já que tem o programa em C acima.
     
    As diferenças em um EXEMPLO
     
    Em C++ é muito mais fácil criar modelos de coisas. O cara que escreveu tinha isso como objetivo maior o que ele chamava de "abstrações de custo zero". Nos '80. E acho que conseguiu.
     
    Uma classe Registros
     

     
    Tem maneiras mais C++ de escrever isso  e o trocadilho foi de propósito. Mas não quero gastar muito tempo e quero manter a familiaridade com o seu programa para ficar clara a vantagem de escrever assim
     
    Veja o tal polimorfismo por exemplo: eu posso criar registros especificando o nome do arquivo ou não. Nesse caso o programa usa "arquivos.txt" como padrão. E dentro dos registros tem uma estrutura registro que contem os campos de dados e assim eu posso tratar como unidade sem ter que especificar um a um.
     
    Veja que as funções cria() e le() e troca_o_segundo() fazem parte de registros e não ficam soltas pelo programa, e faz sentido porque elas só tem a ver com os registros. São chamadas métodos. E os métodos ficam encapsulados nas classes
     
    E cada ocorrência de registros --- são chamadas instâncias ---  tem seu nome_de_arquivo e seu contador de registros total. Ao declarar uma variável como sendo do tipo registros o sistema chama uma função com esse nome, a tal registros(). E você pode criar várias com o mesmo nome apenas mudando o tipo ou o número de argumentos. E só com isso já dá pra fazer muita coisa.
     
    A função main em C++
    registros um; if (um.total <= 0) return -1; // nao leu nada cout << "\nlendo os caras" << endl; um.le(); cout << "\nregrava o segundo" << endl; um.troca_o_segundo(); cout << "\nle de novo" << endl; um.le(); Veja que declarar a variável um como registro vai fazer com que o programa crie o arquivo. Veja a diferença:
    registros um; registros outro("outro.txt"); registros dois("maisum.txt"); No caso do primeiro vai usar o padrão "arquivos.txt" e nos outros vai usar o nome especificado.
     
    E como registros tem um campo total que é atualizado ao criar cada arquivo tudo fica mais simples. um.le() sabe qual arquivo vai abrir, assim como outro.le() e dois.le() e não é preciso mudar nada no programa para tratar múltiplos arquivos, já que são múltiplas classes. struct e classe é a mesma coisa nesse exemplo.
     
    Cada ocorrência de registros --- se chama instância --- tem um campo nome_do_arquivo que indica qual o arquivo a ser usado. Está encapsulado.
     
    O "método" cria()
    int cria(const char* nome_do_arquivo) { int N = 0; registro rec; ofstream arquivo(nome_do_arquivo, ios::out | ios::binary); if (!arquivo) { cout << "Erro ao abrir " << string(nome_do_arquivo) << "!!!\n\n" << endl; exit(-1); }; string nome; cout << "\n[Tecle 0 para encerrar] Nome: " << flush; cin >> nome; while (nome != "0") { N += 1; strncpy(rec.nome, nome.c_str(), 20); cout << "Nome: " << string(rec.nome) << endl; cout << "Idade: " << flush; cin >> rec.idade; cout << "Altura: " << flush; cin >> rec.altura; arquivo.write((char*)&rec, sizeof(rec)); cout << "\n[Tecle ENTER para encerrar] Nome: " << flush; cin >> nome; }; // while() arquivo.close(); return N; // retorna quantos leu }; // cria() Em C++ você pode usar write() close(0 e read() para manipular o arquivo. 
     
    troca_o_segundo() em C++
    int troca_o_segundo() { registro rec{ "Maria", 15, 1.55f }; int N = sizeof(registro); int lidos = 0; ofstream arquivo(nome_do_arquivo, ios::in | ios::out); if (!arquivo) { cout << "Erro ao abrir " << string(nome_do_arquivo) << "!!!\n\n" << endl; return 0; }; arquivo.seekp(N); arquivo.write((char*)&rec, sizeof(rec)); arquivo.close(); return 0; }; // troca_o_segundo() É bem simples. Note que o seek é feito em unidades de N que é o tamanho do registro. Então se você mudar o registro para incluir campos não precisa mexer nessas coisas aqui.

    Esse programa de teste mostra
     
    [Tecle 0 para encerrar] Nome: Ana Nome: Ana Idade: 12 Altura: 1.5 [Tecle ENTER para encerrar] Nome: Bia Nome: Bia Idade: 13 Altura: 1.5 [Tecle ENTER para encerrar] Nome: Cris Nome: Cris Idade: 12 Altura: 1.5 [Tecle ENTER para encerrar] Nome: 0 lendo os caras Registro: [ Nome: Ana, idade: 12, Altura: 1.5 ] Registro: [ Nome: Bia, idade: 13, Altura: 1.5 ] Registro: [ Nome: Cris, idade: 12, Altura: 1.5 ] regrava o segundo le de novo Registro: [ Nome: Ana, idade: 12, Altura: 1.5 ] Registro: [ Nome: Maria, idade: 15, Altura: 1.55 ] Registro: [ Nome: Cris, idade: 12, Altura: 1.5 ] [Tecle 0 para encerrar] Nome: Jhonny Nome: Jhonny Idade: 65 Altura: 1.85 [Tecle ENTER para encerrar] Nome: 0 lendo os caras Registro: [ Nome: Jhonny, idade: 65, Altura: 1.85 ] regrava o segundo le de novo Registro: [ Nome: Jhonny, idade: 65, Altura: 1.85 ] Registro: [ Nome: Maria, idade: 15, Altura: 1.55 ] E aqui está o programa que cria dois arquivos só pra mostrar que nada muda
    #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <fstream> using namespace std; struct registros { const char* nome_do_arquivo; int total; struct registro { char nome[20]; int idade; float altura; }; registros() : nome_do_arquivo("arquivo.txt") { total = cria(nome_do_arquivo); }; registros(const char* nome) : nome_do_arquivo(nome) { total = cria(nome_do_arquivo); }; int cria(const char* nome_do_arquivo) { int N = 0; registro rec; ofstream arquivo(nome_do_arquivo, ios::out | ios::binary); if (!arquivo) { cout << "Erro ao abrir " << string(nome_do_arquivo) << "!!!\n\n" << endl; exit(-1); }; string nome; cout << "\n[Tecle 0 para encerrar] Nome: " << flush; cin >> nome; while (nome != "0") { N += 1; strncpy(rec.nome, nome.c_str(), 20); cout << "Nome: " << string(rec.nome) << endl; cout << "Idade: " << flush; cin >> rec.idade; cout << "Altura: " << flush; cin >> rec.altura; arquivo.write((char*)&rec, sizeof(rec)); cout << "\n[Tecle ENTER para encerrar] Nome: " << flush; cin >> nome; }; // while() arquivo.close(); return N; // retorna quantos leu }; // cria() int le() { registro rec; int N = sizeof(registro); int lidos = 0; ifstream arquivo(nome_do_arquivo, std::ifstream::binary); if (!arquivo) { cout << "Erro ao abrir " << string(nome_do_arquivo) << "!!!\n\n" << endl; return 0; }; arquivo.read( (char*) &rec, N); while (arquivo) { lidos += 1; cout << "Registro: [ " << "Nome: " << string(rec.nome) << ", idade: " << rec.idade << ", Altura: " << rec.altura << " ]" << endl; arquivo.read((char*)&rec, N); }; arquivo.close(); return lidos; } int troca_o_segundo() { registro rec{ "Maria", 15, 1.55f }; int N = sizeof(registro); int lidos = 0; ofstream arquivo(nome_do_arquivo, ios::in | ios::out); if (!arquivo) { cout << "Erro ao abrir " << string(nome_do_arquivo) << "!!!\n\n" << endl; return 0; }; arquivo.seekp(N); if (!arquivo.good()) return -1; arquivo.write((char*)&rec, sizeof(rec)); arquivo.close(); return 0; }; // troca_o_segundo() }; int main() { registros um; if (um.total <= 0) return -1; // nao leu nada cout << "\nlendo os caras" << endl; um.le(); cout << "\nregrava o segundo" << endl; um.troca_o_segundo(); cout << "\nle de novo" << endl; um.le(); registros outro("outro.txt"); if (outro.total <= 0) return -1; // nao leu nada cout << "\nlendo os caras" << endl; outro.le(); cout << "\nregrava o segundo" << endl; outro.troca_o_segundo(); cout << "\nle de novo" << endl; outro.le(); return 0; }  
    C++ é uma linguagem "enorme".  Há muitas e distintas maneiras de fazer quase tudo. Mas acho que dá pra comparar os dois programas fazendo a mesma coisa.
     
    Herança, polimorfismo, templates, private/public, encapsulamento, lambdas, functors, a própria biblioteca padrão... É algo grande. Mas é muito produtiva.
     
     
     
     
  20. O post de arfneto em Migrar licença fpp de um computador para outro?(é possível?/como fazer?)/OEMtbm? foi marcado como solução   
    Sim. Você pode "transferir" a licença para outra máquina. No caso do OEM não, porque quem pagou por ela foi o fabricante. Ela vai junto com a máquina. E pode ser invalidada mesmo assim, se você trocar a CPU ou a placa-mãe. 
  21. O post de arfneto em Arvore Binária String Não Imprime Dados foi marcado como solução   
    arv* insere(arv* raiz, arv arvoree) { int i = 0; arv* a; if (i == NULL) { a = (arv*)malloc(sizeof(arv)); strcpy(a->nome, arvoree.nome); strcpy(a->email, arvoree.email); strcpy(a->endereco, arvoree.endereco); strcpy(a->dataAniversario, arvoree.dataAniversario); a->idade = arvoree.idade; a->esq = NULL; a->dir = NULL; Não tive tempo ainda de olhar o seu programa, vou ver daqui 1h ou duas.
     
    Uma coisa que posso dizer agora é que essa maneira de escrever é muito arriscada para desenvolver e testar. E lerda. E nada produtiva na hora de usar. 
     
    Isso também
    void busca(arv nomeBusca, arv* raiz) { printf("\nInsira o nome de busca:\n"); gets(nomeBusca.nome); if (strcmp(nomeBusca.nome, raiz->nome) == 0) { printf("\nNome: %s\n", raiz->nome); printf("Email: %s\n", raiz->email); printf("Endereco: %s\n", raiz->endereco); printf("Aniversario: %s\n", raiz->dataAniversario); printf("Idade: %i anos\n\n\n", raiz->idade); } else { E declarar assim
    struct arvore { char nome[100]; char email[100]; char endereco[250]; char dataAniversario[10]; int idade; struct arvore* esq; struct arvore* dir; }; Prefira  sempre algo assim por exemplo:
    struct _carga { char nome[100]; char email[100]; char endereco[250]; char dataAniversario[10]; int idade; }; typedef struct _Carga Carga; struct _arvore { Carga* dados; Arvore* L; Arvore* R; }; typedef struct _arvore Arvore; Arvore* insere(Carga* dados, Arvore* arvore); Arvore* preOrder(Arvore* arvore); Arvore* inOrder(Arvore* arvore); Arvore* postOrder(Arvore* arvore); A razão:
    a tal struct Carga, que tem os dados, pode ser qualquer coisa. Em geral se declara mesmo como (void*). E você não usa mexe mais nisso a menos que ache um erro. O percurso pode receber um suposto endereço de arvore e ir devolvendo os nós conforme passa e aí você imprime. Você não imprime dentro da rotina de percurso, pelo mesmo motivo: percorrer a árvore é sempre igual. Você pode ter várias delas em seu programa. Você escreve isso, testa, coloca em um arquivo arvore.c e escreve um header arvore.h e nunca mais mexe nisso. Do modo como escreveu, e que é o normal, você resolve no máximo um problema. E demora.  
     
     
    adicionado 17 minutos depois
     
    @Cristian Leoncini que pretende com essa variável i ? Podia comentar seu código um pouco. 
     
    Se está contando com ela nas outras chamadas você tem um problema aí... O que era pra ser isso? 
     
    Você precisa mesmo usar uma árvore para isso? Uma lista parece mais prático. Trata-se de um enunciado?
  22. O post de arfneto em Alocação de memória com malloc foi marcado como solução   
    Veja na resposta julgada como melhor lá no artigo
     
     
    Ou seja: democracia é isso. Cada voto vale um e não sei como votaram nisso como a melhor resposta. E a gente tem essas surpresas nas eleições também, claro.

    Não me surpreende que você tenha ficado confuso. O sujeito não conseguiu se expressar de modo algum. Não é que não fosse recomendado? viável? necessário? Vírgulas fora de posição, "Certas ocasiões" é sacanagem. "Pode acabar trazendo problemas" mas são "causados por descuido do próprio programador" Sério?
     
    Esqueça
     
    Veja uma fonte mais séria no C FAQ que é uma compilação http://c-faq.com/malloc/cast.html e vai ler por exemplo
     
    On the other hand, some programmers prefer to make every conversion explicit, to record that they have considered each case and decided exactly what should happen (see also question 17.5). Also, the casts are typically seen in C code which for one reason or another is intended to be compatible with C++, where explicit casts from void * are required
    malloc() retorna void* e todos os ponteiros tem o mesmo tamanho então não faz diferença. Mas...
     
    Do mesmo C FAQ
     
     
    Eu postei ontem ou antes um código em C C++ e java para calcular os DV do CPF e você pode ver lá como é parecido. Eu peguei um exemplo em C que eu tinha postado aqui e copiei e colei no editor em java e C++ e mudei umas poucas linhas. Pode ver lá. malloc() pode ser usada ao invés de new em C++ e quando você está portando um programa grande vai gostar de não ter que se preocupar em alterar cada chamada a malloc(). E dificilmente vai  trocar todos malloc() por new e tal. Assim parece que o cara que escreveu no FAQ tinha razão.
     
    Eu sempre uso por questão de disciplina, pra deixar explícito o que estou fazendo. E com o hábito você não precisa ficar pensando em que linguagem está programando apenas para ter que inserir uma coisa tão simples como um cast. Eu sempre uso então se o próximo programa for em C++ não preciso pensar nisso. Eu nunca penso nisso  

    Na resposta longa lá no C FAQ Mark Brader, o autor, cita no item (b) a minha opinião:

     
    Não gosto de conversões implícitas. De nada implícito. Não uso em geral comandos com efeitos colaterais, como atribuições dentro de comandos como printf() ou while() por exemplo. Não gosto de misturar operadores em expressões, tipo || > e + sem parenteses contando com a prioridade dos operadores. Coisas assim eu acho que levam a uma vida mais tranquila. Mas é claro uma opinião apenas.
     
     
    Entendo. Mas isso não é garantido. Vai depender da implementação e até hoje não vi uma razão para contar com isso. Nem para saber um pouco mais, na verdade. Códigos fonte de malloc() estão disponíveis, mas nunca tentei ler, confesso.
     
     
    size_t é um unsigned int ou o que estiver lá no header. Nada tem a ver com o ponteiro diretamente. Se o ponteiro for do tamanho de um int size_T será um unsigned desse tamanho. Compilar para 64 bits é uma opção de compilação e eu uso se tiver uma razão objetiva para usar. Não sabia da campanha para "matar binários de 64 bits". Porque alguém se preocupa com isso?
  23. O post de arfneto em Realocar capacidade de um vetor foi marcado como solução   
    Sim. E pode não "limpar" durante a execução de seu programa, como eu te disse. E isso é bom. 

    Não é que as variáveis sejam inicializadas. É apenas um efeito colateral de uma política de segurança para evitar a injeção de código malicioso. Não conte com isso.
     
     
    Você entendeu perfeitamente. A técnica é válida e realloc() foi escrita para isso: aumentar ou DIMINUIR a área alocada. Mas quase não se usa. É uma rotina um tanto odiada.
     
    Para diminuir está bem. 
     
    O problema é quando aumenta o tamanho da área alocada: A razão é a mesma de não ser esperto inicializar a memória alocada: controle. E custo. 
     
    Eis o que acontece:
     
    A primeira coisa que realloc() faz é comparar o tamanho atual e o solicitado. Se vai diminuir a área correspondente é liberada, contadores internos são reajustados e pronto.
     
    Mas se vai aumentar nada garante que vai ser usado o mesmo endereço inicial. E provavelmente não vai. Isso quer dizer que realloc() vai copiar todo o conteúdo já existente para uma nova área com o novo tamanho. 
     
    Antes que você pergunte: nada pode ser assumido em relação ao conteúdo da parte nova da área. O original vai estar lá, igualzinho. Garantido. A parte nova vai estar lá do jeito que foi entregue pelo sistema. 
     
    Mas copiar tudo de um lugar pro outro pode demorar muito e pode acontecer numa hora errada. Se seu programa está fazendo outras coisas, ou mesmo o sistema como um todo, pode acontecer desse atraso na cópia ser um problema e você não tem como controlar: pode mudar os tempos de resposta e atrasar algo importante.
     
    Por isso em geral se usam outras técnicas, como páginas de alocação, um mapa onde você aloca em unidades grandes uma por vez. Ou estruturas dinâmicas onde você aloca um a um mesmo, como listas ou árvores.
  24. O post de arfneto em Criando imagens em C foi marcado como solução   
    Olá
     
    gerar uma imagem é como gerar qualquer outro arquivo. 
    Deve saber o que pretende fazer com essas imagens. Se for interesante comprimir a imagem mas puder aceitar alguma perda na representação pode usar jpg ou png. Se quer uma imagem fiel pixel a pixel em relação ao que o programa gerou, porque talvez vá continuar calculando algo sobre ela, use bitmaps BMP, mesmo que não seja para Windows. Se precisa poder ampliar sem perder detalhes use algo vetorial como PDF. 
     
    Para cada caso tem uma especificação para ler. Mas não é especialmente complicado. Postei meses atrás um programa em C que gerava um bitmap e tinha algumas funções para ler, salvar e preencher. Deve poder localizar aqui na pesquisa do forum por exemplo. Não me lembro agora.
    adicionado 7 minutos depois Foi em janeiro. Era um programa em C++ mas o que importa são os headers onde tem os formatos todos. E tem só duas funções. seria trivial reescrever.
     
     
  25. O post de arfneto em Struct de arquivo csv com erro de reconhecimento de variáveis. foi marcado como solução   
    Olá
     
    Ainda está um pouco longe de funcionar.
     

     
    Podia fazer um programa primeiro só para ler os dados do arquivo, para se assegurar de que está no caminho certo...
     
    Podia usar nomes mais significativos que dado e dado_t por exemplo.
     
    Se dado_t é um ponteiro para dado onde vai afinal gravar esses dados de que sdegundo o enunciado do tópico você nem precisa? Não declarou nada...
     
     
    Para que a struct se só quer contar os registros? E se na  primeira linha estão os nomes dos campos porque não ler afinal? E se o valor  é temperatura (é?) porque não chamar de temperatura, ou value já que é o nome original?  Ninguém leva a sério uma variável chamada temp ou aux afinal  
     
    fscanf() retorna um número que você deveria tratar. É melhor assim. Um campo a menos e sua leitura pode ficar toda destruída... Recomendo muito SEMPRE fazer isso.
     
    E se dado_t é um ponteiro e você passa o endereço dele para fscanf() tudo que vai conseguir é corromper o próprio valor do ponteiro. Que por sinal não aponta para nada já que você não alocou memória para nenhuma dessas struct....
     
    Podia ter postado ao menos as primeiras linhas do csv direto para poupar trabalho. Afinal apenas as duas primeiras já serviriam. Esse é o sentido de um arquivo csv. A gente precisa da primeira linha para saber o número dos campos e o nome. E depois vem os campos, um registro por linha, um campo entre cada delimitador.

    Veja a diferença:
     

     
    Compare com clicar em um anexo, baixar um programa, abrir um anexo em outro programa e depois voltar ao seu programa para tentar ajudar você. . .
     
    De volta ao programa:
     
    O CSV começa então pelo header, a linha que tem o nome dos campos. O formato dela não é novidade desde os anos 80
    os nomes separados pelo delimitador que em geral é a vírgula.  fscanf() então deve ler esses 3 campos sem problemas porque afinal foi esrita para isso nos '70: ler entrada formatada. Qual o o formato?
     
    um nome, uma vírgula, um nome, uma vírgula e o último nome. Qual a máscara para ler qualquer coisa que não seja uma vírgula? abcd] por exemplo quer dizer que aceita essas letras, quantas vier. [^abcd] que dizer que aceita qualquer coisa exceto a b c e d.  
    Então [^,] lê o que tiver até a próxima vírgula. Como são 3 campos é só repetir. E desprezar as vírgulas.
     
    Sua máscara para os dados está certinha.
     
     Um exemplo
     
    O programa abaixo lê o arquivo e mostra os valores na tela assim
    fscanf(3) leu 'Series' + 'Value' + 'Time' 1: 0 37.9 2018-11-18T08:41:03-02:00 2: 1 37.9 2018-11-18T08:41:13-02:00 3: 2 37.9 2018-11-18T08:41:23-02:00 4: 3 37.9 2018-11-18T08:41:33-02:00 ... 97: 96 35.8 2018-11-18T09:00:30-02:00 98: 97 35.8 2018-11-18T09:00:40-02:00 99: 98 35.8 2018-11-18T09:00:50-02:00 99 leituras no arquivo O programa
    #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <locale.h> struct dado { int c_series; float c_value; char c_time[64]; }; typedef struct dado Dado; int main(int argc, char** argv) { const char* mascara_campos = "%[^,]%*1c%[^,]%*1c%s"; const char* mascara_dados = "%d,%f,%s"; Dado linha; FILE* csv = fopen("camera_temp.csv", "r"); int n = 0; int quantos = 0; char nome[3][30]; n = fscanf( csv, mascara_campos, &nome[0][0], &nome[1][0], &nome[2][0]); printf("fscanf(%d) leu '%s' + '%s' + '%s'\n", n, nome[0], nome[1], nome[2]); do { // le os caras ate o fim n = fscanf(csv, mascara_dados, &linha.c_series, &linha.c_value, linha.c_time ); if (n == 3) { quantos = quantos + 1; printf("%3d: %8d %8.1f %s\n", quantos, linha.c_series, linha.c_value, linha.c_time ); } } while (n == 3); printf("\n%d leituras no arquivo\n", quantos); fclose(csv); return 0; }; Está certo?
     
    Não. Apesar de mostrar o que está lá. 
     
    Num arquivo csv não precisa ter os 3 valores. Tem que aceitar campos com por exemplo
     
    Series,Value,Time 1,2.9, teste ,2.9, ,,valido 1,, Todos esses campos são válidos. Quando o campo está em branco basta ter o delimitador depois para ser considerado válido. Esse troço é importante. Todos os bancos de dados leem CSV, os programas de planilhas e até aquele seu programinha de imprimir etiquetas que vinha em diskette nos anos 90   E esse programa não vai funcionar nesses casos. É só um exemplo.
     
    Um arquivo CSV é uma matriz de  valores [x,y] onde x é o número de linhas e y o número de campos descritos na primeira linha. E scanf() falha quando algum campo está vazio.
     
    Referência considerada oficial sobre o formato CSV
     
    Mas é um começo 

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

×
×
  • Criar novo...