-
Posts
6.526 -
Cadastrado em
-
Última visita
Tipo de conteúdo
Artigos
Selos
Livros
Cursos
Análises
Fórum
Tudo que arfneto postou
-
LITTLE MAN TATE,1991,JODIE FOSTER STUCK,2007,STUART GORDON DANGEROUS GROUND,1997,DARRELL ROODT ENIGMA,2001,MICHAEL APTED FLASH GORDON,1980,MIKE HODGES Você entendeu o que expliquei? Pra escrever em torno dos dados? Você pode começar por esses aqui em cima e colocar em filmes.txt, na própria linha de comando e ver o que esperar O próprio Windows tem sort. E o Linux e o MacOS que é linux também... Então no Windows pode rodar Como usar os dados na memória? Como eu disse, cabem mais de 13000 linhas por megabyte na memória para um vetor assim char filmes[17475][60]; // por exemplo, para perto de 1MB mas não é algo assim elegante. Como o sistema faz isso? Cada programa em C roda com uma estrutura dessas, que é a linha de comando: um vetor de strings que são os parâmetros do programa, certo? E como é declarado isso? Não é segredo algum, em java, em C, em C++,e em muitas linguagens: int main( int argc, char**argv); // o popular: 100% dos programas recebem isso E claro que essa é a maneira elegante e econômica de alocar os filmes int total_de_filmes; char** filmes; E montar isso a partir do arquivo de entrada. Absurdamente mais econômico, porque cada linha vai ter o tamanho certo, ao invés de 60 ou 80 ou 200 letras por linha. A função que postei ontem int insere_na_ordem(int N, int V[], int T) { // insere N em V[], V com T elementos int pos = 0; for (pos = T; pos > 0; pos = pos - 1) { if (V[pos - 1] > N) V[pos] = V[pos - 1]; else break; }; // for() V[pos] = N; // pos = posicao certa return T + 1; }; Essa função é uma implementação trivial e relativamente didática de um método de classificação, o tal insertion sort, o mais simples de todos. Funciona muito bem no caso em que a entrada é assim, item a item. Simplesmente insere N no Vetor V com T elementos, e devolve T corrigido. É trivial alterar para usar strings ou ponteiros para strings. adicionado 0 minutos depois Apenas clica no nome do usuário e vai abrir o perfil do cara. Aí tem um botão marcado explorar conteúdo. Poderia tentar.
-
A julgar pelo trecho era um arquivo csv Não faz diferença se tem uma ou 3000 linhas, a grosso modo. Imaginando um máximo de umas 80 letras por linha, vai ter umas 13.000 linhas por megabyte de memória. E é pouco. E é aí que pega, porque você vai querer classificar tudo na memória e gravar depois no outro arquivo. Se não puder manter tudo na memória vai ter que pensar bastante ou vai ficar muito lento. Sua ideia de gravar em outro arquivo e renomear é o que se faz sempre. Talvez apenas ao invés de excluir o original apenas mude para algo como filmes.back. E use opções na linha de comando, super aprovadas desde os anos 70. Se seu programa se chama xx.exe, xx filmes.txt pega bem e quem vai usar o programa tem menos trabalho, certo? Alias lembro que na linha de comando pode digitar sort filmes.txt temp.txt ren filmes.txt filmes.back ren temp.txt filmes.txt na linha de comando e seria o seu programa em Windows. No Linux é um pouco deferente. Sobre o programa int strcmp(const char *str1, const char *str2) Essa é a função que compara duas strings, devolve -1, 0 ou 1 conforme a comparação char *fgets(char *str, int n, FILE *stream) Essa é a função que lê ima linha do arquivo de entrada void qsort( void *inicio, size_t total, size_t tamanho, int (*compar)(const void *, const void*)) E essa é a função que classifica os caras. Se puder usar. Se não puder acho que aqui por exemplo eu mesmo já postei algumas opções. E outros. Antes de tudo faça seu programa em torno dos dados. SEMPRE. Aqui eles são muito simples, já que vai usar a linha toda como unidade. Deve decidir como vai tratar isso char linha[1300][80]; // 1 megabyte de linhas um vetor de linhas assim pode ser preguiçoso mas se ninguém reclamar... adicionado 3 minutos depois em uma saída de um programa de classificação nunca imaginaria usar append mode. Apenas "w" está bem. Pode ir alocando linha a linha e apenas o tamanho que leu em cada uma, mas é uma opção. Ontem eu postei uma função que faz isso, aqui neste forum. De uma olhada. ão sei o que era agora mas está na lista. Ou depois eu vejo. Agora não dá
-
Não entendo o que tem a ver a ponto de aceitar ou não uma solução. Não sei o que tentam ensinar com essa ideia. Foi ele que escreveu aquele código do outro exercício? A questão de usar Lista** ou Lista**** ou Lista* é ou deveria ser irrelevante. O que importa na lista --- e em todas essa estruturas --- é o grau de abstração. Para um estudante, claro. Aqui está sua versão de insere() TLDE *insere(TLDE** l, int elem) { TLDE* temp = novaLista(elem); temp->prox = *l; (*l)->ant = temp; (*l) = temp; } Aqui está a que havia postado antes void insere(TFila* f, int elem) { TLista* novo = (TLista*)malloc(sizeof(TLista)); novo->info = elem; novo->prox = NULL; if (f->fim) { f->fim->prox = novo; } f->fim = novo; if (!f->ini) { f->ini = novo; } } Não escreva uma única linha de código sem razão, sem saber porque está lá. E escreva sempre seus programas em torno dos dados, não da interface, de menus, que funções... Qual a diferença entre as duas? Como chegou a essa? Vou você que escreveu a outra? Entendeu a estrutura que te mostrei? Podia comentar algo talvez? Preciso saber se entende o que te explico De volta á sua função: TLDE *insere(TLDE** l, int elem) { TLDE* temp = novaLista(elem); temp->prox = *l; (*l)->ant = temp; (*l) = temp; } Sua função retorna um ponteiro. Ao menos foi declarada assim. Seu compilador não reclamou de não estar retornando nada? Não achou que seria importante? Se achou que era importante porque não retornou algo? Se não achou porque não declarou como void como no código original? Você está inserindo no início. O código original inseria no final. Se você pensasse no que retornar teria talvez entendido que podia retornar o novo endereço de início. E se retornasse o novo endereço de início não precisaria passar TLDE** Pense nisso: apenas retorne temp e atribua o valor de volta... Só isso. lista = insere(lista, valor); Mais um palpite: inverta isso: você insere um valor na lista. É mais legível e intuitivo declarar Lista* insere(int elem, Lista* L); // insere 'elem' na lista 'L' Mais: está declarando uma função insere() que retorna um endereço de TLDE então formalmente, como é uma declaração, devia escrever TLDE* insere(int, TLDE*); // insere() retorna TLDE* o fato de *insere ser do tipo TLDE é uma consequência.
-
C Selecionando Caracter dentro de uma palavra em C
arfneto respondeu ao tópico de Marcus Canuto em C/C#/C++
Eles são numerados, a partir de 0 -
C++ criação de sistema para armazenamento de dados
arfneto respondeu ao tópico de UILIAN DE OLIVEIRA FARIAS em C/C#/C++
todos esses dados sobre os livros ao invés de aparecerem na tela apenas como constantes irão para o tal arquivo txt no disco. Ao invés de printf() pode usar fprintf() e gravar direto no arquivo -
Sim, funciona do mesmo modo. Toda expressão é avaliada de modo que retorna um número. E zero é falso, Apenas zero.
-
Eu estava dizendo sobre você manter o código que tinha nesse tópico, ou melhorar um pouco, e partir daí escrever os próximos exercícios, inclusive esses aqui... E não escrever tudo de novo. Veja uma definição mais "arrumadinha" de lista 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 veja que item é só um ponteiro. Então tanto faz se vai usar um int ou uma struct com matricula e notas ou uma playlist ou uma lista de produtos de uma nota fiscal ou o inevitável exercício dos livros na biblioteca. Nenhuma função da lista trata os dados e isso faz toda a diferença. Programe algo assim a partir daquele código que tinha E a lista tem uns atributos, por exemplo o tamanho atual e capacidade... Veja insere() por exemplo: Lista* inserir_na_ordem(void*, Lista*, int(*)(void*, void*)); Lista* inserir_no_inicio(void*, Lista*); Lista* inserir_no_final(void*, Lista*); Entende a diferença? Pode inserir qualquer coisa. Só tem o nome lá. Epode inserir no fim ou no começo. Ou na ordem. E mesmo assim não precisa saber o que são os dados porque quem vai usar a função insere_na_ordem() vai fornecer a função que compara... Esse é um conceito muito importante. Muitos algoritmos funcionam assim.
-
Entendi. Mas está usando as funções que recebeu no outro exercício? Acho que deve tentar só adaptar aquilo num primeiro momento.
-
Olá Não entendi seu programa. Não estou certo de que sei o que você pretendia fazer. Parece muito complicado. Mas set3.get_allocator().allocate(10); Que quer fazer com isso? allocate() devolve um ponteiro e você nada faz com ele. std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), set3.begin()); Se set3 é std::set<> então o que faz você imaginar que set3.begin() seja um output iterator e não um std::set<>::iterator? Por certo que o compilador vai rejeitar... Pode usar inserter() que é um tipo de output iterator ou usar outra técnica, como um loop e um copy ou usar for_each() ou derivar set e definir operator+ para uniao, - por exemplo. Acho que tentou adaptar esse exemplo // set_union example #include <iostream> // std::cout #include <algorithm> // std::set_union, std::sort #include <vector> // std::vector int main () { int first[] = {5,10,15,20,25}; int second[] = {50,40,30,20,10}; std::vector<int> v(10); // 0 0 0 0 0 0 0 0 0 0 std::vector<int>::iterator it; std::sort (first,first+5); // 5 10 15 20 25 std::sort (second,second+5); // 10 20 30 40 50 it=std::set_union (first, first+5, second, second+5, v.begin()); // 5 10 15 20 25 30 40 50 0 0 v.resize(it-v.begin()); // 5 10 15 20 25 30 40 50 std::cout << "The union has " << (v.size()) << " elements:\n"; for (it=v.begin(); it!=v.end(); ++it) std::cout << ' ' << *it; std::cout << '\n'; return 0; } de http://www.cplusplus.com/reference/algorithm/set_union/ para rodar com set. note que set_union() curiosamente nada tem a ver com set mas sim com sorted ranges Vou deixar um curto exemplo que lista os conjuntos usando um simples loop e depois ou output iterator só pra mostrar a união. E depois fazer a mesma coisa usando algoritmos. Talvez seja isso que procura. Eis a saida conjuntos A, B e (A uniao B) usando loops Set 1: 1 2 3 4 5 6 Set 2: 1 3 5 7 8 9 [apenas saida] Set 3: 1 2 3 4 5 6 7 8 9 conjuntos A, B e (A uniao B) usando algoritmos Set 1: 1 2 3 4 5 6 Set 2: 1 3 5 7 8 9 Set 3: 1 2 3 4 5 6 7 8 9 [usando for_each] Set 4: 1 2 3 4 5 6 7 8 9 E o programa #include <iostream> #include <set> #include <string> #include <iterator> #include <algorithm> using namespace std; int main() { const char* let1[] = { "1", "2", "3", "4", "5", "6" }; const char* let2[] = { "1", "3", "5", "7", "8", "9" }; set<string> set1(let1, let1 + 6); set<string> set2(let2, let2 + 6); // usando loops e sem criar o vetor cout << "\nconjuntos A, B e (A uniao B) usando loops\n"; cout << "\nSet 1: "; for (auto x : set1) cout << x << " "; cout << "\nSet 2: "; for (auto x : set2) cout << x << " "; cout << "\n[apenas saida]\nSet 3: "; ostream_iterator<string> iter_saida{ cout, " " }; std::set_union( set1.begin(), set1.end(), set2.begin(), set2.end(), iter_saida // iterador de saida associado a cout ); cout << "\n"; // usando algoritmos cout << "\nconjuntos A, B e (A uniao B) usando algoritmos\n"; cout << "\nSet 1: "; copy(set1.begin(), set1.end(), iter_saida); cout << "\nSet 2: "; copy(set2.begin(), set2.end(), iter_saida); set<string> set3; std::set_union( set1.begin(), set1.end(), set2.begin(), set2.end(), inserter(set3, set3.begin()) ); cout << "\nSet 3: "; copy(set3.begin(), set3.end(), iter_saida); cout << "\n"; // usando for_each() set<string>set4; for_each( set1.begin(), set1.end(), [&set4](string i) {set4.insert(i); }); for_each( set2.begin(), set2.end(), [&set2,&set4](string i) { if(set2.end() != set2.find(i)) set4.insert(i); }); cout << "\n[usando for_each] Set 4: "; copy(set4.begin(), set4.end(), iter_saida); cout << "\n"; return EXIT_SUCCESS; } Faz várias vezes a mesma coisa, afinal é só um exemplo. Espero que ajude adicionado 1 minuto depois Não entendi o que significa o push_back aqui
-
Os mesmos dados vão estar nas duas listas, as matrículas e notas. Vai criar OUTRA lista, igual. Mais uma vez, não é uma lista de referência que aponta para os dados da outra. É uma lista completa, novinha. Escreva uma função que percorre uma lista do fim para o início e mostra os dados. Use as funções que você já tem. Depois mude essa função para ao invés de mostrar inserir em outra lista. Use nomes mais indicativos do que está havendo...
-
C++ Arquivos em linguagem C, Projeto peças(cadastro, alteração, consulta e vendas)
arfneto respondeu ao tópico de AmandaEstella em C/C#/C++
Olá Seu programa ainda tem muitos problemas, eu acho Não use acentos no código, comentários, variáveis. Só vai dar problema dependendo em que máquina for abrir o código, e em pouco ajuda na prática. case e default são os comandos dentro do case não use variáveis globais a menos que receba em dobro em dinheiro ou em nota. É só problema.Passe parâmetros entre as funções. evite retornar void. É um desperdício. No mínimo pode retornar alguma condição ou valor significativo não altera arquivos diretamente. Pode corromper o arquivo em definitivo. E só dá problema. Ao iniciar o programa carregue os dados a partir dos arquivos no disco. Trabalhe com os dados na memória durante o programa. Na saída grave tudo de volta atualizado não use conio.h isso tem 30 anos e essas funções de pouco servem desde os '90. não use um menu durante os testes. Demora uma eternidade para testar o programa e ficar inventando dados. Use constantes e arquivos e termine o programa. Aí volta lá e escreve um menu, se possível uma função que já retorna a opção escolhida pelo usuário crie seu programa em torno dos dados: Peça e Venda. Use vetores dessas estruturas. Faça o programa aos poucos. Vários pequenos programas são muito mais fáceis e rápidos para testar e escrever e alterar. -
Acho que a menos de prova em contrário toda lista é duplamente encadeada. É o caso em que cada nó aponta para o próximo e para o anterior. Em geral na literatura se vê uma tal forward list em que os nós só tem ponteiro para o próximo. Claro que podia também ser para o anterior. Assim economiza um ponteiro para cada nó, mas lógico que se precisar seguir no sentido contrário tem que percorrera lista toda de novo. Esse exercício é trivial: basta percorrer a lista e criar a outra ao contrário
-
a função é o insertion sort apenas. Só escrevi meio que ao contrário porque achei mais legível. E é claro que podia passar o endereço de T e não o valor.
-
Claro, o endereço de onde começou é o fim da lista e foi fornecido: p.fim. E insere() insere sempre no fim... O conteúdo da lista vai ser preservado em termos de ponteiros, mas a lista toda vai ser redefinida, apenas copiada para o fim dela mesma. É verdade, mas não devia ser preciso todo esse trabalho de recriar a lista toda com os mesmos ponteiros se vai só extrair uma cópia em ordem... Meio bobinho o enunciado. Podia só varrer a lista P e criar uma lista Q com os ponteiros em ordem de classificação, uma lista de referência. Só que aí não usaria o código fornecido, só a estrutura já na memória @herbertbahia considerando seu vetor int v[] pense nessa função int insere_na_ordem(int N, int V[], int T) { // insere N em V[], V com T elementos int pos = 0; for (pos = T; pos > 0; pos = pos - 1) { if (V[pos - 1] > N) V[pos] = V[pos - 1]; else break; }; // for() V[pos] = N; // pos = posicao certa return T + 1; }; que já insere o valor extraído da fila no vetor, só que na ordem. Acabou acabou: não precisa ler tudo de novo e classificar: apenas aproveita a oportunidade de vir um por um, como eu falei. Ela retorna o total: atenção
-
Sim, claro. Se optar por esse caminho o vetor fica dentro de ordena(). Depois de coletar os int que estão na fila você cria a nova a partir do vetor ordenado. Para ordenar o trivial é usar insertion sort já que vai pegar um por um mesmo Eu não tinha lido com atenção o código e o enunciado. Como precisa preservar a fila p e não foram fornecidas funções de percurso simplesmente, a única coisa que tem lá é retira(), fica complicado percorrer a fila usando o código que está lá sem mudar nada... Nem sei se foi de propósito que o enunciado acabou assim. O fato é que você precisa retirar para poder ver o que tem lá e precisa repor na ordem. Nada especial, mas um pouco chato. Você pode retirar os nós e colocar de volta no fim, marcando o endereço de onde começou para evitar um loop. e assim poderia ficar só com as rotinas fornecidas. Confirme se entendeu isso. Continuam válidas as duas opções que sugeri, apenas com esse cuidado de preservar as coisas. Veja isso com papel e caneta antes e vai entender, eu creio.
-
Pena não poder mudar o código oferecido, porque ele poderia ficar bem melhor... Como seu compromisso é apenas com a função TFila* ordena (TFila *f) pode escrever isso do modo como achar melhor. É claro que p vai ficar com todos seus elementos, já que vai criar outra fila. Não entendi o porque da observação no enunciado já que é mais fácil criar outra pilha do que classificar a fila original e o objetivo é exatamente criar outra. Seria um exercício mais complexo classificar in-line a mesma fila. De volta ao enunciado: Sugiro duas opções: como são apenas int os dados da fila, apenas criar um vetor com eles em ordem. É trivial porque vai ler um por um mesmo, usando retira() e aí coloca claro no vetor já na ordem porque afinal repito vem 1 a 1. Ao final da fila tem o vetor ordenado e cria a nova fila num único loop usando insere() uma opção talvez mais elegante seria SOMAR ao código fornecido uma rotina "insere_na_ordem()" que faz advinha o que? Insere na ordem. É simples, e nesse caso você em um único loop retira da fila original usando retira() e insere na nova usando sua nova função. Claro que ela já deveria fazer parte do código oferecido, assim como uma rotina para inserir no fim e outra para inserir no início, ao invés de uma singela insere() void insere_na_ordem(TFila* fila, int elemento);
-
Escreva seu programa em torno dos dados, sempre Isso sugere que podia usar % --- módulo, o resto da divisão --- e o tamanho do universo de letras para codificar, e provavelmente pode ficar também sem o alfabeto[] e usar só os limites, já que os símbolos são consecutivos. E que limite é esse? no caso aqui é a distância entre a letra lida e 'a' Seu exemplo usa L = 26 símbolos e uma distância K. E é 1:1 no sentido de que cada simbolo vai gerar um outro na saída. É só um filtro e não vai mudar o comprimento. Então se um símbolo X está dentro do intervalo e na posição [ i ] apenas troca pelo valor na posição [ i + K ] % L. Ex: Para K = 6, por exemplo: Para x == 'a': i = 0, i + K = 6, (i + K) % 26 = 6, y = 'a' + 6 = 'g' Para x == 'y': i = 23, i + K = 29; (i + K) % 26 = 3, y = 'a' + 3 = 'd' Um gabarito (use os dados) ....*.....1....*....2....5 01234567890123456789012345 abcdefghijklmnopqrstuvxywz E pode ver o sentido do que estou explicando A linha de comando Considere usar K e a linha como parâmetros de execução, o óbvio desde os '70. Exemplo: se seu programa é cesar.exe em Windows: cesar 3 cesar 6 "um teste simples" cesar 8 teste_simples E vai economizar um tempo ao menos para testar ou demonstrar isso. A menos que goste de ficar esperando e digitando letrinhas no teclado e rodando o programa a cada vez, e esperando o prompt, e digitando k, e digitando a string... Assim O primeiro caso perguntaria a string mas já saberia que K = 3. O segundo usaria K = 6 e a string com espaços no meio O terceiro usaria K = 8 e a string como digitada Em geral isso é feito só com uma tabela de referência: é só um byte e são só 256 possíveis valores então no início você aplica o valor de K e arranja tudo uma vez só na tabela, e na saída troca X por tabela[X] sem lógica alguma. De volta ao seu programa for (i=0;i<26;i++) { if (codigo[alpha]!=alfabeto[i]){ continue; } else codigo[alpha]=alfabeto[i+k]; alpha++; } Sua lógica está, digamos, de ponta cabeça. O loop não é pelas MAX letras --- sim você esqueceu de trocar 26 por MAX --- do grupo mas sim pelas strlen(string) letras da entrada. char codigo[MAX],copia[MAX],alfabeto[]="abcdefghijklmnopqrstuvwxyz"; E se leu o que expliquei já sabe que não precisa de codigo[MAX] não precisa de copia[MAX] não precisa de albabeto[] Basta ler letra a letra até o fim e mostrar o valor dela segundo a distância K Ao final um '\n' E a vida segue para o próximo exercício
-
Talvez seja muita esperança esperar encontrar algo exatamente assim Em geral isso se faz com DOIS ou CINCO dados. Faça o programa em torno dos dados. Provavelmente o mais simples: escreva uma função par() que devolve o óbvio, um par de dados, e uma função Sorteio(N) que devolve N pares chamando par() e chame Sorteio(4) para receber um vetor de 4 pares de int com valores de 1 a 6 correspondendo... ao sorteio. E use no programa. Pode começar com constantes e já construir o programa todo sem isso
-
Essa é uma noção comum, mas não está certa. Se fizer só isso vai trabalhar MUITO mais. E está já trabalhando muito mais. A lista tem outras variáveis --- ou pode ter --- além desse endereço. E isso é bom e não ruim. Facilita apenas. Veja uma possibilidade 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; Pra que isso? Simples: ao declarar Lista uma_lista, outra_lista, lista[500]; Lista* lista; Você tem centenas de listas, mas cada uma pode ter um nome, já tem ponteiros pros dois lados, uma capacidade em termos de número de nós, um total atualizado de nós e um ponteiro para o início e outro para o fim. Tudo fica mais fácil. E em cada nó tem os itens, só que foram declarados (void*) item. Então sua lista funciona para qualquer coisa, para o resto da vida. O enunciado não está bom e talvez esteja até errado mesmo. Se vai criar uma sub-lista é uma outra estrutura. Se vai apagar os nós da lista original quer dizer que não está criando uma sub-lista mas apenas editando a lista original e apagando livros que não são do ano desejado. Se vai criar uma sub-lista não vai criar os nós de dados, mas vai criar os nós correspondentes à estrutura da sub_lista. De todo modo não é nada complicado. Escreva a lista normal se ainda não fez isso, as funções todas. Claro que vai criar uma função mostra() para poder listar e testar se criou direitinho, e então copie essa função para criar a sub lista. É óbvio que para listar vai percorrer a lista toda e então no caminho vai criando a sub lista e corrigindo os ponteiros
-
C++ criação de um programa em devc++
arfneto respondeu ao tópico de UILIAN DE OLIVEIRA FARIAS em C/C#/C++
"pressione", certo? Seu programa não faz nada. Está usando constantes para imprimir os livros. Qual o propósito? Para que? Mesmo que liste os livros não vai incluir o registro das obras. Isso é claro variável: alguém vai digitar esses dados para o programa -
Claro, mas max é um nome reservado... Deve ter recebido warnings sobre isso Funções vão facilitar e não complicar a sua vida. São apenas blocos de código com nome, mas facilitam muito as coisas A alocação de memória não está certa. Pode alocar direto os 100 ponteiros para os funcionários, são só uns 400 bytes, mas a cada novo cara deve alocar uma estrutura toda e colocar o endereço na posição do vetor... Faça o programa em torno dos dados. Sempre em torno dos dados. veja como pode ser mais simples: typedef struct { char nome[MAX_NOME]; float base; float comissao; float total; } Funcionario; typedef struct { int N; Funcionario* cadastro[MAX_FUNC]; } Empresa; int classifica(Empresa*); Funcionario* le_um(Empresa*,FILE*); int mostra_todos(Empresa*); int relatorio(Empresa*); Uma empresa tem N funcionários e um cadastro. um cadastro tem MAX_FUNC ponteiros para funcionários uma função classifica o cadastro uma função le um funcionário a partir de um arquivo, que pode ser o teclado, e devolve um funcionário pronto para inserir no cadastro da empresa, o simples uma função classifica o cadastro da empresa uma função imprime o relatório ao final precisa liberar a memória E main() pode ficar simples como int main() { Empresa loja; loja.N = 0; const char* final = "FIM\n"; //lendo os dados while (le_um(&loja,stdin)){}; mostra_todos(&loja); printf("Em main(): Total de funcionarios: %d\n", loja.N); classifica(&loja); mostra_todos(&loja); relatorio(&loja); // aqui libera a memoria alocada return 0; }; Que até já roda: mostra_todos(): Total de 0 funcionarios ----- Em main(): Total de funcionarios: 0 classifica() mostra_todos(): Total de 0 funcionarios ----- relatorio() Claro, a primeira chamada a mostra() é para ver se leu direito e a segunda é pra ver se classificou direito e são só pra teste. O relatório é que vai mostrar a saída definitiva. Parece um brinquedo mas é quase o seu programa, afinal digitei em cima de seu programa. #define _CRT_SECURE_NO_WARNINGS #define MAX_FUNC 100 #define MAX_NOME 40 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char nome[MAX_NOME]; float base; float comissao; float total; } Funcionario; typedef struct { int N; Funcionario* cadastro[MAX_FUNC]; } Empresa; int classifica(Empresa*); Funcionario* le_um(Empresa*,FILE*); int mostra_todos(Empresa*); int relatorio(Empresa*); int main() { Empresa loja; loja.N = 0; const char* final = "FIM\n"; //lendo os dados while (le_um(&loja,stdin)){}; mostra_todos(&loja); printf("Em main(): Total de funcionarios: %d\n", loja.N); classifica(&loja); mostra_todos(&loja); relatorio(&loja); // aqui libera a memoria alocada return 0; }; int classifica(Empresa* E) { printf("classifica()\n"); /* //imprimindo salario antes da ordenação printf("Salario no Mes: R$%.2f\n", salario); printf("- %s\n", dados->nome); } //ordenação por bubble sort for (j = i - 1; j > 0; j--) { //j: limite da última posição for (i = 0; i < j; i++) { // Compara par a par: if (dados.salario > dados[i + 1].salario) { aux = dados; dados = dados[i + 1]; dados[i + 1] = aux; } } } */ return 0; }; Funcionario* le_um(Empresa* E, FILE* f) { // le um funcionario para a empresa E // a partir do arquivo f return NULL; }; int mostra_todos(Empresa* E) { printf("mostra_todos(): Total de %d funcionarios\n", E->N); for (int i = 0; i < E->N; i += 1) { printf("%3d\t%s\n\t%8.2f\n\t%8.2f\n\t%8.2f\n", 1+i, E->cadastro[i]->nome, E->cadastro[i]->base, E->cadastro[i]->comissao, E->cadastro[i]->total ); }; printf("-----\n"); return 0; }; // mostra_todos(); int relatorio(Empresa* E) { printf("relatorio()\n"); return 0; };
-
Li rapidamente seu programa e parece um pouco longe de funcionar ainda. struct funcionario { char nome[max]; float salariob; float comissao; float salario; }aux; struct funcionario* dados; //ponteiro para o espaço alocado dados = malloc(max * sizeof(struct funcionario*)); não devia redefinir max. Use outro nome. E max é o total maximo de funcionários e também o tamanho maximo dos nomes em número de letras? se não opera com os valores podia já gravar só o salário total ou só as parcelas está alocando espaço para 100 PONTEIROS para os dados e depois lendo um sobre o outro? a comparação no sort é onde deve decidir a ordem if (dados.salario > dados[i + 1].salario) { aux = dados; dados = dados[i + 1]; dados[i + 1] = aux; } e é aqui que se o salário é igual você compara por outro critério... Sabe escrever funções?
-
Ainda acho que não dá pra usar containers nesse exercício porque é um exercício para mostrar loops aninhados, mas de vetor <string> para um char[][] de C não muda muito afinal. E aí seria bem como escreveu! Mas se é possível pode usar <vector> então pode usar <list> e <set> e set é mais intuitivo e fácil de ler: são conjuntos afinal. E set tem find() e vector não. Mas se <vector> não tem find() std::find(0 está aí. Claro que dá na mesma e então podia escrever de um jeito C++ for (auto valor : VA) if (std::find(VB.begin(), VB.end(), valor) == VB.end()) cout << valor << endl; E assim funcionaria para VA e VB sendo <list> <set> ou <vector> ou qualquer classe "iterable" na essência dos containers em C++. Para focar no espírito STL e C++ se pode também usar for_each() e vai funcionar para qualquer classe dessas, como vector ou set ou uma classe sua mesmo, escrevendo apenas for_each(A.begin(), A.end(), [&B](auto valor) {if (std::find(B.begin(), B.end(), valor) == B.end()) cout << valor << endl; }); por exemplo. Eis 3 possíveis casos: Usando vetor e find() mas funciona para qualquer container int outroVF() { // usando std::find() std::string lista1[8]{ "0", "1", "2", "3", "3", "4", "5", "5" }; std::string lista2[4]{ "1", "3", "5", "5" }; std::vector <string> VA; for (auto valor : lista1) VA.push_back(valor); // lista1 em VA std::vector <string> VB; for (auto valor : lista2) VB.push_back(valor); // lista2 em VB for (auto valor : VA) if (std::find(VB.begin(), VB.end(), valor) == VB.end()) cout << valor << " "; cout << endl; return 0; }; Usando Set e .find() int outroSet() { std::string lista1[8]{ "0", "1", "2", "3", "3", "4", "5", "5" }; std::string lista2[4]{ "1", "3", "5", "5" }; std::set <string> A; std::set <string> B; for (auto valor : lista1) A.insert(valor); // lista1 em A for (auto valor : lista2) B.insert(valor); // lista2 em B for (auto valor : A) if (B.find(valor) == B.end()) cout << valor << " "; cout << endl; return 0; }; Que só funciona se a classe tiver find() Ou usando for_each(), genérica também int outroFe() { std::string lista1[8]{ "0", "1", "2", "3", "3", "4", "5", "5" }; std::string lista2[4]{ "1", "3", "5", "5" }; std::set <string> A; std::set <string> B; for (auto valor : lista1) A.insert(valor); // lista1 em A for (auto valor : lista2) B.insert(valor); // lista2 em B for_each(A.begin(), A.end(), [&B](auto valor) {if (std::find(B.begin(), B.end(), valor) == B.end()) cout << valor << endl; }); return 0; }; Um teste com as 3 mostra claro 0 2 4 0 2 4 0 2 4 Como esse #include <algorithm> #include <iostream> #include <set> #include <vector> using namespace std; int outroFe(); int outroSet(); int outroVF(); int main() { outroFe(); outroSet(); outroVF(); return 0; }; int outroSet() { std::string lista1[8]{ "0", "1", "2", "3", "3", "4", "5", "5" }; std::string lista2[4]{ "1", "3", "5", "5" }; std::set <string> A; std::set <string> B; for (auto valor : lista1) A.insert(valor); // lista1 em A for (auto valor : lista2) B.insert(valor); // lista2 em B for (auto valor : A) if (B.find(valor) == B.end()) cout << valor << " "; cout << endl; return 0; }; int outroFe() { std::string lista1[8]{ "0", "1", "2", "3", "3", "4", "5", "5" }; std::string lista2[4]{ "1", "3", "5", "5" }; std::set <string> A; std::set <string> B; for (auto valor : lista1) A.insert(valor); // lista1 em A for (auto valor : lista2) B.insert(valor); // lista2 em B for_each(A.begin(), A.end(), [&B](auto valor) {if (std::find(B.begin(), B.end(), valor) == B.end()) cout << valor << " "; }); cout << endl; return 0; }; int outroVF() { // usando std::find() std::string lista1[8]{ "0", "1", "2", "3", "3", "4", "5", "5" }; std::string lista2[4]{ "1", "3", "5", "5" }; std::vector <string> VA; for (auto valor : lista1) VA.push_back(valor); // lista1 em VA std::vector <string> VB; for (auto valor : lista2) VB.push_back(valor); // lista2 em VB for (auto valor : VA) if (std::find(VB.begin(), VB.end(), valor) == VB.end()) cout << valor << " "; cout << endl; return 0; };
-
escreva uma função como void rodape(char* msg) que mostra o que quer. Se quer usar em uma posição fixa da tela vai ter que controlar o cursor em todo o programa e não enviar '\n' nunca porque a tela rola sozinha e acaba desalinhando tudo. E é trivial, apenas chato. Essa é a função BOOL WINAPI SetConsoleCursorPosition( _In_ HANDLE hConsoleOutput, _In_ COORD dwCursorPosition ); No popular, pode usar assim static COORD coord; HANDLE H = GetStdHandle(STD_OUTPUT_HANDLE); coord.X = coluna; coord.Y = linha; SetConsoleCursorPosition(H, coord); E o cursor vai para a linha 'linha' e coluna 'coluna', em programas para console do Windows. Pode escrever uma função simples como void gotoYX(int linha, int coluna) { static COORD coord; HANDLE H = GetStdHandle(STD_OUTPUT_HANDLE); coord.X = coluna; coord.Y = linha; SetConsoleCursorPosition(H, coord); return; }; // gotoXY E chamar assim gotoYX( 10,50 ); // cursor na linha 10 coluna 50 que é a noção usual de linha e coluna e não a noção matemática de plano xy que o sistema usa. Não use esse troço. Isso vem da biblioteca conio da Borland dos anos 80 e não tem nada realmente importante. E tem algumas funções obsoletas há décadas e seu compilador vai ficar reclamando sobre "xxx is deprecated use yyy" toda hora. A menos que seu IDE seja dessa época também
-
C Erro de referência ao usar Tipos Abstratos de Dados
arfneto respondeu ao tópico de pelequinho em C/C#/C++
Acho que basta tirar esse ponto de #ifdef ALUNOS.H
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