Ir ao conteúdo

arfneto

Membro Pleno
  • Posts

    6.526
  • Cadastrado em

  • Última visita

Tudo que arfneto postou

  1. Olá Felipe Legal incluir o enunciado Afinal é como um contrato. Como falei, não é um bom exemplo. É uma pena uma escolha dessas. O que vai mudar para o template é o máximo de ítens, que podia ser uma constante na struct, e o conteúdo, que é irrelevante. poderia ter uma lista de contatos de cada tipo na mesma agenda Esse conceito de template nem foi pensado para isso. E em C++ em situações normais não se usa uma rotina inicializar() porque cada struct já vem com isso de fábrica, digamos. A rotina que insere tem acesso à estrutura inteira então pode preencher todos os campos como preferir. Não recomendo ficar lendo nada do teclado enquanto está testando. Demora uma eternidade e fica difícil de reproduzir m erro. Use constantes e quando estiver funcionando em minutos você insere a leitura... Vou te ajudar
  2. Olá Felipe Depois eu entendi que estava lá o código do header... templates podem ser mesmo muito úteis, como maneira de personalizar códigos que podem tratar vários tipos de dados, Confesso no entanto que não entendi esse exemplo: usar para uma agenda não parece ser vantagem. Para excelentes exemplos basta olhar na própria STL --- e veja que STL significa exatamente isso, biblioteca padrão de templates --- e ver que se pode declarar conjuntos, listas, filas e vetores de qualquer coisa e o código já está pronto lá. Seu programa é um programa em C na prática. Por exemplo é raro em C++ se ter uma função inicializa() para algo. Um construtor faz isso normalmente. Uma classe agenda --- struct agenda --- do modo como foi escrita não usa nenhuma vantagem de C++ exceto usar essas tais templates onde --- posso estar errado --- não é um bom cenário. Exemplos para declarações usando essas templates para dados pessoa_fisica<string, 1> uma_pessoa_fisica; Agenda<pessoa_fisica<string, 1>, 100>* uma_agenda = new(Agenda<pessoa_fisica<string, 1>, 100>); Essa é a ideia de usar templates. Talvez essas declarações não funcionem no seu programa atual mas essa é a ideia: o compilador usa o código no template para gerar a declaração a cada momento. É um modelo. E para métodos? Por exemplo insere <pessoa_fisica<string,1>, 100> ( uma_pf, agenda_pf ); Esse método por exemplo seguiria o mesmo princípio e isso é muito útil. Mas temo que não nesse exemplo Confesso que ainda não entendi o propósito. Vai gerar uma agenda que pode ser para pessoa jurídica ou para pessoa física e vai usar templates para definir o máximo de itens na agenda? E então uma agenda de 98 itens vai ser estruturalmente diferente de uma agenda de 89 itens? Só que não é. Em C++ uma classe Agenda poderia ser implementada justamente usando coisas da STL e você poderia ter a Agenda armazenada em vetores, ou listas ou conjuntos ou sei lá. Esse era o propósito original dessas tais templates. Veja esse seu caso template <typename TIPO, int MAX> struct Agenda { TIPO itens[MAX]; int quantidade; }; Isso quer dizer que, até onde eu entendi, vai ter uma agenda que pode ser de pessoa jurídica ou pessoa física, e o tamanho faz parte da definição da template. Fixo. Mas em C++ tem um enorme suporte para gravar entradas de agenda em estruturas de dados diversas... E pessoa_jurídica é a pessoa_física mais uns campos. E a agenda não tem nome... Outra hora mostro um exemplo. Vejo que seu programa está aumentando foi boa ideia mudar a declaração dos ítens da agenda. Aqueles [] na versão inicial não eram boa ideia. MAs temo que os int de agora também não sejam...
  3. Rodou o programa que te mostrei? Entendeu porque a rotina funciona igual para várias configurações dos doze int na memória? tipo 2x6 1x12, 3x4? Entendeu a diferença entre as duas versões mostra() e mostra_e() naquele programa? Se não entendeu 100% então deve ter alguma pergunta... Arrumou seu código para a tal matriz?
  4. Talvez devesse postar o outro header tambem, agenda.h
  5. O que seria uma struct genérica e uma "original"? Se refere ao código gerado a partir do template?
  6. Olá! Talvez pudesse considerar no caso recursivo o raciocínio recursivo mesmo: se estou procurando a distância entre esses dois valores, então: se eles são iguais eu sei a distância: zero. se eles não são iguais, então a distância é pelo menos 1 então eu somo 1, diminuo um dos pontos e continuo contando até eles serem iguais, certo? Essa é a recursão por definição. Só tem essa pegadinha do maior poder vir primeiro e por isso o código tem 3 linhas Exemplo simples para o caso recursivo // retorna distancia entre a e b usando recursao int dist_r(int a, int b) { if (a == b) return 0; // fim. Ja temos a distancia if (b > a) return 1 + dist_r(a, (b - 1)); // o primeiro e maior entao diminui do outro lado return 1 + dist_r((a - 1), b); // sim, podia escrever usando dois pares '?' ':' } // end dist_r() Exemplo simples para o caso iterativo // retorna distancia entre a e b usando aritmetica int dist_i(int a, int b) { if (a > b) return a - b; return b - a; // sim, podia ser escrito em uma linha so usando '?'e ':' } // end dist_i() Um programa de teste Porque não um programa curtinho que testa para um intervalo determinado, se possível em torno de zero pra testar os casos de sinais distintos, e já mostra e compara os resultados? Por exemplo para A = -2 e B entre -10 e 10? Algo assim dist( -2,-10) = ( 8, 8) [iterativa, recursiva] dist( -2, -9) = ( 7, 7) [iterativa, recursiva] dist( -2, -8) = ( 6, 6) [iterativa, recursiva] dist( -2, -7) = ( 5, 5) [iterativa, recursiva] dist( -2, -6) = ( 4, 4) [iterativa, recursiva] dist( -2, -5) = ( 3, 3) [iterativa, recursiva] dist( -2, -4) = ( 2, 2) [iterativa, recursiva] dist( -2, -3) = ( 1, 1) [iterativa, recursiva] dist( -2, -2) = ( 0, 0) [iterativa, recursiva] dist( -2, -1) = ( 1, 1) [iterativa, recursiva] dist( -2, 0) = ( 2, 2) [iterativa, recursiva] dist( -2, 1) = ( 3, 3) [iterativa, recursiva] dist( -2, 2) = ( 4, 4) [iterativa, recursiva] dist( -2, 3) = ( 5, 5) [iterativa, recursiva] dist( -2, 4) = ( 6, 6) [iterativa, recursiva] dist( -2, 5) = ( 7, 7) [iterativa, recursiva] dist( -2, 6) = ( 8, 8) [iterativa, recursiva] dist( -2, 7) = ( 9, 9) [iterativa, recursiva] dist( -2, 8) = ( 10, 10) [iterativa, recursiva] dist( -2, 9) = ( 11, 11) [iterativa, recursiva] dist( -2, 10) = ( 12, 12) [iterativa, recursiva] As rotinas retornaram valores identicos para o intervalo A partir desse código #include "stdio.h" int dist_r(int, int); // calcula distancia entre dois int, recursiva int dist_i(int, int); // calcula distancia entre dois int, iterativa int main() { int iterativo; int recursivo; int a = -2; for (int i = -10; i <= 10; i += 1) { iterativo = dist_i(a, i); recursivo = dist_r(a, i); printf( "dist(%3d,%3d) = (%3d,%3d) [iterativa, recursiva]\n", a, i, dist_i(a, i), dist_r(a, i) ); if (iterativo != recursivo) { printf("Erro para i = %d\n", i); return - 1; } } // end for printf("\nAs rotinas retornaram valores identicos para o intervalo\n"); return 0; } // end main() // retorna distancia entre a e b usando recursao int dist_r(int a, int b) { if (a == b) return 0; // fim. Ja temos a distancia if (b > a) return 1 + dist_r(a, (b - 1)); // o primeiro e maior entao diminui do outro lado return 1 + dist_r((a - 1), b); // sim, podia escrever usando dois pares '?' ':' } // end dist_r() // retorna distancia entre a e b usando aritmetica int dist_i(int a, int b) { if (a > b) return a - b; return b - a; // sim, podia ser escrito em uma linha so usando '?'e ':' } // end dist_i()
  7. Há claro um milhão de maneiras de fazer isso. Vou te falar de duas, as duas sendo uma representação no programa do que você faria numa folha de papel O mais comum: uma tabela e um contador Em geral as pessoas programam isso assim: você varre a entrada e vai criando uma lista de palavras numa tabela, ordenada pra facilitar a busca. Ao inserir cada palavra você vê na tabela de palavras já encontradas: se já tem você incrementa um contador para aquela palavra e continua. Quando acabar a linha você imprime a tabela e pronto. Em C seria um loop até o fim da linha. Para cada palavra encontrada: veja se já tem na lista. Se tem incrementa um contador, que pode ser um outro vetor, mas de int. Se não tem cria uma nova palavra e inicia novo contador. Para criar as palavras pode usar alocação dinâmica, afinal já sabe o tamanho da palavra afinal. Basta alocar com esse tamanho mais um, por causa do byte com zero que termina cada string. É melhor usar o zero no fim porque assim pode usar a função strcmp() para comparar a palavra que acha com cada uma que está no vetor. Mas não é essencial, já que pode simplesmente comparar letra a letra. Não é obrigado a usar alocação dinâmica: pode usar um vetor de strings. Cada string pode ter no maximo o tamanho da linha, claro. E quantas podem ser? Pense assim: o maior número vai ser com strings bem pequenas, A menor tem uma letra só e estaria entre dois brancos, então se sua linha tem 10 caracteres por exemplo vão caber no máximo... 0123456789 a b c d e metade do tamanho do vetor. Então se sua linha tem 80 caracteres pode ter no máximo 40 strings. No caso da maior string terá uma única string do tamanho da linha. No caso das menores terá no máximo umas 40 delas. considerando o que discutimos aqui. Exemplo dos dados char linha[80]; char palavras[40][81]; int contadores[40]; Algo até mais simples: um crivo Solução bem antiga, os gregos usavam desde antes de Cristo. Como o crivo de Eratóstenes que a gente aprende no ensino fundamental para achar números primos. Você lê a linha, pode até imprimir para ajudar a testar claro. Mas depois que leu nem precisa mais dela ou das palavras de verdade: você vai ler as palavras uma a uma, mas resolve a vida com cada palavra assim que a vê. Não espera compilar o resultado todo. afinal não é um livro, é só uma frase. Você lê uma palavra, posiciona um indicador para a posição logo a seguir dela pra continuar depois. Aí pega essa palavra e procura pra diante na frase toda e vai contando. Quando acha uma palavra marca no contador, que pode ser um só afinal, e apaga na frase a palavra. Quer dizer, troca por espaços todas as ocorrências extras da palavra. Imprime a palavra e o total de vezes. E continua para as próximas palavras. No final da linha o final do programa. Só isso. No final vai sobrar a linha com a lista de palavras únicas, se quiser imprimir para confirmar Exemplo dos dados char linha[80]; char palavra[80]; int contador; Teste antes com uma linha como essa a b c d a b c d uma linha com uma palavra só palavra e uma linha vazia, claro Pode usar soluções "não invasivas" também: sem declarar novas palavras, apenas declarando um vetor de início e outro de fim de cada palavra e atualizando um vetor de contadores. Mas recomendo uma dessas duas de que falei Conseguiu escrever algo nesses dias? Acha que consegue escrever um desse de que falei? Escreva mais
  8. Não E aquilo que eu sempre falo de ler a partir da direita? Se declarou int a[4] por exemplo então... Tem os colchetes a direita indicando que é um vetor depois vem a o nome e int o tipo então a[4] é claro um int como esta escrito E não pode usar new Mesmo porque em C não existe new() nem delete () que são os operadores de alocação e memória em c++ Em c se usa como eu disse malloc() e free() adicionado 7 minutos depois Não. Não é. Tudo depende de como foi declarado. Instalou o programa que escrevi na sua máquina? Rodou aquilo? É importante pra ajudar a entender Uma coisa é você declarar int* a[4] outra coisa é declarar int a[4] Quando você declara int a[4] quer dizer que vai reservar 4 int a partir do endereço de a Quando você declara int* a[4] quer dizer que você vai reservar 4 ponteiros para int, todos y enfileirados a partir do endereço do primeiro, a Deve ler da direita para a esquerda para entender adicionado 12 minutos depois O que eu tentei te mostrar naquele código é que uma mesma área de 12 int pode ser acessada como vetor [12] ou vetor[2][6] ou vetor [3][4] ou qualquer coisa Entenda que os valores são simplesmente enfileirados a partir do endereço inicial. E o que eu tentava mostrar com o programa adicionado 46 minutos depois Quando você declara algo como coisa* matriz [4] está indicando que matriz é um vetor de 4 posições e em cada posição vai ter um ponteiro, um endereço para coisa. Claro, todos os ponteiros tem o mesmo tamanho então você pode fazer com que ele aponte para outras "coisas" usando o que se chama cast. Exemplo : int* p = (int*) matriz [3] é perfeitamente legal em C ou C++ Mas você não está alocando nada aí. Apenas manipulando os endereços. Vamos chamar de matriz então um vetor de duas dimensões. Quando você declara um trem desses, por exemplo int matriz [3][5] está declarando int não ponteiros. Leia da direita para a esquerda São quinze int e eles vão estar lá na memória, um depois do outro. Primeiro os cinco da linha zero depois os cinco da linha um depois os cinco da linha dois IMPORTANTE isso. Então matriz[1][2] vai ser o oitavo cidadão a partir do início. A memória só tem uma dimensão. É o início é o endereço do primeiro. no geral (X, Y) = (X*largura) + Y é a fórmula que converte o endereço 2D tipo [1][2] no deslocamento linear X a partir do início do vetor na memória. Veja no exemplo matriz [1][2] para matriz declarada como int matriz [3][5] vai estar na posição 1*5 + 2 = 7 a oitava posição a partir do início... Só que todos os quinze são INT e o endereço do primeiro é o matriz [0][0] ou simplesmente matriz e C entende essas operações Então se você tiver o endereço do primeiro pode percorrer a matriz usando... Aritmética. Ex: int* p = matriz; *(p+7) = 345; Isso faz com que matriz [1][2] = 345; Entendeu? Não desista. É absolutamente essencial entender isso se quer ser produtivo nessas linguagens. Coisas como Qt, SQL, estruturas como listas e árvores, tudo isso só faz sentido se entender esse paradigma
  9. Talvez não tenha pensado nesse caso por completo não há qualquer garantia de que mesmo o vetor original tenha espaço alocado suficiente. Sequer se tem garantia de ser possível de aumentar porque a rotina pode ter sido chamada por engano com uma constante... Se você chamar replace() replace( "Qualquer coisa", 4, "azul" ); vai entender do que estou falando. A especificação é frágil. Só isso. Sem salvação. Não, não resolve como te expliquei Claro que aqui é um forum de discussão então é bom ver outro ponto de vista. Mas recomendo exatamente o contrário: justamente por ver onde os problemas podem ocorrer um iniciante --- ou mesmo um profissional que tente fazer isso na hora do almoço para ajudar alguém --- não deve destruir o argumento de entrada antes de estar certo de que tudo está ok. Alguns mais precavidos até declarariam como const o vetor inicial num primeiro momento e devolveriam o endereço novo na saída, que é o que a biblioteca padrão C faz em geral . Comentei isso numa mensagem anterior até. Talvez a noção do que um programador irá fazer não esteja assim tão claramente estabelecida e te dei ao menos um argumento O problema oferecido nem é assim muito bom, mas tem o mérito --- raro nesses programas para iniciantes --- de tentar mostrar ao aluno a vantagem possível de prosseguir a partir de elementos que ele criou, caso da rotina replace() Um passo a mais seria o estudante pensar que todos os atalhos e tags tem processamento similar e que se poderia usar a partir de replace() algo como eu mostrei insere_par_de_tags(linha, '*', "<b>", "</b>"); insere_par_de_tags(linha, '_', "<i>", "</i>"); E assim criar uma solução usando uma solução que usa uma solução, bem de acordo com o que um desenvolvedor precisa fazer Abraço
  10. Olá! De uma olhada no programa C abaixo, que mostra isso imprime vetor na ordem de endereco. Tam 12 (int [12]) 0 1 2 3 4 5 6 7 8 9 10 11 imprime vetor na ordem de endereco. Tam 12 (int [2][6]) 12 13 14 15 16 17 18 19 20 21 22 23 imprime vetor na ordem de endereco. Tam 12 (int [3][4]) 24 25 26 27 28 29 30 31 32 33 34 35 imprime vetor na ordem de endereco. Tam 25 (int [5][5]) 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 ********** ********** ********** ********** Usando os enderecos como parametro imprime vetor na ordem de endereco. Tam 12 (int [12]) 0 1 2 3 4 5 6 7 8 9 10 11 imprime vetor na ordem de endereco. Tam 12 (int [2][6]) 12 13 14 15 16 17 18 19 20 21 22 23 imprime vetor na ordem de endereco. Tam 12 (int [3][4]) 24 25 26 27 28 29 30 31 32 33 34 35 imprime vetor na ordem de endereco. Tam 25 (int [5][5]) 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 Ele imprime duas vezes a mesma coisa usando essas duas rotinas void mostra(int v[], int t, int col, char* mensagem) { printf("\nimprime vetor na ordem de endereco. Tam %d\n", t); printf("\n(%s)\n\n", mensagem); for (int i = 0; i < t; i++) { printf("%2d ", v[i]); if (i % col == col - 1) printf("\n"); } // end for } // end mostra E essa void mostra_e(int* v, int t, int col, char* mensagem) { printf("\nimprime vetor na ordem de endereco. Tam %d\n", t); printf("\n(%s)\n\n", mensagem); for (int i = 0; i < t; i++) { printf("%2d ", *(i+v) ); if (i % col == col - 1) printf("\n"); } // end for } // end mostra_e() Para vetores de 12 posições declarados como [12] ou [2][6] ou [3][4]. Para a primeira rotina o compilador reclama de tudo mas funciona. Para a segunda não há problema graças a um cast na chamada. Veja: mostra(v12, 12, 12, "int [12]"); mostra(v_2_6, 12, 6, "int [2][6]"); mostra(v_3_4, 12, 4, "int [3][4]"); mostra(a, 25, 5, "int [5][5]"); mostra_e((int*) v12, 12, 12, "int [12]"); mostra_e((int*)v_2_6, 12, 6, "int [2][6]"); mostra_e((int*)v_3_4, 12, 4, "int [3][4]"); mostra_e((int*)a, 25, 5, "int [5][5]"); Eis o programa #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> void mostra(int v[], int t, int col, char* mensagem) { printf("\nimprime vetor na ordem de endereco. Tam %d\n", t); printf("\n(%s)\n\n", mensagem); for (int i = 0; i < t; i++) { printf("%2d ", v[i]); if (i % col == col - 1) printf("\n"); } // end for } // end mostra void mostra_e(int* v, int t, int col, char* mensagem) { printf("\nimprime vetor na ordem de endereco. Tam %d\n", t); printf("\n(%s)\n\n", mensagem); for (int i = 0; i < t; i++) { printf("%2d ", *(i+v) ); if (i % col == col - 1) printf("\n"); } // end for } // end mostra_e() int main() { int v12[12]; for (int i = 0; i < 12; i++) { v12[i] = i; }; int v_2_6[2][6]; for (int i = 0, k = 12; i < 2; i++) { for (int j = 0; j < 6; j += 1) { v_2_6[i][j] = k++; } }; int v_3_4[3][4]; for (int i = 0, k = 24; i < 3; i++) { for (int j = 0; j < 4; j += 1) { v_3_4[i][j] = k++; } }; // agora a matriz a[5][5] int a[5][5]; for (int i = 0, k = 36; i < 5; i++) { for (int j = 0; j < 5; j += 1) { a[i][j] = k++; } }; mostra(v12, 12, 12, "int [12]"); mostra(v_2_6, 12, 6, "int [2][6]"); mostra(v_3_4, 12, 4, "int [3][4]"); mostra(a, 25, 5, "int [5][5]"); printf("\n********** ********** ********** ********** \n"); printf("Usando os enderecos como parametro\n\n"); mostra_e((int*) v12, 12, 12, "int [12]"); mostra_e((int*)v_2_6, 12, 6, "int [2][6]"); mostra_e((int*)v_3_4, 12, 4, "int [3][4]"); mostra_e((int*)a, 25, 5, "int [5][5]"); return 0; } Pense nisso e escreva de novo
  11. Muito bom que funcionou! Parabéns. Não entendi o que disse sobre new(type) e tal. De fato em C não se usa isso mas sim malloc() e free(). E isso não ia ajudar em seu teste de todo modo porque lá está usando alocação estática. Em C++ se usa new() delete e delete[] Note que esses vetores multidimensionais em C são mesmo um pesadelo. E quase isso em outras linguagens também. Na declaração se vai usar mesmo [] deve deixar o primeiro em branco como int func( int vetor2D [][5] ); Note que os valores são alocados em sequencia na memória, uma coluna por vez, e C e C++ tem aritmética de ponteiros então em geral é muito mais tranquilo esquecer tudo isso e usar ponteiros
  12. Claro, mas esse é um programa para iniciantes e o algoritmo é destrutivo. Então se você usar o vetor inicial diretamente só vai dificultar a sua vida porque vai ficar mais difícil de testar porque vai zoar o vetor de entrada... Recomendo muito fazer o simples e usar outro vetor, e abusar de printf() para imprimir os resultados intermediários e tal. Depois que estiver funcionando você pode alterar seu programa, apagar ou coentar os printf() e usar um vetor só. @Gabriel Tellaroli Ramos Se não terminou ainda o trabalho, espero que ao menos tenha concluído a replace() e recomendo pensar numa função assim int insere_par_de_tags( char* texto, // a cadeia const char atalho, // o atalho, * ou _ no enunciado const char* tag_abre, // a nova tag de abertura const char* tag_fecha // e de fechamento ); que faz o que parece considerando o nome, troca um atalho por um par de tags usando replace() e você usaria assim insere_par_de_tags(linha, '*', "<b>", "</b>"); insere_par_de_tags(linha, '_', "<i>", "</i>"); É o caminho mais curto, possivelmente se já terminou por exemplo para os asteriscos, basta ir lá e trocar os valores pelos dos argumentos porque o resto vai continuar funcionando, certo? Veja um loop para uma rotina que funciona: entrada = fopen(arquivo, "r"); if (entrada == NULL) { perror("Abrindo o arquivo deu esse erro"); // deu pau return 0; } // end if printf("[linha/tamanho] [linha]\n"); // com legenda :) while (!feof(entrada)) { total_linhas += 1; fgets(linha, 50, entrada); // le a linha n tamanho_linha = strlen(linha); linha[tamanho_linha - 1] = 0; // termina a string porque // e nao \0 e vamos mostrar na tela printf("Entrada:\n[%2d,[%2d] [%s]\n", total_linhas, tamanho_linha, linha); // mostra insere_par_de_tags(linha, '*', "<b>", "</b>"); insere_par_de_tags(linha, '_', "<i>", "</i>"); printf("Saida:\n[%2d,[%2d] [%s]\n", total_linhas, tamanho_linha, linha); // mostra } printf("\nLidas %d linhas\n", total_linhas); fclose(entrada); return 0; E mostra isso [29,[28] [_a_ tag subinhado uma letra] Saida: [29,[32] [<i>a</i> tag subinhado uma letra] Entrada: [30,[28] [*b* tag asterisco uma letra] Saida: [30,[32] [<b>b</b> tag asterisco uma letra] Entrada: [31,[34] [A _linguagem_ C e muito poderosa!] Saida: [31,[38] [A <i>linguagem</i> C e muito poderosa!] Entrada: [32,[43] [A linguagem *C* e mais rapida que *Python*] Saida: [32,[52] [A linguagem <b>C</b> e mais rapida que <b>Python</b>] Entrada: [33,[39] [_ _ __ _ yabba dabba _ * dooooo * ****] Saida: [33,[68] [<i> </i> <i></i> <i> yabba dabba </i> <b> dooooo </b> <b></b><b></b>] adicionado 12 minutos depois Se sua rotina replace() funciona, essa rotina int insere_par_de_tags( char* texto, const char atalho, const char* tag_abre, const char* tag_fecha); não precisa de mais que umas 20 linhas. E você chama duas vezes mudando os parâmetros como expliquei insere_par_de_tags(linha, '*', "<b>", "</b>"); insere_par_de_tags(linha, '_', "<i>", "</i>"); Veja uma que funciona, com MUITOS comentários: int insere_par_de_tags( char* texto, // a cadeia const char atalho, // o atalho, * ou _ no enunciado const char* tag_abre, // a nova tag de abertura const char* tag_fecha // e de fechamento ) { int pos; int tam_texto = strlen(texto); int index = -1; do { // posiciona no primeiro asterisco do par. pode nao ter nenhum index = -1; // indica que nao tem asteriscos for (pos = 0; pos < tam_texto; pos += 1) { if (texto[pos] != atalho) continue; index = pos; break; } if (index == -1) return 0; // nao tinha mais asteriscos // entao o proximo asterisco esta em texto[index]; // e o enunciado garante que estão em pares // troca o primeiro replace(texto, index, tag_abre); tam_texto = strlen(texto); for (pos = index + strlen(tag_abre); pos < tam_texto; pos += 1) { if (texto[pos] != atalho) continue; index = pos;Se break; } if (index == -1) return -1; // nao podia acontecer entao retorna -1 // troca o segundo replace(texto, index, tag_fecha); tam_texto = strlen(texto); // trocou um par. volta pro inicio a ver se tem outro } while (index > 0); return 0; // retorna ok } // end insere_par_de_tags()
  13. que significa "mais recente"?
  14. Tenho dúvida de que possa simplesmente usar strcpy() para copiar as strings em replace(). Talvez perca pontos por isso. Afinal se pode usar strcpy() também pode usar strtok() e strstr() pra trocar as tags e não precisaria escrever replace(). Se puder usar, siga em frente, porque é sempre mais seguro E não fui eu que preparei o exercício afinal De todo modo veja esse programa que tem uma função que le o arquivo de entrada, uma implementação de replace() bem simples, que não usa strcpy() e mostra isso [linha/tamanho] [linha] [ 1,[ 1] [] [ 2,[32] [sem tags. linha em branco acima] [ 3,[ 3] [__] [ 4,[ 3] [**] [ 5,[23] [__ tag subinhado vazia] [ 6,[23] [** tag asterisco vazia] [ 7,[28] [_a_ tag subinhado uma letra] [ 8,[28] [*b* tag asterisco uma letra] [ 9,[34] [A _linguagem_ C e muito poderosa!] [10,[43] [A linguagem *C* e mais rapida que *Python*] [11,[38] [_ _ __ _ yabba dabba _ * dooooo * ***] Lidas 11 linhas antes(....[teste] depois:...[te<tag>te] antes(....[teste] depois:...[<tag>este] antes(....[teste] depois:...[test<tag>] Eis o programa #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> // os testes int fase1(); int fase2(); // a funcao void replace(char* texto, int index, const char* tag); FILE* entrada; // o arquivo int total_linhas = 0; // conta as linhas int maximo_linha = 50; // max 50 letras char linha[51]; // linhas aqui int tamanho_linha; // tamanho da linha int main(int argc, char** argv) { fase1(); // so le o arquivo pra testar. E mostra as linhas fase2(); // testa replace return 0; } // end main() // // le o arquivo de entrada // mostra as linhas // mostra os tamanhos // int fase1() { entrada = fopen("entrada.txt", "r"); if (entrada == NULL) { perror("Deu esse erro"); // deu pau return 0; } // end if printf("[linha/tamanho] [linha]\n"); // com legenda :) while (!feof(entrada)) { total_linhas += 1; fgets(linha, 50, entrada); // le a linha n tamanho_linha = strlen(linha); linha[tamanho_linha - 1] = 0; // termina a string porque // e nao \0 e vamos mostrar na tela printf("[%2d,[%2d] [%s]\n", total_linhas, tamanho_linha, linha); // mostra } printf("\nLidas %d linhas\n", total_linhas); fclose(entrada); return 0; } // end fase1() int fase2() { char linha[200]; // testa a funcao replace // tenta trocar o s por <tag> // deve ficar te<tag>te char* teste = "teste"; strcpy(linha, teste); replace(linha, 2, "<tag>"); // testa no comeco strcpy(linha, teste); replace(linha, 0, "<tag>"); // testa no fim strcpy(linha, teste); replace(linha, 4, "<tag>"); return 0; } // end fase2() /* replace() substitui o caracter da posicao index em texto pela tag texto tem no maximo 50 tag tem 3 ou 4: <b> </b> <i> </i> */ void replace(char* texto, int index, const char* tag) { int i; int tam_texto = strlen(texto); int tam_tag = strlen(tag); char nova[128]; // tag no exemplo tem 3 ou 4 // copia texto para a nova, até a posicao index for (i = 0; i < index; i++) { nova[i] = texto[i]; } // agora copia a tag. i_tag aponta dentro da tag for ( int i_tag = 0; i_tag < tam_tag; i_tag++) { nova[i] = tag[i_tag]; i += 1; } // agora copia o resto de texto depois da tag // em texto[index] estava o caracter que vamos // trocar pela tag, entao copia de texto[index+1] ate o fim for (int j = index+1; j < tam_texto; j++) { nova[i] = texto[j]; // copia o resto i += 1; // avanca o ponteira em nova[] } nova[i] = 0; // termina com um zero a string nova // printf("antes(....[%s]\n", texto); printf("depois:...[%s]\n", nova); // agora copia de volta de nova[] para texto[] tam_texto = strlen(nova); // tamanho atualizado for (i = 0; i < tam_texto; i += 1) { texto[i] = nova[i]; } // um zero no final pra terminar o texto[] texto[tam_texto] = 0; // so isso return; } E tem um arquivo de entrada anexo, que você pode usar para testar com as condições mais comuns e as do enunciado, claro... Pode ajudar. Tem muitos comentários. Atente para a provável vantagem de escrever e testar aos poucos. Veja lá as funções fase1(), fase2()... entrada.txt
  15. @Gabriel Tellaroli Ramos O enunciado é bem ruim hein? Tem erros de concordância e escreve demais pra dizer pouco. E porque asterisco e sublinhado são atalhos e <b></b> e <i></i> são tags>? Quando tem uma letra é atalho? asterisco e sublinhado são tags... E já que é um simples exemplo porque não usar sublinhado para texto sublinhado e usar a tag <u></u>? Folclórico. Você escreveu a função replace() ao menos? Que fez até agora? Tem que entregar isso hoje, 14 mesmo?
  16. @Eduarda Menezes da Silveira Como @devair1010 escreveu, todo contato com um arquivo é feito através de uma estrutura FILE. E quando você tenta abrir o arquivo o sistema preenche a que você passou como parâmetro e a partir daí você usa o arquivo através do ponteiro Todo o contato com dois arquivos é então feito a partir de duas dessas estruturas, já que você precisa acessar os dois ao mesmo tempo Permissao Negada? Porque imprime isso? Não está claro que o open() fracassou por erro de permissão: pode ser que o arquivo não exista, ou o nome seja inválido, ou qualquer coisa... Em C você pode sempre chamar perror() quando deu erro e ter uma mensagem explicando o que aconteceu FILE* lista = fopen("arquivo.txt","r"); if(lista==NULL) { perror("Deu esse erro: "); } E se o arquivo não existe por exemplo mostra Deu esse erro:: No such file or directory "Entre com a string:"? Agora isso eu não entendi mesmo... No seu programa ou no que @devair1010 escreveu: não se trata de ler nada do teclado.Tudo que seu programa deve fazer é dizer se os dois arquivos são ou não são iguais. É o que está escrito lá: Você abre os dois arquivos e lê linha a linha, limitando a leitura a 20 caracteres por linha. E verifica se os arquivos são idênticos em termos dos primeiros 20 caracteres de cada linha. Só isso. Ex: Exercicio2.txt linha 1 linha 2 01234567890123456789 mais de vinte Exercicio2a.txt linha 1 linha 2 01234567890123456789 Eles são iguais porque até os 20 caracteres eles são idênticos....
  17. Agora está meio abstrato pra mim.... Podia explicar o que pretende fazer comentando seu próprio código. Mas agora tem o código de teste() também e imagino que queira imprimir a, 5x5 linha a linha. Vou insistir sobre o que falei de ler da direita para a esquerda. Veja aquele teste que te mostrei do programa que imprime 12345678 e o que escrevi e me diga se entende aquilo e tento explicar de outro modo se preciso. Em relação a esse código aqui: sua rotina teste() não retorna nada --- void --- e recebe um único argumento t, um ponteiro para int. Quando você chama teste() em seu programa usa teste(a) então seria razoável achar que a é do tipo int*. Só que não é: Declarou int a[5][5]; Pense nisso. Depois te mostro as alternativas.
  18. Em relação ao jogo em C talvez devesse abrir outro tópico, certo? Você vai precisar de alguma estrutura de dados para implementar o jogo e em c++ teria claro mais suporte. Mas se vai implementar o jogo em C e vai ter uma estrutura com o tabuleiro e outras para acompanhar o jogo e os tamanhos já estão definidos não precisa de alocação dinâmica. Como vai usar um tabuleiro, que é mais fácil de ver como uma estrutura 2D, então pode declarar tudo com tamanho fixo. Um vetor em C é um ponteiro de qualquer forma, então não sei ao certo o que quer evitar... Os asteriscos? adicionado 1 minuto depois O banco de dados já existe? testou com o próprio banco? O Qt está preparado para acessar esse banco? viu no script de configuração do Qt se o driver está habilitado?
  19. Microsoft Visual Studio?
  20. A resposta curta é sim. Mas o que é uma matriz? Como eu disse, você deve ler a declaração da direita para a esquerda. E como eu sugeri, em muitos casos ou se usa * ou se usa [] mas não os dois. Não que seja errado. Mas em código de produçào --- como código de frameworks, bibliotecas famosas e tal --- é mais comum ver apenas os asteriscos Na tela que mostrou está um protótipo, mas onde está o código de teste()?
  21. . Para n = 2 210012 Para n=20 2019181716151413121110987654321001234567891011121314151617181920 e assim por diante @MB_ talvez com mais esses exemplos ajude a entender. Espero que não esteja já muito longo o texto, mas entenda que seu exemplo não faz o que foi pedido. Não sei qual era sua ideia, mas espero que se leu até aqui isso ajude
  22. O enunciado está certinho, talvez pudesse melhorar a pontuação apenas O exemplo também e sua solução ... quase Basta tirar aquele else. Assim funcionaria: int recursividade(int n) { printf("%d", n); if(n>0) { recursividade(n - 1); } printf("%d", n); return n; } a pegadinha está na redação onde fala de "depois ir de 0 até n". Na verdade, na implementação mais simples, cada execução da função imprime um par de n e chama a função de novo para tratar a parte "interna"
  23. Olá Gabriel! Esse nome e essa declaração não foram provavelmente boa escolha. Mas pelo exemplo você quer envolver um único caracter por tags de abertura e fechamento como em linguagens de marcação, tipo XML ou HTML. Como por exemplo é comum usar <b></b> para negrito e <i></i> para itálico. Essas " tags" envolvem o argumento. O normal seria usar outra string como parâmetro mesmo, para trocar por exemplo rápida por <b>rápida</b> e devolver o endereço da string nova também, porque assim você poderia usar em expressões. Muitas das rotinas da biblioteca de manipulação de strings do C fazem isso, por uma boa razão. Algo assim: char* insere_tags( char* texto, const char* palavra, const char* tag); seria bem mais útil. E aqui entre nós uma rotina replace() que não troca de fato nada é algo estranho De volta ao problema: Dentro da rotina replace() - você já sabe onde está a letra porque é o parâmetro indice então - cria uma string nova pra montar a saída - copia a string original pra a string nova até a posição imediatamente anterior - copia a tag de abertura para a nova string - copia a letra de volta para a nova string - e copia o resto da string de entrada -retorna Dentro de main() seja ts o tamanho de texto, e tt o tamanho da tag então sua string em replace() vai crescer e ficar com (tt+ts) caracteres porque afinal você vai chamar replace() mas ela não vai de fato fazer um replace e sim inserir a tag. porque estou dizendo isso? porque você vai precisar saber o novo indice para o caracter depois de ter inserido a tag de abertura. Exemplo: char* texto = "A linguagem C e mais"; char* tag_abre = "<b>"; char* tag_fecha = "</b>"; int indice = 12; // posicao do C int tt = strlen(texto); int ts = strlen(tag_abre); Você vai chamar replace() replace(texto, indice, tag_abre); o texto aumentou em ts caracteres, que agora vem antes da letra que estava em indice, e a letra continua lá. Então você chama replace() de novo replace(texto, indice+ts, tag_fecha); E pode imprimir o texto com aletra circundada pelas tags corretas Só isso
  24. @Reberth Siqueira A classe que controla sua janela principal parece ser o lugar ideal pra hospedar uma instância da conexão com o banco de dados e assim você vai poder acessar de qualquer canto... Esse objeto --- classe em C++ afinal --- db declarado na janela que é parent de todas deve estar disponível em ... todas. E então você pode escrever por exemplo if(MainWindow.db.open()) { ... } ... em qualquer janela que tenha acesso a MainWwindow
  25. @matheuscrluiz Claro que tem muitas possíveis soluções, como a que usou e outras demonstradas aqui, mas como eu disse não é preciso usar nada disso Imagine o que faria você com um papel e caneta. Algo assim: Um programa de computador não poderia fazer igual e imprimir A cadeia [CALCULO] tem tamanho 7 e 5 letras unicas Sim. Podia escrever assim: #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> int main(int argc, char** argv) { char* teste_1 = "CALCULO"; char* teste_2 = "coisa coisa"; char* teste_3 = "Clube do Hardware"; char linha[80]; int tamanho = 0; int total = 0; //strncpy(linha, teste_3, 80); // so para poder testar com mais //strncpy(linha, teste_2, 80); // linhas trocando os comentarios strcpy(linha, teste_1, 80); // tamanho = strlen(linha); printf( "A cadeia [%s] tem tamanho %d e ", linha, tamanho); for (int i = 0; i < tamanho; i = i + 1) { char letra = linha[i]; if (letra != 0) { // uma letra original total = total + 1; // original linha[i] = 0; // apaga essa for (int j=i+1; j<tamanho; j = j + 1) { if (linha[j] == letra) linha[j] = 0; // apaga repetido } // end for (j) } } // end for(i) printf("%d letras unicas\n", total); return 0; } // end main() Como no papel, você pode marcar a cadeia na própria cadeia... Como eu disse, não precisa mais dela. O enunciado não diz se brancos são letras, então não precisa interpretar isso.

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

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!