Ir ao conteúdo
  • Cadastre-se

arfneto

Membro Pleno
  • Posts

    6.252
  • Cadastrado em

  • Última visita

Tudo que arfneto postou

  1. Acho que seu programa não está bom. Algumas notas além do que eu já falei, agora que li o resto: apesar de ter uma função inicialização e uma função insere_na_lista_vazia e uma aloc() com parâmetro e tudo, você aloca memória no programa principal, fora (!) dessas funções. É perda de tempo. Imagine se você tivesse duas listas... tem um menu lá, que devia ser a última coisa a escrever e não a primeira, e provavelmente não daquele modo. Sia lista usa um dado char* e não acho que era o que pretendia. Isso é problema: você precisa realocar todos esses dados ou os ponteiros serão invalidados logo em seguida. char* é um ponteiro e precisa alocar antes de colocar na árvore: não pode ir inserindo dados que você acabou de ler, por exemplo. Adicionar o primeiro elemento não deve ser diferente de adicionar qualquer outro. Ao menos não se não quiser trabalhar a toa. a opção 4 acaba testando para toda a vida se só tem um nó na lista? Não é prático. case 4: if (lista->tamanho == 1) { printf("Utilizar a inserção no início ou no fim (Entrar Menu: 1 ou 2)\n"); break; } Tem que ter outro jeito de escrever isso O menu bem que poderia simplesmente retornar a opção para tratar no programa que o chamou. Seria bem comum. E é comum porque é mais simples e prático. Em geral se implementa primeiro listar() depois algum inserir() e remover() e se parte daí. Boa sorte adicionado 13 minutos depois acentos nos comentários e nas mensagens não acrescentam nada num primeiro momento. Não devia perder tempo com essas coisas. Veja esse trecho que poderia estar em seu programa, e vai entender do que estou falando: // cria a lista e insere 10 caras dl_Lista* teste = NULL; for (int i = '0'; i <= '9'; i = i + 1) { ins_inicio_lista(teste, (char*)&i); // insere 'i' exibe(teste); }; // for() // remove o primeiro 10 vezes for (int i = '0'; i <= '9'; i = i + 1) // claro que copiei o loop { REMOV( teste, 1); // remove o primeiro exibe(teste); }; // for() destruir(teste); // apaga a lista exibe(teste); // tenta mostrar a lista vazia Esse trecho deveria: criar uma lista chamada teste. inserir os valores '0', '1'... '9' listando o conteúdo entre cada inserção para você ficar mais seguro. remover o primeiro elemento 10 vezes, o que deve deixar a lista vazia. E listando entre cada um pra você acompanhar apagar a lista tentar listar a lista vazia Assim você progride mais rápido. Espero que ajude
  2. entenda que tem coisas dessas que eu te expliquei que são importantes justamente para quem está começando ou simplesmente porque se está começando. . Sem essas coisas você vai levar MUITO mais tempo para resolver seu problema. Em particular: não retornando o endereço da lista para funções que podem mudá-lo criando funções sem necessidade, como essas que alocam nós e iniciam a lista criando tipos fixos de dados E coisas assim. Para um profissional ou um especialista não faz diferença. Apenas existe uma convergência entre esses caras --- e os autores de livros sobre essas coisas --- de modo que os programas acabam quase idênticos, o que provavelmente indica que eu estou certo... Vou ler o resto do seu programa
  3. int insercao_em_uma_lista_vazia(dl_Lista* lista, char* dado) { dl_elemento* novo_elemento; if ((novo_elemento = aloc(novo_elemento)) == NULL) return -1; ... Meu compilador por exemplo reclama desse tipo de construção. Afinal novo_elemento não foi inicializado antes de entrar na comparação. E não é uma prática recomendada afinal. Inicialize TODAS as variáveis. Recomendo também evitar atribuições dentro de condições. Acaba dificultando a leitura apenas. Isso se você não esquecer um parenteses para manter a prioridade correta. É mais problema do que solução. Compare: int insercao_em_uma_lista_vazia(dl_Lista* lista, char* dado) { dl_elemento* novo_elemento = aloc(); if (novo_elemento == NULL) return -1; ... Veja como fica mais fácil de ler. E mais seguro. Não é comum: ter uma função para criar um elemento --- a tal aloc() ter um parâmetro na função aloc() que parece fazer sempre a mesma coisa. Ela não parece precisar de um argumento de entrada, como seria o caso se pudesse criar um número arbitrário de elementos... Apenas importa o valor retornado ter uma função para inserir um elemento numa lista vazia que chama uma função que aloca um nó da lista E em geral é mais seguro retornar não int mas sim o endereço da lista, que pode ter mudado. Em geral você escreve apenas LISTA* inserir( DADO*, LISTA*); já que é a acepção mais comum em português: vai inserir um dado na lista, então passa o endereço do dado e o endereço da lista. Sugiro inverter os parâmetros. E recebe o endereço de início da lista, que pode ter mudado E declarar os dados como um tipo interno, ou o mais comum, (void*). A razão é muito simples: você não quer editar essas funções para tratar a próxima lista no exercício da semana que vem... Sabe, a tal lista de livros, a playlist, a lista de produtos na nota fiscal... Mais do mesmo... Se prepare... Compare: typedef char DADO; ja serviria Apenas isso e você poderia usar typedef struct dl_elementoLista { DADO* dado; struct dl_elementoLista* anterior; struct dl_elementoLista* seguinte; } dl_elemento; // ao invés de typedef struct dl_elementoLista { char* dado; struct dl_elementoLista* anterior; struct dl_elementoLista* seguinte; } dl_elemento; // mas veja int ins_em_uma_lista_vazia(dl_Lista* lista, DADO* dado); int ins_inicio_lista(dl_Lista* lista, DADO* dado); int ins_fim_lista(dl_Lista* lista, DADO* dado); int ins_depois(dl_Lista* lista, DADO* dado, int pos); int ins_antes(dl_Lista* lista, DADO* dado, int pos); E ao mudar os dados não precisaria mexer nessas funções. Não use nomes de variáveis nos protótipos. Não são usados. E em geral não é preciso testar se a lista está vazia. Na hora de inserir, se você passa o endereço da lista como NULL --- 0 no popular --- a rotina de inserção cria a lista silenciosamente. Isso permite escrever coisas assim sem ter que pensar LISTA* umaLista = inserir( &dado, NULL); // cria a lista e insere o primeiro registro LISTA* umaOutraLista = inserir( NULL, NULL); // cria uma lista vazia ... umaOutraLista = inserir( &lidoAgora, umaOutraLista); // insere algo na segunda lista E funciona. Se está escrevendo métodos para inserir no fim e no início e na posição, talvez devesse ter um para inserir na ordem e crie na lista um ponteiro para o fim. Porque perder tempo percorrendo a lista para inserir no final se você tem o controle sobre o processo de inserção? adicionado 3 minutos depois Os protótipos servem para o compilador não para o leitor. Use main() sempre como a primeira função. Em especial se trabalha com mais gente ou se pode pedir ajuda para alguém ler seu programa. E use alguma ordem nas funções, como a ordem alfabética comum. O tempo passa, os programas ficam grandes e tal...
  4. ajudaria você dizer qual compilador está tentando usar e quem sabe a saída da compilação... adicionado 0 minutos depois talvez tenha.
  5. A janela corrente é a que vai receber os caracteres teclados. Se mudar de aplicação vai mudar o foco Pode explicar mais sobre a mecânica do que quer fazer?
  6. arfneto

    C++ Lista de maior número

    cin >> num; aux = num; Essa é uma construção curiosa. Ao invés de ler num para imediatamente copiar para aux, sugiro usar como descrito no tópico #6 logo acima e usar o simples cin >> aux; Sobre esse loop, for(i = 2; i < 16; i++){ cout << "\nDigite o número " << i << ":"; cin >> num; Ao invés de usar <16 prefira o mais óbvio para quem leu o enunciado e está lendo seu programa, e escreva <= 15 Sobre isso: esta é a razão de existirem as constantes em limits.h, para que nos programas se possa usar sempre as contantes. Se optar por essa solução, como está descrito em outros tópicos acima, use INT_MIN e INT_MAX e tal... adicionado 2 minutos depois Sobre os livros, eu recomendaria o simples, "A linguagem de programação C" segunda edição, de Kernighan e Ritchie Sua escola não tem uma biblioteca virtual que você pode acessar, tipo https://www.oreilly.com/ ? Muitas escolas assinam esses serviços e aí você pode acessar muitos livros e escolher algo. Você pode assinar por um mês de graça também. Vi agora o que tem a venda na Amazon.com.br mas está tudo muito caro eu achei
  7. O simples é: para cada possível linha você identifica o elemento mínimo e, de posse desse valor, verifica se ele é o maior valor da coluna EM QUE ELE ESTÁ. Um loop que gera um par de valores [v,j] onde v é o valor e j a coluna. Com esses valores você verifica num outro loop um outro valor [x] que é a posiçao na coluna j que tem o maior valor da coluna. Se x for igual a v você tem o tal ponto de sela e pode retornar o valor e encerrar a busca. Basta retornar o primeiro ponto de sela afinal.
  8. arfneto

    C++ Lista de maior número

    Tem toda razão. Mas são 15 números. Aí o cara digita 15 vezes o número -4 por exemplo... Ele acha que o maior foi... -4. O seu programa diz que foi 0. Só que o zero ele não digitou. Pois é. O zero é maior mas não está na lista. Isso que escreveu não faz sentido: Lendo só a primeira sentença o maior é zero, só que o cara não digitou o zero. Lendo o parágrafo não fica melhor: Se fosse em módulo estaria "mais errado" já que o zero seria claro o menor e NUNCA o maior. Sabe o que é módulo, então... todos seriam positivos. Como resolver? Modo 1: Uma maneira eu te disse já. O menor número possível é -2147483648. Basta iniciar a série por esse valor. Onde eu arrumei esse valor? No livro. Você não tem um livro? Um manual? C tem um arquivo chamado limits.h que você pode incluir em seu programa e tem esses valores bem convenientemente disponíveis. Basta usar #include "limits.h" // em seu programa. E declarar ao invés de int aux = -2147483648; a constante int aux = INT_MIN; Afinal os menores números que o cara pode digitar são 15 desses e mesmo assim seu programa vai dizer o menor certinho. Eis um pedaço de limits.h, copiado de https://www.tutorialspoint.com/c_standard_library/limits_h.htm Modo 2: Mais ingênuo mas sem chance de errar: leia o primeiro número em aux antes do loop. Fazendo o simples, lê o primeiro número em aux e os outros 14 em num... E no loop usa os índices certos já: é mais legível ler os números até <= 15 do que <16. Porque deixar o cara que está lendo o programa fazer uma subtração de cabeça se pode ser mais claro no texto? int main(){ setlocale(LC_ALL, ""); int num = 0; int maior = 0; cout << "\nDigite o primeiro número: "; cin >> maior; for(int i = 2; i <= 15; i++) { cout << "\nDigite o número " << i << ":"; cin >> num; if(num > maior) maior = num; } cout << "O maior número da lista é: " << aux << "."; return 0; } Uma nota Sobre esse if em seu programa if(num >= aux){ num = aux; } else{ aux = aux; } Acho que escreveu a meiga linha aux = aux porque queria completar o if e não tinha o que fazer. Então colocou um comando inofensivo. Está difícil de ler com aquelas chaves todas e essa expressão. E está errado também. Tudo o que você queria escrever era: se o valor lido for maior que os lidos até agora salva o valor em aux. Só isso. Então escreva só isso. if (num>aux) aux = num; E a condição está errada. Para que vai copiar um número se foi igual? E inverteu as condições escrevendo num = aux, como @devair1010. te mostrou. E se é o seu programa e só tem 3 variáveis, porque não chamar de algo mais ilustrativo o tal aux, algo tipo maior, maior_numero, MaiorAteAqui? Quanto ao comando if: Não precisa de chaves quando o if só tem uma instrução. Não precisa escrever um else quando ... não precisa fazer nada se a condição for falsa...
  9. arfneto

    C++ Lista de maior número

    ok ok tudo certo até entrar com 15 números negativos e seu programa dizer que o maior é zero... Um int é isso, um inteiro entre -2147483648 e +2147483647 no caso de 4 bytes... está errado ainda. O que pretendia com essa linha? aux = aux; fiquei curioso
  10. #include<stdio.h> main () { int vium=1, vfum=1,vidois=2, vfdois=2; printf("\n Entre com o valor inicial: "); scanf("%d%d", &vium,&vidois); printf("\n Entre com o valor final: "); scanf("%d%d", &vfum,&vfdois); vium--; vfum--; vidois++; vfdois++; } Espero que durante esses dias você tenha pensando um pouco mais sobre isso. Isso que conseguiu fazer quer dizer: diminuir um de duas variáveis e somar um em outras duas. E encerrar o programa sem contar nada para ninguém. E uma leitura estranha de dois valores (plural) com uma mensagem no singular. Como o cara que roda seu programa vai adivinhar que ao ler ele deve digitar dois valores? Claro, se ele usar de paranormalidade e conseguir da primeira vez vai conseguir da segunda, porque logo depois você escreve a mesma coisa para ler o valor final. Talvez tenha escrito isso só pra postar algum código no tópico e ele não ser excluído afinal... Esse enunciado não fala nada sobre duas séries: é só um exemplo o que tem lá, citando dois casos, uma lista ascendente e uma descendente. Basta ler os parâmetros e gerar uma série Imagino que isso tenha vindo depois de alguma aula sobre loops loops em C Em C há 4 comandos claros de loop: for while do goto E imagino que tenha um livro ou uma apostila sobre isso. o comando for é dessa lista o mais próximo do seu problema. Veja a sintaxe (https://www.tutorialspoint.com/cprogramming/c_for_loop.htm) e seu enunciado ma sé claro de qualquer um dos 4 serviria
  11. Sim, deve ter ao menos uma função. Esse caixa nem se compara com as ATM de hoje em dia É um caixa minimalista, sem 3 ou 4 gavetas de notas, sem gaveta de rejeição, sem depósitos, sem extratos, pagamentos, serviços de massagem, venda de ingressos e afins. Então uma função saque() combina. E para ficar parecido com um caixa desses, uma tabela de mensagens como por exemplo Assim o saque devolve um int: o número de notas dispensadas ou um índice negativo que dá o número da mensagem na tabela. Como uma ATM de verdade. E controla o saldo lá dentro da função mesmo. A saída de um exemplo seria assim Valor do SAQUE: 1 Valor desejado nao e multiplo de R$10 Valor do SAQUE: 10 1 nota dispensada Valor do SAQUE: 10 1 nota dispensada Valor do SAQUE: 80 8 notas dispensadas Valor do SAQUE: 9900 990 notas dispensadas Valor do SAQUE: 10 Falta de notas Valor do SAQUE: 20 Falta de notas Valor do SAQUE: -1 Fechando o caixa... Resumo: não se esqueça da função. Concentrar as mensagens no início facilita muitas coisas --- o compilador faz isso, por exemplo.
  12. Então não foi você que escreveu esse código? O que você escreveu disso? O que está tentando resolver?
  13. 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.
  14. Esse problema envolve avaliar 3 coisas em uma série de números inteiros lida do teclado e terminada por -1 a distribuição dos pares e ímpares a soma dos números os limites: o maior e o menor número Os erros mais comuns para o programa --- e que apareceram no tópico --- afetam muitos desses programas para iniciantes então acho que é algo útil para o forum. Condições comuns de erro: números muito grandes e o aluno achou que usar algo como 99999 resolveria para achar o maior e 0 para o menor números negativos desprezados quando a entrada é um inteiro série de constantes: com todos os números iguaizinhos e o aluno pega esse número como maior ou menor para sempre porque não salvou o maior e menor ao menos uma vez séries crescentes ou decrescentes onde sempre entra para o maior ou menor e o outro lado da condição nunca é visitado No geral o loop do programa deve avaliar as 3 condições e ler o próximo número. Pode ler antes ou depois e aí temos as condições que se viu aqui nos tópicos anteriores. Como a maioria desses exercícios, a lógica é como a do comando for: inicialização, condição final do loop e teste. O loop mínimo pode ser algo assim, e reflete claramente o enunciado. @AdrianoSiqueira note que se escrever assim não tem artifícios no loop, apenas a lógica do problema. E sequer precisa de constantes limite. while (num != -1) { if (num % 2 == 0) // par pares++; else impares++; // impar soma = soma + num; // soma if (num > maiornum) maiornum = num; // maior else if (num <= menornum) menornum = num; // menor printf("Digite um numero: "); scanf("%d", &num); }; // while() Note que o segundo if só funciona se na inicialização se tiver considerado os valores de menor e maior ANTES de entrar no loop, ou vai falhar para séries crescentes ou decrescentes Note que no segundo if um dos sinas tem que ter = ou vai falhar para séries constantes Note que se não ler ao final do loop vai ter que acrescentar uma condição extra no início logo depois da leitura e que vai saltar todo o loop. Se mudar a lógica para usar do{}while não vai mudar muito porque vai ter que saltar o loop de todo modo , Uma solução mínima incluindo o sugerido por @Simon Viegas , uma mensagem para o final prematuro e o else para o > <= com a ressalva que está acima: se não inicializar de acordo pode falhar para séries crescentes ou decrescentes... Assim como está ok int main(int argc, char** argv) { int soma = 0, pares = 0, impares = 0; int num = 0; printf("Digite um numero: "); scanf("%d", &num); if (num == -1) { printf("Encerrando sem dados apresentados\n"); return; } int maiornum = num; // o primeiro e o maior int menornum = num; // e o menor while (num != -1) { if (num % 2 == 0) // par pares++; else impares++; // impar soma = soma + num; // soma if (num > maiornum) maiornum = num; // maior else if (num <= menornum) menornum = num; // menor printf("Digite um numero: "); scanf("%d", &num); }; // while() printf("\n Quantidade de numeros pares:%d\n", pares); printf("\n Quantidade de numeros impares:%d\n", impares); printf("\n A soma dos numeros e igual a:%d\n", soma); printf("\n Maior numero:%d\n", maiornum); printf("\n Menor numero:%d\n", menornum); fgetc(stdin); } Alguns resultados Digite um numero:-2 Digite um numero:-3 Digite um numero:2 Digite um numero:3 Digite um numero:-1 Quantidade de numeros pares:2 Quantidade de numeros impares:2 A soma dos numeros e igual a:0 Maior numero:3 Menor numero:-3 --- Digite um numero:-1 Encerrando sem dados apresentados --- Digite um numero:-2 Digite um numero:-2 Digite um numero:-2 Digite um numero:-2 Digite um numero:3 Digite um numero:-1 Quantidade de numeros pares:4 Quantidade de numeros impares:1 A soma dos numeros e igual a:-5 Maior numero:3 Menor numero:-2
  15. Eu ia em testar isso no gcc no próximo programa que eu fosse escrever com ele. Eu quase não uso. Estranho mesmo nenhum programa da biblioteca padrão usar essas contantes. Recriaram esses valores dentro das rotinas por alguma razão. Obrigado por postar!
  16. Tem razão. Mas o modo como escreveu, e que é o mais comum, repete o teste da condição final em todos os ciclos do loop. E fica mais difícil de ler porque é algo híbrido, um while-do-while pela condição que mostrei: a variável de controle do loop é redefinida logo no início de cada ciclo do próprio loop.
  17. Sim, claro. Tem razão. Ou não. Pense nesses casos: os números entram em ordem decrescente. Nunca vai atualizar o maior, que vai ser o primeiro os números entram em ordem crescente. Nunca vai atualizar o menor, que vai ser o primeiro só tem um número: teria que executar os dois lados Foi assim que começou o tópico afinal... if (num > maiornum) maiornum = num; else if(num <= menornum) menornum = num; Escrevendo como eu escrevi o else seria mais correto, porque essa questão já foi resolvida antes de entrar no loop. Porque eu não escrevi assim? Porque eu mudei a condição depois e não voltei ao loop. My bad. Condição limite E ainda sobra uma condição limite, que é o caso de cada número que se repete na série. Você tem que colocar o igual em um dos lados do else. Muitos programas assim falham porque o aluno usa só > e < e quando vem todos os números iguais o programa falha... Pensem nisso
  18. imagino que corrigiu isso certo @Vinicius schmitz ? Poste o programa. Entendeu que escreveu um programa em C, certo?
  19. Essa é uma coisa interessante. Não imagino uma implementação de stdlib que não inclua limits. Basta pensar nas funções que estão na biblioteca padrão. Nunca usei um compilador online, mas é uma coisa interessante saber que isso pode acontecer. Obrigado por postar, @Simon Viegas Tem razão. Eu não tinha visto essa constante folclórica. O normal é usar stdlib.h e ela incluir claro limits porque é a biblioteca padrão e não é difícil imaginar que a biblioteca padão use constantes "padrão" como as estabelecidas em limits.h, E omo é difícil um programa desses que não use stdlib.h é raro usar limits.h diretamente, na prática. Veja no código: ao entrar no loop a primeira variável se não for -1 é a menor e a maior e a fila anda. Basta declarar depois de ler o primeiro número, como está lá: printf("Digite um numero:"); scanf("%d", &num); int maiornum = num; int menornum = num; while (num != -1) É claro que você poderia escrever logo depois da leitura e não ver, como mostrou Bastaria testar logo depois de ler o primeiro e encerrar o programa com uma mensagem de acordo, tipo "encerrando sem nenhum valor fornecido". No entanto esse é um exemplo para estudantes e essa é uma condição limite. Achei mais importante mostrar que lendo o primeiro elemento antes e preparando tudo para entrar no while o loop em si fica mais simples, com instruções simples para cada objetivo, e a leitura no final e não no início como é tradição entre estudantes. Se encerrase ali o cara teria menos ainda chance de entender que fazendo assim o programa segue sem entrar no loop e sem criar artifícios como repetir testes e criar flags. Esse é um padrão recorrente como vai ver sempre aqui nos exercícios postados neste forum. Na dúvida entre do e while eis o que o iniciante escreve: le o primeiro valor, pode pode ser algo como "deseja continuar?". Dentro do loop logo em seguida vem o teste para ver se vai encerrar e o código que pula todo o loop e depois vem o código normal Isso quer dizer que vai repetir ao menos um teste para todos os ciclos, e vai ter algum tipo de seleção dentro do loop, um break ou um else gigante que inclui TODO o código normal do loop. Se eu me lembrar, quando ver o próximo desses casos vou te indicar. É divertido até. Veja o exemplo do autor e do exemplo de @AdrianoSiqueira aqui. Se entrar -1 no inicio fica claro estranho, mas já é estranho alguém rodar o programa para encerrar sem entrar nenhum número, e o resultado mostrado não é muito mais estranho que isso Repetindo o exemplo Não há dúvida de que -1 é ímpar, mas essa é uma condição limite: o cara desistiu do programa apenas. E claro que o certo seria ter dado uma mensagem de acordo, mas eu queria mostrar o genérico: se você preparar o loop assim o código fica mais simples e legível.
  20. Seu programa não está bom. Do modo como escreveu é muito difícil de testar. Lerdo e chato. E é praticamente um programa em C. Use C++. É mais fácil. Objetivamente em relação ao seu programa: Ao ler o arquivo qual o propósito de chamar rewind() para um arquivo de acabou de abrir? Não vai fazer nada. Ao regravar o arquivo, em main(), não acha que devia chamar ler() de novo? Assim, digamos, mostraria de uma vez se gravou ou não? Não seria melhor espaçar a impressão dos registros e colocar um prompt avisando o que o programa está fazendo? Está usando um tamanho diferente na definição de nome na regravação. 10 e não 20. Não devia abrir o arquivo em append mode. Use "r+"e ele já fica posicionado no início.... Use C++. Defina uma struct ou class fora do programa. Se tivesse feito isso não teria errado o tamanho no substituir_Arq() por exemplo... adicionado 2 minutos depois A nota sobre o append mode se refere ao método substituir_arq2() onde usou "a+b". Pode usar apenas "r+"
  21. do { printf("Digite um numero: "); scanf(" %i%*c", &entrada); if (entrada == flag) break; { ... } } while (entrada != flag); @AdrianoSiqueira resumi acima o código do seu exemplo. Também poderia ser escrito como abaixo: do { printf("Digite um numero: "); scanf(" %i%*c", &entrada); if (entrada != flag) { ... } } while (entrada != flag); Trata-se de um do-while-while talvez? Um loop com teste no início e no fim pela mesma variável. É um while dentro de um do-while, porque reavalia a condição de saída do do-while logo no início do loop, lendo a variável de controle de novo, e as condições de saída são as mesmas: (entrada != flag) Isso pode ser simplificado assim printf("Digite um numero: "); scanf(" %i%*c", &entrada); while (entrada != flag) { ... printf("Digite um numero: "); scanf(" %i%*c", &entrada); } E assim não teria dois testes para cada loop pelo mesmo valor. E não precisaria mais das contantes INT_MIN e INT_MAX. Note que stdlib inclui limits então se inclui stdlib não precisa incluir limits. E nesse caso basta incluir limits porque só está usando as duas constantes mesmo.
  22. Acho que vai se sair bem. Entendeu que seu programa não funciona para números negativos? E entendeu que está testando sempre para ver se o primeiro é o primeiro, imagino... Abaixo está uma versão mais comum para esse programa. Rode na sua máquina e compare se achar útil. int main(int argc, char** argv) { int soma = 0, pares = 0, impares = 0; int num = 0; printf("Digite um numero:"); scanf("%d", &num); int maiornum = num; int menornum = num; while (num != -1) { if (num % 2 == 0) // par pares++; else impares++; // impar soma = soma + num; // soma if (num > maiornum) maiornum = num; if (num < menornum) menornum = num; printf("Digite um numero:"); scanf("%d", &num); }; // while() printf("\n Quantidade de numeros pares:%d\n", pares); printf("\n Quantidade de numeros impares:%d\n", impares); printf("\n A soma dos numeros e igual a:%d\n", soma); printf("\n Maior numero:%d\n", maiornum); printf("\n Menor numero:%d\n", menornum); fgetc(stdin); }
  23. Você entendeu o programa que está do lado direito? É mais simples ir por aquele caminho Exato. Mas há sempre as diretrizes da empresa, ou da escola, ou preferências pessoais e tudo. E há critérios como eficiência e legibilidade que são menos subjetivos. E de correção. Se você pensar nas leituras de seu programa vai ver que tem dois tipos de leitura: a primeira e as outras. A primeira vai iniciar os contadores se não optou pelo simples uso das contantes como te expliquei. E as outras são idênticas, exceto pelo fato de que se o cara teclar -1 você tem que sair do loop a menos que seja a última ação do loop e em seu caso não é. Note que eu te mostrei duas maneiras de resolver essa questão de menor e maior e você não quer aceitar nem uma nem outra. E optou por testar TODA vez durante o loop se é o primeiro numero ou não. Não é esperto testar a toda vez se é o primeiro. Depois do primeiro acontecer, e é o primeiro vai testar toda vez uma situação que nunca mais vai acontecer. Fosse você meu aluno e perderia pontos aí pela inércia em não criar uma solução melhor que testar PELO PRIMEIRO durante o programa todo... É muito mais simples e legível programar como está no código que te mostrei e que está do lado direito. Se você ler o primeiro item em separado resolve os dois problemas: o iníco da sequência de maior/menor e o teste do primeiro já ser (-1). E ler no final do loop resolve o outro problema, que seria pular código dentro do loop porque leu um -1 e vai terminar. Mesmo que use um break para sair do loop vai fazer um teste a mais que é supérfluo. if (primeironum == true){ maiornum = num; menornum = num; primeironum = false; } else { if(num>maiornum){ maiornum=num; } if(num<menornum){ menornum=num; } E porque está processando apenas os números positivos de novo? Tem um outro enunciado que não mostrou? Acha que -2 não é par? Não pode somar -8? Pode. E mantem o uso de getch() com um #include para uma biblioteca dos anos 80 para usar uma função só para parar o programa antes de terminar?
  24. @Enzo Mathias entendeu que não está funcionando? Veja os dois programas abaixo. O da esquerda, como você escreveu. O da direita uma versão comum e que funciona Veja que no caso a direita você lê um valor inicial, que pode ser -1 se o usuário resolver terminar logo antes só pra ver o que acontece. E prepara os valores de maior e menor... E se entrar no loop o programa roda apenas 4 instruções para os 4 resultados, e lê o próximo valor. É mais fácil de entender o que acontece. E o da esquerda ainda tem problemas, como eu disse
  25. Você tem seis valores e quer que os 6 estejam nesse intervalo e tem muitos modos de escrever isso. A primeira coisa que precisa considerar é testar depois de ter os 6 disponíveis. Muitas vezes o fato de um deles estar fora do intervalo já influencia na lógica do programa e não vale a pena esperar ter todos 6 para depois descobrir que o segundo não é válido. De todo modo talvez pude agrupar os tais na em um vetor, como int na[6]; e assim poderia testar usando um loop e um índice como em: int i = 0; int na[6] = { 1,2,3,4,500,6 }; for (i = 0; i < 6; i = i + 1) { if ((na[i] >= 1) && (na[i] <= 99)) continue; printf("indice %i fora dos limites: (%d)\n", i+1, na[i]); i = -1; break; }; if ( i != -1 ) printf("indices ok\n"); na[4] = 5; for (i = 0; i < 6; i = i + 1) { if ((na[i] >= 1) && (na[i] <= 99)) continue; printf("indice %i fora dos limites: (%d)\n", i + 1, na[i]); i = -1; break; }; if (i != -1) printf("indices ok\n"); que faz duas vezes a mesma coisa e mostra indice 5 fora dos limites: (500) indices ok Adapte algo assim para seu programa e vai ficar bem Atente para esse trecho que é o que quer fazer: int na[6] = { 1,2,3,4,500,6 }; for (i = 0; i < 6; i = i + 1) { if ((na[i] >= 1) && (na[i] <= 99)) continue; printf("indice %i fora dos limites: (%d)\n", i+1, na[i]); i = -1; break; };

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...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!