Ir ao conteúdo
  • Cadastre-se

arfneto

Membro Pleno
  • Posts

    6.232
  • Cadastrado em

  • Última visita

Tudo que arfneto postou

  1. Leia o programa e veja a parte onde faz o que você precisa. E rode em sua máquina. Pode te dar alguma ideia. É um programa divertido. Ele prepara as cartelas e coloca na tela e o painel faz os sorteios. Os números que saem nas cartelas vão ficando em verde e segue até alguém ganhar. Como são só 5 cartelas em geral só vai terminar perto de saírem todos os números mesmo
  2. ? Mas então você não fez nadinha certo? Qual a sua dúvida inicial? Leu o que o pessoal está sugerindo? Sabe o que é uma lista? tem noção de como alocar memória, liberar memória? criar uma struct? Você tem um livro-texto? Sua escola não adota um? A lista que postou struct aluno { int matricula; char nome[100]; float n1,n2,n3; }; struct lista { int qtde; struct aluno a[3]; }; Tem uma struct lista que sequer tem um ponteiro. e dentro dela 3 singelos alunos. Porque só 3? Como vai percorrer os alunos de uma lista que sequer tem um ponteiro? Vai usar o índice da struct? OK. Mas só tem 3... Veja uma declaração de lista de um programa comum: struct no { void* item; struct no* proxima; struct no* anterior; }; // no typedef struct no Node; struct a_propria_lista { char* nome; unsigned quantos; unsigned maximo; Node* inicio; Node* fim; }; typedef struct a_propria_lista Lista; E pense nisso... No segundo caso você pode de um item, um Aluno digamos, ir para o anterior ou o próximo... Na lista tem a quantidade, o limite e endereço de início e fim...
  3. Pergunte algo objetivo para que alguém possa te ajudar. Recomendo escrever primeiro a função que lista, depois a que cria e depois a que insere e partir daí. Poste o código.
  4. Meses atrás eu postei um programa que fazia exatamente isso, aqui nesse forum veja um pedaço da saída Esse programa cria 5 cartelas normais de bingo e simula uma rodada até alguém ganhar. Pode ser um exemplo útil. Lá no tópico tem um botão de download. O sorteio O clássico em C para isso é usar rand() que devolve um int e escrever rand() % 100 por exemplo para ter um número entre 0 e 99, e depois escrever rand() % 99 e ter um número entre 0 e 98 e ir diminuindo. No final vai escolher entre dois números apenas. E usar essa sequência para pegar os números e gerar as cartelas.
  5. No caso de inserir numa lista tem duas soluções seguras e comuns: Lista* inserir(void* elemento, Lista* a_lista_mesmo); void inserir(void* elemento, Lista** a_lista_mesmo); E tem uma outra decisão: você vai inserir um elemento que vai ser um nó na lista então sempre passa pela cabeça se o parâmetro vai ser um Node mesmo ou um elemento... Entenda que listas são absurdamente comuns e úteis em programas. Então você não quer programar isso toda hora. Por isso você escreve um troço caprichado e genérico e usa sempre o mesmo. Não vai querer mexer em um programa de lista ligada porque está usando uma lista de cadastro ao invés de uma lista de int. Na próxima semana vai ser uma struct de música, depois um livro... O que você faz é compilar isso uma vez só. Gera um arquivo .lib ou .dll e nos seus 325 programas que usam lista você só volta a mexer nisso se achar um erro. Nem vai querer ver o fonte mais. Assim é. Veja a estrutura abaixo e pense nas consequências: #pragma once #define _CRT_SECURE_NO_WARNINGS struct no { void* item; struct no* proxima; struct no* anterior; }; // no typedef struct no Node; struct a_propria_lista { char* nome; unsigned quantos; unsigned maximo; Node* inicio; Node* fim; }; typedef struct a_propria_lista Lista; Lista* apagar(Lista*); Lista* criar(const char*); int define_maximo(Lista* l, const unsigned); Lista* inserir_na_ordem(void*, Lista*, int(*)(void*, void*)); Lista* inserir_no_inicio(void*, Lista*); Lista* inserir_no_final(void*, Lista*); int listar(Lista*); int listar_do_seu_jeito(Lista*, int(*)(void*)); int maximo(Lista*); Node* primeiro(Lista*); Lista* remover(void*, Lista*); int tamanho(Lista*); Node* ultimo(Lista*); int vazia(Lista*); Você pode programar só o que usa, claro. Mas percebe que esses dados são genéricos? Cuidam de listas de qualquer coisa. E você pode ter várias listas no mesmo programa, cada uma com um conteúdo distinto. E elas tem até um nominho! Meigas. E preste especial atenção a essas duas rotinas: Lista* inserir_na_ordem(void*, Lista*, int(*)(void*, void*)); int listar_do_seu_jeito(Lista*, int(*)(void*)); Elas permitem que você por exemplo se tiver uma estrutura de livro insira na lista por ordem de autor, título, ISBN, data de publicação, qualquer coisa, sem mexer no código da lista. Ou liste os caras de uma maneira resumida, ou algo elaborado indo consultar seu estoque para ver quantos exemplares tem na loja, Sem mexer em uma linha sequer. Você escreve uma função que compara os caras no primeiro caso, uma que formata a listagem de um item no segundo, e a rotina faz o resto. Recomendo que se certifique de entender essa parada. É um conceito muito importante, como deve imaginar. Sobre decidir entre as duas opções: Em geral o ponteiro para a lista foi criado pela rotina que cria a lista, e está disponível em main(). Se você passar o ponteiro apenas para dentro de insere() por exemplo, e mudar o endereço de início, ele precisa voltar alterado para main(). Então ou você escreve Lista* lista = insere(Item* dado, Lista* lista); ou insere(Item* dado, Lista** lista); para ter o ponteiro lista atualizado na volta, ou ele vai sumir lá dentro de insere() Em geral é melhor usar a primeira opção porque assim você cria um hábito, é mais difícil de esquer um asterisco, e ainda pode usar o valor de retorno em expressões... adicionado 0 minutos depois Boa sorte. Veja o que expliquei sobre a passagem de parâmetros. É importante
  6. Não. "12" é o que? const char* então tem um zero no final...
  7. lista-> dado = rand() % 100; // eu estou dizendo lista.dado = rand() % 100; Esses operadores -> e . são similares. Apenas você usa -> quando o que está à esquerda é um endereço e usa . quando é algo estático. Considere essa declaração Lista a_propria; Lista* lista = &a_propria; você pode escrever a_propria.dado = rand() % 100; // ou lista->dado = rand()%100; // ou ainda (*lista).dado = rand() % 100; E no último caso precisa dos parenteses.
  8. Você tem razão. Mas entenda que o que você está declarando é uma variável e não um tipo. Tenho ensinado isso por muitos anos para incontáveis pessoas e esse seu argumento é claro sempre ouvido e muito, mas muito lido. Inclusive em livros de referência. Mas veja o caso de argv por exemplo: o fato de **argv ser um char é irrelevante. Raramente alguém vai se importar com isso. O que importa é (char*) (*argv) que indica claramente que *argv é um ponteiro para char (char*) argv[] que diz mais ou menos a mesma coisa (char**) argv que diz que argv é um ponteiro para um ponteiro de char e é isso que estamos declarando e é o que importa. (char) **argv diz que **argv é um char e não serve pra nada. Colocando os parenteses para reforçar a leitura. Veja isso no meio da linha então: char letra, outra_letra = 'a', um_byte, **argv = NULL; Onde fica claro que declaramos 4 char. Mas não é bem isso o que importa no caso de argv Dúvidas como a do autor sobre o limite dos ponteiros seriam muito menos frequentes ao declarar p. Isso porque afinal estamos declarando p e nada mais. o que é p? int***, declarando p: int*** p; e não um int int ***p; que faz o aluno entrar no papel do compilador e cria a noção de que ponteiros possam ter um limite, quando na verdade é a mesma coisa que usar uma função como argumento de outra, como em char* funcao = f(g(h(parm))); Aproveitei para escrever assim e tentar mostrar que fica muito claro que funcao() retorna um ponteiro para char e talvez mais claro que char *funcao = f(g(h(parm))); Mas é claro uma questão final de opinião ou estilo. E em geral a gente não pode escolher porque as empresas tem diretrizes de codificação e pronto ...
  9. Pois é. Como @Simon Viegas disse, está errado o que escreveu: "PRIMEIRO" é um literal, uma constante do tipo string, uma coisa do tipo char*, na verdade const char* e você não pode escrever algo assim. Precisa de uma função para isso, ou um loop e atribuir letra a letra. A função seria algo como strcpy() como @herbertbahia mostrou, e o loop pode ser qualquer um, tipo um for. Essa linguagem --- C --- foi escrita para resolver esse tipo de problemas. Os sistemas operacionais são cheios disso e essa linguagem foi escrita para escrever sistemas com ela. Antes de tudo olhe para seus dados. Alunos com código + RA par vão para o primeiro andar? Sério? Mas código é uma constante ímpar e vale 3531? E você vai somar isso toda vez ao invés de simplesmente inverter a condição? Pode ser uma pegadinha @herbertbahia @Leonardo Yuji para ver quantos alunos vão cegamente somar uma constante ímpar a um inteiro e depois testar se é ímpar Já teria pego 2. Ou pode ser uma ingenuidade do cara que escreveu, claro. Par + Impar é impar, ímpar + ímpar é par. Só isso. É a realidade. Inverta a condição e tire essa constante e variável daí... Pois é: são duas condições binárias: Sala A ou B, Andar 1 ou 2. E uma regra precisa. Só isso. Exemplo Então imagine um vetor sala const char* sala[4] = { "Andar 2 Sala A", "Andar 2 Sala B", "Andar 1 Sala A", "Andar 1 Sala B" }; E nossas condições dadas pelo número do celular par e o código par. Não faz diferença par/ímpar desde que monte a tabela direito. São só 4 valores. E esqueça a mágica constante 3551 Operadores lógicos Em C alguns dos operadores AND operador E é o '&'. Exemplo: c = a&b; avalia bit a bit as variáveis a e b e o resultado em c tem o óbvio: cada bit vale 1 quando o correspondente bit de a E b for 1. Ou zero se não for. Afinal é a noção de E OR operador OU é o '|'. Exemplo: c = a|b; avalia bit a bit as variáveis a e b e o resultado tem o óbvio: o bit vale 1 quando um dos correspondentes bit de a E b for 1. Ou zero se os dois forem zero operador SHIFT para a esquerda: << pega o valor e desloca para a direita o número certo de bits. Exemplo: c = a << 2; pega o valor de a e desloca 2 bits para a esquerda. Se a = 1, a<<2 = 4: char a = 1 << 2 por exemplo: 1 = 0000 0001 a constante 1 1<<2 = 0000 0100 a constante 1 deslocada 2 bits para a esquerda Sim, equivale a multiplicar por 4, já que é um nuúmero em binário e cadao zero a direita equivale a multiplicar por 2. Em decimal seria como transformar 1 em 100: multiplica por 10 a cada shift... 10*10 é 100, 2*2 é 4. Tem muitos outros operadores. Você tem um livro-texto, imagino? Um manual? Uma apostila? Uma cola com a tabela de operadores? Deveria. Veja uma em https://www.tutorialspoint.com/cprogramming/c_bitwise_operators.htm E porque essa conversa toda afinal? A expressão é o que você precisa, usando o enunciado e o vetor sala e os operadores acima. Só isso. Para um código de aluno e um número de celular ela te dá o índice certo de sala[] para onde vai o aluno... Essa expressão: sala[((codigo & 1) << 1) | (celular & 1)] Esse printf() printf("%s\n", sala[((codigo & 1) << 1) | (celular & 1)]); Nesse programa #define _CRT_SECURE_NO_WARNINGS #include <locale.h> #include <stdio.h> main() { const char* sala[4] = { "Andar 2 Sala A", "Andar 2 Sala B", "Andar 1 Sala A", "Andar 1 Sala B" }; int celular, codigo; setlocale(LC_ALL, "Portuguese"); printf("Digite o seu código: "); scanf("%i", &codigo); printf("Digite o número do seu celular: "); scanf("%i", &celular); printf("%s\n", sala[((codigo & 1) << 1) | (celular & 1)]); } Faz o serviço todo em 8 linhas. Uma linha na verdade, depois de leu os valores.. Como eu disse, essa linguagem foi escrita para resolver esse tipo de problema Rodando o programa Claro, só tem 4 possibilidades.
  10. O limite é 1 mesmo. Um ponteiro tem o endereço de algo.Uma variável comum é algo. struct dados a; indica que no endereço alocado para a está uma estrutura do tipo dados. Por outro lado, struct dados* a; indica que no endereço alocado para a está um endereço, e nesse endereço está uma estrutura do tipo dados. Acho que boa parte da dificuldade em entender isso vem do fato de autores escreverem e ensinarem a declarar como você fez no seu exemplo int ****p; e não int**** p; que é o que acontece na verdade. Se está declarando p. Quando usar mais de um * O que determina isso é a lógica do programa. Se a lógica justifica usar um ponteiro para um ponteiro para um ponteiro para algo então você declara algo*** variavel; O exemplo mais óbvio é int main(int argc, char** argv) claro argv. Se os autores fizessem a gentileza de escrever char** argv talvez ficasse mais claro que argv é um ponteiro para char*, que por sua vez é um ponteiro para char. Ao escrever char **argv indicam que **argv é um char e isso não é importante. Só confunde o aluno e o leitor, porque o que a declaração deveria qualificar era argv e não **argv. Declarar char* argv[] é um meio termo, talvez. De todo modo é só minha opinião. Ainda sobre argv Entendendo isso vai entender porque usaria qualquer número de *, ou de outro modo qualquer número de redirecionamentos, de "apontamentos".... argv é um vetor de strings. argv[0] é o nome de seu programa, sempre. argv[1] é o primeiro argumento, argv[2] o segundo e tal. Quantos desses tem? argc deles. E essa é a razão de main declarar 2 parâmetros: int main( int argc, char** argv) O sistema prepara essas strings quando o programa é disparado. Então tem o caso mais comum do universo de declarar tipo** variavel Não tinha como declarar isso antes no programa porque ainda não existia programa ainda quando isso foi criado. O sistema pega uma área de memória e coloca esses valores um depois do outro. Todos são strings, do tipo char*. Mais ainda, do tipo const char* porque não dá para voltar no tempo e mudar o que foi digitado. Como não se sabe o tamanho, o mais simples é alocar um ponteiro para cada valor e colocar um depois do outro e passar para o programa em main(). Nenhum argumento? um único ponteiro com o nome do programa. 2 argumentos? 3 ponteiros. Nesse exemplo então o sistema faz o simples: pega uma área suficiente para 3 ponteiros e aloca 3 áreas char* para abrigar o nome do programa e os dois parâmetros seguintes. E coloca esses 3 ponteiros na área alocada. Como declarar essa área? char* * certo? Isso é argv. Veja a saída desse programa rodando 3 vezes com argumentos diferentes C:\Users\toninho\source\repos\chc-argv\Debug>chc-argv argc = 1 arg 0: [chc-argv] tamanho '8' argc = 1 arg 0: [chc-argv] tamanho '8' C:\Users\toninho\source\repos\chc-argv\Debug>chc-argv um dois argc = 3 arg 0: [chc-argv] tamanho '8' arg 1: [um] tamanho '2' arg 2: [dois] tamanho '4' argc = 3 arg 0: [chc-argv] tamanho '8' arg 1: [um] tamanho '2' arg 2: [dois] tamanho '4' C:\Users\toninho\source\repos\chc-argv\Debug>chc-argv "um dois tres 4" argc = 2 arg 0: [chc-argv] tamanho '8' arg 1: [um dois tres 4] tamanho '14' argc = 2 arg 0: [chc-argv] tamanho '8' arg 1: [um dois tres 4] tamanho '14' E o tal programa #define _CRT_SECURE_NO_WARNINGS #include "stdio.h" #include "string.h" int main(int argc, char** argv) { printf("argc = %d\n", argc); for (int i = 0; i < argc; i = i + 1) printf("arg %d: [%s] tamanho '%d'\n", i, argv[i], strlen(argv[i])); // ou sem os [ e ] printf("\nargc = %d\n", argc); for (int i = 0; i < argc; i = i + 1) printf("arg %d: [%s] tamanho '%d'\n", i, *(argv+i), strlen(*(argv+i))); return 0; } O programa só lista os parâmetros. Duas vezes porque eu queria mostrar que os colchetes não são necessários. O fato de poder declarar coisas como int*** coisa e C ter aritmética de ponteiros, somando o valor do tamanho do item, explicam porque C foi escrita para escrever sistemas. É muito fácil e rápido "falar" com endereços de memória e chips e buffers e tal. E os parâmetros são no fundo char: são só letras. Mas cada parâmetro é do tipo char* porque é uma sequência de char com um 0 no fim. E o número de parâmetros é variável. E os parâmetros tem tamanhos variáveis e então empilhar os ponteiros para strings onde estão os caras é perfeito. E isso quer dizer que argv é um ponteiro para um ponteiro de char. Então *argv é o primeiro. Mas *(argv+1) é o segundo e C sabe que +1 aqui não é +1 apenas e sim uma vez mais o tamanho de char*, e a fila anda. No caso a fila de ponteiros. Veja o programa. Espero que ajude a entender. Um outro exemplo claro é por exemplo uma lista ou uma árvore e a maneira de atualizar o ponteiro para uma estrutura dessas: void insere(Dado* dado, Lista** lista); // ou Lista* insere(Dado* dado, Lista* lista); // mas void insere(Dado* dado, Lista* lista); // nao funciona Ou você retorna o novo endereço ou passa o ponteiro do ponteiro ...
  11. Isso é redundante, como seria escrever scanf("%f", &*&*&*&*&*&*salario); & e * são operadores inversos então usar os dois assim é a mesma coisa que escrever x = x + 1 - 1 + 1 - 1; Não vai fazer nada. Ou melhor, vai fazer e desfazer e fazer e desfazer... realloc() faz o simples: pega um bloco de memória que você alocou antes e reajusta o tamanho, para mais ou para menos, e devolve o endereço no novo bloco. Se for menor é garantido que será o mesmo, se for maior não há garantias: Se você tinha 30000 alocados em x e realoca para 10000 os 10000 vão ficar em x e o resto vai ser liberado Se você tinha 10000 em x e realocou para 30000 é garantido que os 10000 vão ser copiados igualzinho, mas não há garantia que o endereço de x não vá mudar. Esse enunciado é uma bobagem. Não faz sentido usar malloc() ou realloc() para isso. Mas se é para fazer simplesmente aloque os salários a partir de 1: 1, 2, 3...
  12. Pode. Mas não foi isso o que fez no exemplo. Se são comandos pode usar ';' ou ',' em muitos casos. Se se refere a chamar uma função dentro de outra também pode. Mas o valor da função vai ser substituído pelo valor de retorno dela. printf() retorna um int, o total de caracteres que ela gerou. É isso que vai ser usado nesse código: int x = printf("12") + 2; printf("x = %d\n", x); vai mostrar 12 x = 5 e é provavelmente inútil...
  13. @herbertbahia @Rodrigo Diamond Não sei se entendi a ideia de ver qual a maior. Usando o mesmo índice para as duas strings, a menos que elas tenham o mesmo tamanho, o programa vai cancelar assim que tentar acessar um índice que não tenha nas duas. Ou deveria pelo menos... Sugiro sempre mostrar os valores lidos quando se está aprendendo ou testando. No mínimo para não ter que ficar pensando se leu o que acha que leu... E ler de verdade já é irrelevante no início. Sugiro usar coisas como strcpy(x, "uma string"); strcpy(y, "uma outra string"); E testar a lógica. Ler uma string não acrescenta nada. Ler duas também não. //ver qual a maior if(strlen(x)>strlen(y)){ maior = strlen(x); } else{ maior = strlen(y); } //faz um laço no limite do tamanho da maior printf ("as letras da string x que nao estão na string y: %c\n"); for (i=0;i<maior;i++){ if (x[i]!=y[i]) printf ("%c",x[i]); } adicionado 14 minutos depois Em resumo: if (x[i]!=y[i]) vai cancelar o programa a menos que as strings sejam iguais e então não adiantou muito ver a diferença. E o penultimo printf() tem um especificador %c mas não tem parâmetros para tanto Sugiro não usar nunca caracteres acentuados nos programas a menos que seja obrigado...
  14. imagino que acertou o idioma lá do lado direito e entrou com sua conta. Ou não?
  15. Nas janelas de prompt de comando tecle Alt-Espaço e P para acessar as propriedades e vai ter as 4 escolhas que vê abaixo... Apenas altere como preferir a fonte, o Layout e as cores e tal... No windows 10 use o Terminal como sugerido nessa mesma tela. É melhor e muito mais rápido... São "os novos recursos da console" como aparece na tela desde 2017, de modo que não assim tão novos mais
  16. struct lista { int qtde; struct aluno lAlunos[TAMANHOLISTA]; }; Sua estrutura de lista tem um problema, digamos, estrutural... Sua lista termina em si mesma já que não há um ponteiro para o próximo elemento, ou para o anterior, ou para qualquer coisa. Só um int, qtde e uma outra estrutura... Pense nisso: Se isso fosse um elemento de usa lista a quantidade não seria sempre um? Se tem 20 na lista ao mudar a quantidade iria alterar todos? Como iria encontrá-los? Como percorrer uma lista assim? Compare com o exemplo abaixo, de uma implementação comum: struct no { void* item; struct no* proxima; struct no* anterior; }; // no typedef struct no Node; struct a_propria_lista { char* nome; unsigned quantos; unsigned maximo; Node* inicio; Node* fim; }; typedef struct a_propria_lista Lista; Tem dois elementos aqui: Node e Lista. A lista dá pra imaginar é uma lista de Node A lista tem um nome uma quantidade um limite um ponteiro para o inicio um ponteiro para o fim O tal Node, o nó tem um ponteiro para algum conteúdo tem um ponteiro para o próximo nó tem um ponteiro para o nó anterior E a conta fecha: Se você não precisa apontar para o anterior, não usa Se você não precisa apontar para o próximo não usa Se não precisa dar um nome, por exemplo porque só vai ter uma lista no seu programa, não usa o nome Se não tem um limite não precisa do tal maximo item é um ponteiro e você pode apontar cada um para um Aluno, no seu caso Pense nisso.
  17. Ontem eu postei um programa. uma série que eu ia alterando e mostrando o conteúdo depois de algumas leituras. É a mesma situação desse programa aí. Veja em e pode ser interessante. De volta ao programa int main() { double h; char sexo; printf("Digite a sua altura:\n"); scanf("%d", &h); printf("Digite o seu sexo M ou F:\n"); scanf("%c", &sexo); return 0; } Veja que a leitura seguida de valores do mesmo arquivo --- fluxo, stream como queira --- vai ser satisfeita por coisas que já estejam lá ou que serão obtidas a partir da chamada. Em C tudo é um arquivo. stdin é o teclado, o arquivo 0. E scanf() lê de lá. Se o cara digitar "1.87coisas asasasaas" tudo isso ficará disponível para alimentar as leituras. É o arquivo 0, a entrada padrão do programa. E a gente não sabe o que o cara vai digitar. scanf() não é pra isso. scanf() é para ler entrada formatada. E ao ver tudo isso vai alimentar todas as leituras até gastar essas letras todas. Note que se quer ler um float ou double deve usar um especificador de acordo, como "%f" e não %d Veja esses resultados Digite a sua altura: 1.54 teste teset tefsdkfkdshfksdhfkdshfkshfdksf Altura: 1.54 Digite o seu sexo M ou F: Tentando ler o sexo nao leu NADA! C:\Users\toninho\source\repos\chc-200425-tscanf\Debug>t Digite a sua altura: 1.87 Altura: 1.87 Digite o seu sexo M ou F: F Sexo = 'F' C:\Users\toninho\source\repos\chc-200425-tscanf\Debug>t Digite a sua altura: 1.87 Altura: 1.87 Digite o seu sexo M ou F: fDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD Sexo = 'f' Desse programa #define _CRT_SECURE_NO_WARNINGS #include "stdio.h" #include "stdlib.h" int main() { int _ch = 0; int _n = 0; char _linha[80]; float h; char sexo = 16; printf("\nDigite a sua altura: "); _n = scanf("%f", &h); if (_n == 0) { printf("Nao leu NADA!\n"); return -1; }; printf("Altura: %4.2f\n", h); do { _ch = getc(stdin); } while ((_ch != '\n') && (_ch != EOF)); printf("Digite o seu sexo M ou F: "); _n = scanf("%1[mfMF]", &_linha[0]); if (_n == 0) { printf("Tentando ler o sexo nao leu NADA!\n"); return -1; }; printf("Sexo = '%c'\n", _linha[0]); return 0; } Que faz um pouco mais de esforço para ler e não cancelar. Primeiro, se scanf() não ler nada. por exemplo dse o cara digitou uma letra ou 500 letras, o programa retorna. Já é algo. E se veio mesmo um número é preciso descartar o que veio depois... Para não zoar a próxima leitura E a próxima leitura vai aceitar só mfMF para o sexo, mas não vai cancelar se não vier nada Agora veja esse caso O cara digitou ',' ao invés de ponto numa máquina em que o ponto decimal é mesmo o ponto. scanf() descartou tudo que veio depois da vírgula porque ela terminou o número. Não cancelou, mas não foi assim um sucesso. E na hora de digitar o sexo o cara teclou um número. Mas a máscara de scanf() é "%1[mfMF]" que só aceita mfMF mas um número é visto como um dígito e ela não le nada. Veja o primeiro exemplo de que eu falei e esses casos desse programa e veja se ajudou a entender. E veja que ler números decimais é algo enjoado: você precisa consultar o sistema para ver se o ponto decimal é o ponto ou a vírgula e avisar o usuário e depois testar o que veio. E use o retorno de scanf()... SEMPRE. Acho que o próprio Ken Thompson escreveu scanf().Ele deve ter razão. Mais que nós. Ela retorna int por alguma boa razão. E é essa que está aqui. Controle. adicionado 15 minutos depois Tudo que tem na máscara é significativo. O espaço vai fazer com que qualquer número de espaços na entrada seja descartado. Espaço para scanf() pode ser também um TAB ou um newline '\n' então esse comando pode "comer" um número arbitrário de linhas na entrada. Pode ser o que você quer. Ou não.
  18. O oficial do padrão do C é que é indefinido. Se você pode garantir que vai usar sempre um compilador que faz isso, flush num buffer de entrada, ok. Use. Mas é tão simples usar uma rotina como a que eu mostrei com 5 linhas (ou um loop de uma linha) que não sei qual seria a vantagem. Não recomendo a ninguém de fato escrever programas de console. Mas se quer ou precisa fazer isso com sossego eis o que eu faria: ler tudo como caracter usando fgets() e tratar no programa. E mesmo assim não é sossego.
  19. Elas são perfeitas, ou quase isso. Acontece que você não está usando de acordo. Como eu disse, scanf() por exemplo sequer foi escrita para isso e você estava lendo do jeito errado. Você leu os exemplos que eu mostrei? lá tem até o código do programa que dá erro e depois dá certo e a discussão passp a passo. Se você não entendeu poste a linha do que você não entendeu, algo objetivo. Assim será mais produtivo para você. O livro clássico de C é sempre o "livro branco" de Kernighan e Ritchie. https://www.amazon.com.br/Programming-Language-Brian-W-Kernighan/dp/0131103628 Online eu acho que o material em https://www.tutorialspoint.com/c_standard_library/c_function_scanf.htmé muito bom. Tem um erro aqui ou ali, mas cobre tudo e com exemplos... Sua escola não assina uma biblioteca online? É muito comum hoje em dia. Pergunte algo objetivo. Algo assim nebuloso. Vamos ver se dá pra ajudar. Entendeu o que eu expliquei sobre flush()? Todas as linhas?
  20. Ficou tudo muito muito confuso e engraçado. Muito bom esse tópico. Vendo a coisa meio de ponta-cabeça: Como forçar uma codificação Isso é um pesadelo dos anos 80. O pesadelo do século 21 é Unicode. ASCII é uma tabela de 128 bits, de 1963. Quando era moderna o antigo era EBCDIC da IBM. Unicode é uma tabela que hoje tem mais de 1.1 milhão de caracteres. Curiosamente foi projetada em boa parte dor Ken Thompson e Rob Pike, caras que escreveram coisas simples como o Unix (KT) e linguagem Go (Pike) e boa parte da stdlib (KT) Eis o que acontece: como a tabela ASCII só usava 7 bits a IBM criou --- acho que ainda na época acoplada à Microsoft com o desenvolvimento do DOS --- uma tabela que chamou de Extended ASCII e que usava os caracteres entre 128 e 255 para novos símbolos. Alguns eram muito legais para desenhar na tela, coisas como caracteres com barras duplas e simples para desenhar caixas em torno do texto, e caracteres para preencher blocos inteiros de letra, que permitiam gerar um tipo de gráfico na tela, que só tinha letras e em geral 24 linhas por 80 colunas de letras. Veja um pedaço da tabela: E veja que tem os caras com barras simples, duplas e as intersecções então dava para criar formulários com dois tipos de borda. Era muito legal. E aí vieram alguns caracteres acentuados também. E logo veio a noção de poder alternar entre opções para esses caracteres e incluir caracteres de outros idiomas e tal. Nasceu a noção de code page. E vieram dezenas delas. Como controlar essa coisa O ideal é você chamar chcp() em seu programa logo no início e ver se a página de código que está configurada no momento tem o caracter que você quer mostrar, como esse 166 do exemplo. Se não tem você muda e depois restaura ao encerrar o programa. O politicamente correto é na carga do programa ver as definições de cor de fundo cor do texto, página de código, fonte da console e coisas assim, e salvar. Aí você altera para o que precisa e no final restaura tudo para como estava antes. Eis um exemplo para Windows, que eu escrevi sem grandes cuidados: char* guarda() { char* pLocale = &local_original[0]; ccp_original = GetConsoleCP(); occp_original = GetConsoleOutputCP(); pLocale = setlocale(LC_ALL, NULL); // mas afinal qual a fonte da console? HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_FONT_INFO info; CONSOLE_FONT_INFOEX infoEx; char buffer[80]; char* pBuffer = buffer; int res = 0; printf("Chamando GetCurrentConsoleFont()\n"); res = GetCurrentConsoleFont(h, 0, &info); if (res != 0) { printf("Posicao da fonte na tabela: %d\n", info.nFont); printf("Largura e altura de cada letra: %dx%d\n", info.dwFontSize.X, info.dwFontSize.Y ); } else { printf("GetCurrentConsoleFont res = %d\n", res); }; // if() // pois e: mas qual a fonte? Tem que ver na tabela // precisa da versao ex da rotina e eu nao sabia printf("Chamando a tal GetCurrentConsoleFontEx()\n"); infoEx.cbSize = sizeof(CONSOLE_FONT_INFOEX); res = GetCurrentConsoleFontEx(h, 0, &infoEx); if (res != 0) { printf("Familia da fonte (FontFamily): %d\n", infoEx.FontFamily); printf("Tamanho da fonte (FontWeight): %d\n", infoEx.FontWeight); int n = wcstombs(pBuffer, infoEx.FaceName, 80); printf("A fonte afinal: %s\n\n", buffer); } else { printf("GetCurrentConsoleFontEx res = %d\n", res); }; // if() // // A fonte em uso fica aqui no registro // Computador\HKEY_LOCAL_MACHINE\SOFTWARE\ // Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont // return pLocale; }; // guarda() O modo ignorante de fazer é simplesmente chamar chcp() e forçar a codepage que você quer e pronto. Não faria isso para rodar no computador do seu chefe, claro... E isso é claro um inferno. E tem a transição para o novo inferno, que é a codepage 65001 que usa UTF-8, um pedaço de Unicode, e se prepare para ler e estudar e se frustrar. Não funciona e nunca vai funcionar direito. Não é o caso de correção. Não tem a ver com bibliotecas. Apenas com garantir que a página de código em uso tenha o tal caracter que você quer na posição 166. Os compiladores online podem não se importar com codepages latinas ou mesmo ocidentais... Esqueça essa conio. Como eu já disse muitas vezes aqui essa infeliz é uma herança do Turbo C da Borland, hoje Embarcadero, dos anos 80. Vinha em dois diskettes. O compilador todo: 1,44MB * 2. Até onde eu sei não há nada lá relevante em 2020. Ou em 2000 na verdade. Então, o exemplo que eu mostrei tem a fórmula. Basta aplicar em um loop tipo for. Veja a matriz que eu postei lá e entenda que os valores são lidos por linha, da esquerda para a direita. Só isso. Eu postei um programa aqui um dia desses que fazia exatamente isso, mas em várias dimensões. Um pouco off-topic mas é um exemplo difícil de achar e por isso escrevi um. Pode ajudar a entender a mecânica disso e como declara esse tipo de coisa. Vi agora que era um programa em C++ mas podia ser em C igualzinho eu creio. Ele mostra como acessar um vetor de 60 bytes em 1,2,3,4 ou 5 dimensões. Eu não me expliquei bem. Eu só escrevi nesse tópico para dizer que não há "matrizes" nessas linguagens. Apenas vetores. E mostrar a fórmula que monta os valores para 2 dimensões. E um programa de exemplo. E nem tinha lido o enunciado original. E digitei errado a fórmula . Já corrigi. Note que é a mesma para qualquer número de dimensões. Para ler os dados para a matriz como o autor do tópico precisa basta aplicar a fórmula ou simplesmente entender que precisa ler os dados da maneira como vai colocar na matriz. Só isso. O mais simples claro que é entrar com os dados por linha. Como eliminar um coluna ou uma linha numa matriz? De fato não há um comando, mas há uma simples fórmula então se você precisa seguidamente fazer isso para uma matriz basta criar um filtro usando como entrada os índices originais e como saída o desejado. Uma função simples na verdade. Mais simples de escrever do que de explicar. Algo assim: int* extrair( int* origem, int parametros); // algo assim Se fosse para extrair uma linha ou a diagonal ou coluna ou sei lá. Recebe o endereço da matriz e retorna o valor desejado. Só isso. Se você quer extrair uma "linha" é trivial porque ela está seguidinha na memória. Se você quer uma coluna a distância entre cada elemento é... o número de colunas, lógico. Numa matriz (3x5) as colunas tem 3 elementos e a diferença entre o endereço de cada uma é... 5. E C tem aritmética de ponteiros então é só somar... Se for importante me mostre uma especificação e eu escrevo um exemplo...
  21. leu o exemplo que eu mostrei? Não entendi o que quer dizer... ASCII é uma abreviatura da tabela que associa as letras aos valores. Pode ver uma tabela dessas em a tal tabela ASCII American Standard Code for Information Interchange é o que significa Eis um pedaço dela mostrando as letras apenas
  22. Essa noção de matriz vem da matemática. No escritório é uma tabela mesmo Mas no computador em C é apenas um vetor sempre, mesmo que tenha doze dimensões. E a fórmula é sempre essa aí, porque a alocação é feita sempre por linha, a partir do endereço inicial. Explicando um pouco melhor, a partir do mesmo programa aqui acima m(x,y) = * ( p + y*C + x) Onde p é o endereço de início da matriz, x a linha y a coluna a partir de 0,0 e C é o número de colunas m22 = *(&m[0][0] + 2 * 5 + 2); &m[0][0] é o endereço de início, o tal p. E x = 2 e y = 2 e C = 5 Eu não prestei atenção ao que escrevi. Desculpem. O programa está certo no entanto.
  23. @devair1010 mais ou menos isso. Uma matriz é formada por um endereço de início e uma série de bytes na memória. Apenas uma longa fila, e o tamanho vai ser a multiplicação das dimensões da dita matriz pelo tamanho de cada valor. Só isso. Não existe a noção de linhas ou colunas nesse momento. Exemplo: int m[3][5]; são 3 * 5 * sizeof(int) Outros casos char outra[5][6][2]; struct coisa[20][1]; outra tem 5*6*2 char, ou seja 60 bytes coisa tem 20 * sizeof(struct coisa) e o espaço é alocado por linha então para encontrar o valor de m[x][y] considerando os índices a partir (0,0) se p for o endereço de m[0][0], o início da estrutura, você pode escrever m(x,y) = * ( p + y*C + x) onde C é o número de colunas da matriz Exemplo: considere a "matriz" do exemplo 1: int m[3][5] e o programa abaixo e ele mostra sizeof(m) = 60 valor de m[2][2] = 12 (deve ser 12) valor de m[2][2] = 12 (deve ser 12) porque esse compilador usa int com 4 bytes e são 3*5 = 15 deles e então 60 bytes. O primeiro é m[0][0] e o último m[2][4]. Se você numerar um por um o valor de m[2][2] deve ser 12, como mostra o programa #include <stdio.h> int main(int argc, char** argv) { int m22 = 0; int m[3][5] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; printf("sizeof(m) = %d\n", sizeof(m)); printf("valor de m[2][2] = %d (deve ser 12)\n", m[2][2]); m22 = *(&m[0][0] + 2 * 5 + 2); printf("valor de m[2][2] = %d (deve ser 12)\n", m22); return 0; }
  24. void flush(FILE* f) { int ch = 0; do { ch = getc(f); } while ((ch != '\n') && (ch != EOF)); }; // flush() Você leu mesmo o que eu escrevi? Viu o programa exemplo de ontem com scanf() getchar() fgets() e o resto que expliquei? Sobre a versão de flush() Basta você acreditar que flush() funciona e colocar esse código no seu programa, antes de main(). É só uma função... Troque o fflush(stdin) por flush(stdin) e pronto. A função tem apenas 5 linhas. Se achou complexa podia ter perguntado algo objeitivo eu acho. Essa "função" apenas chama getc() para ler uma letra, em loop while, até ler o newline ou o fim de arquivo. O que achou complexo? podia ter explicado sua dúvida... Comentando 3 das 5 linhas: void flush(FILE* f) { int ch = 0; // a letra do { ch = getc(f); // le a letra } while ((ch != '\n') && (ch != EOF)); // ate o fim da linha }; // flush() E é só isso: ler até o fim da linha conio é uma biblioteca dos anos 80 derivada do compilador de uma empresa chamada Borland daquela época, e que vinha em dois disquetes. Eu comprei. Não entendo o que tem lá que pode mesmo ser útil em 2020. Por certo não seria getch(). Ou perdi algo? Você leu o programa que mostrei ontem? Entendeu as notas que te escrevi hoje? scanf() retorna um parâmetro. USE. scanf() consome a entrada só até satisfazer o que tentou ler. E as vezes é mais ou menos do que você imaginava. Essa rotina não foi escrita para isso. Mas serve. Se quer ler uma letra para o voto leia com getc() que retorna exatamente a letra e depois use flush() para descartar o resto da linha. Se o cara teclar em seu programa algo como "coisa" e ENTER por exemplo vai pular a mensagem de escolha inválida... Faça o simples, minha sugestão. E leia aquilo que falei sobre scanf() é só uma folha. E me diga o que não entendeu na função de 5 linhas que te mostrei para que eu possa tentar te explicar. Sua dúvida pode ser a de outros. adicionado 2 minutos depois importar o código executável de uma biblioteca você precisa conseguir de algum lugar a versão já compilada para sua plataforma, algo como um arquivo .DLL ou .OBJ ou .lib pro seu sistema. ou conseguir o código fonte, o programa na linguagem em que foi escrito e compilar em seu sistema. E salvar o arquivo .lib ou DLL gerado porque você não vai ficar compilando isso para o resto da vida certo? O que precisa de conio, dos anos 80, em 2020? adicionado 42 minutos depois fflush(stdin) e um pouco de história Acho que eu ou alguém devia escrever isso afinal parece que não faz parte das aulas ou nos livros mais... Desde os programas em linguagem FORTRAN do final dos '50 os programas acessavam arquivos por números. Sim, existiam programas em 1958 por exemplo! E alguns desses números eram pré-definidos e apontavam para certas coisas. No final dos 70 a linguagem C fazia a mesma coisa. E ainda faz. Um programa em C tem acesso SEMPRE a 3 arquivos --- streams ou fluxos é o nome hoje em dia --- e eles tem um número cada um. No Unix, no Windows, todo lugar. E um nome. Os arquivos são 0, 1 e 2 e os nomes são stdin, stdout e stderr. Então quando você fala em limpar o buffer de entrada está falando de stdin, de 0. getc(stdin) é a mesma coisa que getc(0) flush() foi criado para limpar o buffer de um arquivo desse tipo, mas um arquivo de saída. Porque isso? Há muitas razões. Vou deixar 2 exemplos: se você tem um programa rodando funções em paralelo escrevendo coisas num mesmo lugar, como vários printf(), você pode precisar de fflush(stdout) para garantir que imprima o que você quer de imediato para diminuir a chance de misturar com a saída de outra função. Se você tem um periférico tipo um painel LCD e tem uma lógica que escreve nele, pode usar fflush() para forçar a descarregar o buffer e mostrar o que já está lá para ser impresso. O que acontece é que os sistemas usam áreas intermediárias de armazenamento --- os tais buffers -- e tem uma lógica deles para descarregar os dados. Isso por questão de pura eficiência. É a mesma coisa na entrada: o sistema imagina que alguém vai ler tudo que está lá no buffer de teclado. Isso inclui espaço, ENTER e o que tiver. E como tem rotinas lendo elas podem pegar o troco do que sobrou de outras e não foi consumido ainda, como o ENTER de uma leitura de teclado, que em C é um arquivo como outro qualquer. Sobre fflush(stdin) veja uma discussão em https://www.geeksforgeeks.org/use-fflushstdin-c/ onde alguém até cita o parágrafo do padrão onde diz que fflush() para entrada tem comportamento indefinido E uns exemplos em C e C++ em https://www.geeksforgeeks.org/clearing-the-input-buffer-in-cc/

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

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!