PsySc0rpi0n Posted September 19, 2014 Report Share Posted September 19, 2014 (edited) Boas... Estou a tentar cirar um programa que lê um ficheiro de texto com palavras e selecciona 10 palavras aleatórias e as armazena numa variável para depois as imprimir na consola... Como poderei criar a variável que guarda as 10 palavras à medida que elas são seleccionadas do ficheiro??? Estava a tentar fazer usando o typedef assim: typedef struct palsel{ char pal0 [MAX_LEN]; char pal1 [MAX_LEN]; char pal2 [MAX_LEN]; char pal3 [MAX_LEN]; char pal4 [MAX_LEN]; char pal5 [MAX_LEN]; char pal6 [MAX_LEN]; char pal7 [MAX_LEN]; char pal8 [MAX_LEN]; char pal9 [MAX_LEN]; }listapal; Mas depois como faço para usar o contador de um for para preencher cada uma das 10 palavras? Posso fazer algo do tipo: listapal.pal[i] = palavra; Edited September 19, 2014 by PsySc0rpi0n Kurt Cobain - Grunge misses you Nissan GT-R - beast killer Link to comment Share on other sites More sharing options...
HappyHippyHippo Posted September 19, 2014 Report Share Posted September 19, 2014 #define N_WORDS 10 #define MAX_LEN 256 int index = 3; char words[N_WORDS][MAX_LEN]; strcpy(words[index], "batatas"); printf("word %d : %s\n", index, words[index]); IRC : sim, é algo que ainda existe >> #p@p Portugol Plus Link to comment Share on other sites More sharing options...
PsySc0rpi0n Posted September 19, 2014 Author Report Share Posted September 19, 2014 Pois, parece-me bem mais simples. Agora, no meu caso, como estou a ler um ficheiro que tem 1 palavra por linha, terei que ler todos os caracteres da linha seleccionada até encontrar o '\n' e ir copiando cada caractér para essa variável. É este o melhor método ou posso fazê-lo de uma forma mais eficiente? Kurt Cobain - Grunge misses you Nissan GT-R - beast killer Link to comment Share on other sites More sharing options...
HappyHippyHippo Posted September 19, 2014 Report Share Posted September 19, 2014 int i, count = 0, length; char words[N_WORDS][MAX_LEN]; FILE* fd = NULL; fd = fopen("file.txt", "r"); // <--- add error check while (count < N_WORDS && fgets(words[count], MAX_LEN, fd)) { length = strlen(words[count]); if (words[count][length - 1] == '\n') words[count][length - 1] = '\0'; ++count; } fclose(fd); for (i = 0; i < count; ++i) { printf("word %i : %s\n", i, words[i]); } IRC : sim, é algo que ainda existe >> #p@p Portugol Plus Link to comment Share on other sites More sharing options...
PsySc0rpi0n Posted September 19, 2014 Author Report Share Posted September 19, 2014 (edited) O fgets devolve a string, certo? Não percebi como incluiste o fgets na condição do while! Edied; Eu vou explicar melhor o que queria fazer. 1 - Ler um file txt com alguns milhares de palavras (uma palavra por linha). 2 - Seleccionar uma linha esse ficheiro aleatoriamente 3 - Ler a palavra que se encontra nessa linha 4 - Copiar essa palavra para uma variável na memória 5 - Repetir os passos 2, 3 e 4 10 vezes e gravar as 10 palavras seleccionadas na variável. 6 - Apresentar na consola as palavras seleccionadas. Para já não me vou preocupar em evitar palavras repetidas, mais para a frente trato disso. O que eu fiz foi: 1 - Percorrer o ficheiro e contar as linhas /*Contar as linhas do ficheiro*/ 25 while ((c = fgetc(fp)) != EOF){ 26 if (c == '\n') 27 linenum++; 28 } Se calhar podia-o fazer com o fgets, mas para já está assim. 2 - Gerar um número aleatório 10 vezes e garantir que é menor que o número de linhas. 2.a - Se for menor que o número de linhas, ler a palavra que se encontra nessa linha e copiá-la para a variável que as vai armazenar a todas srand((unsigned) time(&t)); for (i = 0; i < n; i++){ do{ *(numlinelist + i) = rand (); if (*(numlinelist + i) <= linenum){ le_palavra(*(numlinelist + i), fp, n); } } while (*(numlinelist + i) > linenum); } 3 - Imprimir na consola a variável com as 10 palavras escolhidas aleatoriamente! Agora o problema está na função para ler a palavra da linha seleccionada! Mas estou a tnetar fazer! Edited September 19, 2014 by PsySc0rpi0n Kurt Cobain - Grunge misses you Nissan GT-R - beast killer Link to comment Share on other sites More sharing options...
HappyHippyHippo Posted September 19, 2014 Report Share Posted September 19, 2014 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define BUFFER_SIZE 256 #define REALLOC_INCREMENT 4 #define RANDOM_COUNT 10 char** alloc_word_list(unsigned int count) { char** words; unsigned int i, del; // argument check if (count == 0) return NULL; // allocate the word list memory if ((words = malloc(sizeof(char*) * count)) == NULL) return NULL; // allocate the word list string buffers for (i = 0; i < count; ++i) { if ((words[i] = malloc(sizeof(char) * BUFFER_SIZE)) == NULL) { // free previously/already allocated memory for (del = 0; del < i; ++del) free(words[del]); return NULL; } } return words; } void free_word_list(char*** words, unsigned int count) { int i; char** aux = *words; // argument check if (words == NULL || *words == NULL || count == 0) return; // free list allocated memory for (i = 0; i < count; ++i) free(aux[i]); free(aux); *words = NULL; } long int* get_words_indexes_from_file(FILE* fd, unsigned int* count) { long int* indexes = NULL, *aux = NULL, pos = 0; int indexes_size = 0, ok = 1; char buffer[bUFFER_SIZE]; // argument check if (fd == NULL || count == NULL) return NULL; // file parsing cycle fseek(fd, 0, SEEK_SET); *count = 0; while (ok) { // indexes list size check/resize if (*count == indexes_size) { // check if the first allocation if (indexes == NULL) { if ((aux = malloc(sizeof(long int) * REALLOC_INCREMENT)) == NULL) return NULL; } else { // reallocate the previously allocated memory if ((aux = realloc(indexes, sizeof(long int) * (indexes_size + REALLOC_INCREMENT))) == NULL) { free(indexes); return NULL; } } // store the list information indexes = aux; indexes_size += REALLOC_INCREMENT; } // store the word position in the file and advance to the next one indexes[(*count)++] = pos; if ((ok = fgets(buffer, BUFFER_SIZE, fd) != NULL) != 0) pos += strlen(buffer); } return indexes; } unsigned int* select_n_randoms(unsigned int count, unsigned int max) { unsigned int* list, *result = NULL; unsigned int i = 0, random = 0, swap = 0; // argument check if (count == 0 || max < count) return NULL; // allocate memory to the number selection array if ((list = malloc(sizeof(unsigned int) * max)) == NULL) return NULL; // fill the number selection array for (i = 0; i < max; ++i) list[i] = i; // randomize the array elements srand(time(NULL)); for (i = 0; i < max; ++i) { // select a random ordered value random = rand() % (max - i); // swap the ordered value to the unordered portion of the list swap = list[random]; list[random] = list[max - i - 1]; list[max - i - 1] = swap; } // create the function returning list if ((result = malloc(sizeof(unsigned int) * count)) == NULL) { free(list); return NULL; } // copy the first N element to the resulting list memcpy(result, list, sizeof(unsigned int) * count); // free the number selection array memory previously allocated free(list); return result; } char** get_n_random_words_from_file(char* file, unsigned int count) { FILE* fd = NULL; long int* indexes = NULL; unsigned int* random = NULL; unsigned int indexes_count = 0, i = 0, del = 0, length = 0; char** words = NULL; // argument check if (file == NULL || count <= 0) return NULL; // open the file stream if ((fd = fopen(file, "r")) == NULL) { perror("fopen"); exit(-2); } // retrieve the words indexes, the quantity of indexes and // a "count" number of random indexes to be retrieved if ((indexes = get_words_indexes_from_file(fd, &indexes_count)) == NULL) { fclose(fd); return NULL; } if ((random = select_n_randoms(count, indexes_count)) == NULL) { fclose(fd); free(indexes); return NULL; } // allocate the words list if ((words = alloc_word_list(count)) == NULL) { fclose(fd); free(random); free(indexes); return NULL; } // populate the words list for (i = 0; i < count; ++i) { // seek for the position in the file for the selected random word fseek(fd, indexes[random[i]], SEEK_SET); // copy the word from the file into the iterated word list element fgets(words[i], BUFFER_SIZE, fd); // remove the '\n' readed by the fgets length = strlen(words[i]); if (words[i][length - 1] == '\n') words[i][length - 1] = '\0'; } // close the file stream fclose(fd); // free the indexes and random arrays free(random); free(indexes); return words; } int main(int argc, char ** argv) { char** words; unsigned int count = RANDOM_COUNT, i; // check application arguments if (argc < 2) { fprintf(stderr, "command: wordselect <file>\n"); exit(-1); } // retrieve RANDOM_COUNT random words from the file words = get_n_random_words_from_file(argv[1], count); for (i = 0; i < count; ++i) printf("random word %d : %s\n", i, words[i]); // release the words list memory free_word_list(&words, count); return 0; } 1 Report IRC : sim, é algo que ainda existe >> #p@p Portugol Plus Link to comment Share on other sites More sharing options...
PsySc0rpi0n Posted September 19, 2014 Author Report Share Posted September 19, 2014 Só me dá vontade de rir e já perdi a vontade!!! 😄 Kurt Cobain - Grunge misses you Nissan GT-R - beast killer Link to comment Share on other sites More sharing options...
HappyHippyHippo Posted September 19, 2014 Report Share Posted September 19, 2014 Só me dá vontade de rir e já perdi a vontade!!! 😄 como dizem os brasileiros : - oi ? IRC : sim, é algo que ainda existe >> #p@p Portugol Plus Link to comment Share on other sites More sharing options...
PsySc0rpi0n Posted September 23, 2014 Author Report Share Posted September 23, 2014 como dizem os brasileiros : - oi ? Porque fizeste isso tudo assim de repente e nem me chegaste a dar a oportunidade de tentar fazer as coisas por partes. E depois reparei que tkavez fosse areia a mais para a minha camionete e para o tempo que tenho. Por isso perdi a vontade só ao ver o teu code. Mas obviamente agradeço a tua ajuda e até gostava de perder um bocado de tempo a tentar entender o teu code. Se quiseres editar o teu post e colocar comentários mais intuitivos, agradecia. É que alguns termos não me estão a ajudar a entender o comentário! Thanks Psy Kurt Cobain - Grunge misses you Nissan GT-R - beast killer Link to comment Share on other sites More sharing options...
HappyHippyHippo Posted September 23, 2014 Report Share Posted September 23, 2014 Porque fizeste isso tudo assim de repente e nem me chegaste a dar a oportunidade de tentar fazer as coisas por partes. não te dei oportunidade ? estás na tua liberdade de fazer o exercício como bem entenderes ... eu não impedi absolutamente nada olha que em programação o ditado "todas as ruas vão dar a Roma" tem um significado redobrado E depois reparei que tkavez fosse areia a mais para a minha camionete e para o tempo que tenho. Por isso perdi a vontade só ao ver o teu code. se era areia a mais, a única coisa que deverias fazer era perguntar pelas secções que não percebestes (mesmo tendo comentários em tudo que é sítio) Se quiseres editar o teu post e colocar comentários mais intuitivos, agradecia. É que alguns termos não me estão a ajudar a entender o comentário! os comentário já são bastantes e esclarecedores, e por isso não vou adicionar mais. mas se mesmo assim existe alguma coisa que não percebes, estás à vontade de questionar tanto a mim como o fórum ... IRC : sim, é algo que ainda existe >> #p@p Portugol Plus Link to comment Share on other sites More sharing options...
PsySc0rpi0n Posted September 23, 2014 Author Report Share Posted September 23, 2014 Ok, eu vou copiar para aqui as funções separadamente para ir fazedo as perguntas. Eu não quis dizer que me impediste de fazer o programa por mim e sei que há várias maneiras de fazer "a coisa" mas ao ver tudo feito, acabei por achar que se calhar era complicado demais para mim. Eu agradeço o que fizeste e os comentários que colocaste no code mas na verdade dou-me muito mal em contextualizar o termo "indexes" na generalidade, ou seja, não consigo perceber muito bem o que significa e como enquadrar no contexto. Adiante. Em primeiro lugar gostava de perceber qual foi a tua abordagem ao fazeres/pensares a forma de construíres o programa e para tal gostava que explicasses resumidamente qual a "função" de cada uma das funções que criaste! char** alloc_word_list(unsigned int count); void free_word_list(char*** words, unsigned int count); long int* get_words_indexes_from_file(FILE* fd, unsigned int* count); unsigned int* select_n_randoms(unsigned int count, unsigned int max); char** get_n_random_words_from_file(char* file, unsigned int count); Na altura que eu comecei, a minha abordagem foi: Ler o ficheiro e contar as linhas Gerar números aleatórios menores que o número de linhas e cada vez que esse número era gerado, percorria o ficheiro até essa linha e copiava a palavra para uma variável que ia poder guardar até 10 palavras. Imprimir na consola essa variável com as 10 palavras aleatórias... Mas a tua abordagem foi bem diferente, claro e gostava de a perceber para depois olhar para as funções e poder identificar determinado passo naquela função. É que todas as funções recebem vários parâmetros e eu acabo por me perder! Kurt Cobain - Grunge misses you Nissan GT-R - beast killer Link to comment Share on other sites More sharing options...
HappyHippyHippo Posted September 23, 2014 Report Share Posted September 23, 2014 o ponto no meu código que mais diverge da tua solução é algo que tenta combater este problema : (na tua solução) se pretenderes obter a palavra na linha N, terás de reler parcialmente o ficheiro (N-1 linhas) até encontrares a linha que pretendes isto leva muito tempo porque estás a ler um ficheiro e não algo que deverá estar em memória. para não estar sempre a ler o ficheiro, linha a linha, sempre que pretendo uma palavra, o que fiz foi guardar as posições (byte/índice) de cada palavra existente no ficheiro. é isso que a função get_words_indexes_from_file faz. resumidamente, o que o meu código faz é : - verifica se o nome do ficheiro a ser abreto foi dado como argumento da aplicação if (argc < 2) - abre o ficheiro pretendido if ((fd = fopen(file, "r")) == NULL) { - lêr todas as linhas do ficheiro aberto obtendo a sua posição (byte/índice) while (ok) { // ... if ((ok = fgets(buffer, BUFFER_SIZE, fd) != NULL) != 0) pos += strlen(buffer); } - verifica se tem espaço para guardar o posição da palavra lida do ficheiro if (*count == indexes_size) - caso não tenha esse espaço, reserva ou redimensiona o array usado para guardar as posições das palavras if ((aux = malloc(sizeof(long int) * REALLOC_INCREMENT)) == NULL) // ... if ((aux = realloc(indexes, sizeof(long int) * (indexes_size + REALLOC_INCREMENT))) == NULL) { - guarda a posição da palavra no array de índices/posições das palavras indexes[(*count)++] = pos; - obtenho no final o número de palavras no ficheiro assim como as suas posições long int* get_words_indexes_from_file(FILE* fd, unsigned int* count) { // <--- count = número de palavras // ... return indexes; } - tento obter M números aleatórios entre 0 e o número de palavras do ficheiro (N) if ((random = select_n_randoms(count, indexes_count)) == NULL) - para isso crio um array com os números de 0 a N if ((list = malloc(sizeof(unsigned int) * max)) == NULL) // ... for (i = 0; i < max; ++i) list[i] = i; - baralho o array : http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle srand(time(NULL)); for (i = 0; i < max; ++i) { random = rand() % (max - i); // swap the ordered value to the unordered portion of the list // ... } - obtenho os meus M números aleatórios ao guardar os M primeiros números do array baralhado memcpy(result, list, sizeof(unsigned int) * count); - crio uma lista de buffers com tamanho de M para guardar as minhas M palavras aleatórias if ((words = alloc_word_list(count)) == NULL) { - para cada número aleatório obtido for (i = 0; i < count; ++i) { , pesquiso na lista de índices/posições das palavras pela posição da palavra pretendida e avanço para essa posição do ficheiro fseek(fd, indexes[random[i]], SEEK_SET); - lei o ficheiro guardando a palavra na lista de buffers previamente criada fgets(words[i], BUFFER_SIZE, fd); - e por fim apresento as palavras for (i = 0; i < count; ++i) printf("random word %d : %s\n", i, words[i]); -------------------------------------------- espero que desta forma fique claro o que o código faz IRC : sim, é algo que ainda existe >> #p@p Portugol Plus Link to comment Share on other sites More sharing options...
PsySc0rpi0n Posted September 23, 2014 Author Report Share Posted September 23, 2014 ... para não estar sempre a ler o ficheiro, linha a linha, sempre que pretendo uma palavra, o que fiz foi guardar as posições (byte/índice) de cada palavra existente no ficheiro. é isso que a função get_words_indexes_from_file faz. Se percebi o que explicaste, significa em linguagem de "pedreiro" que criaste uma array com tantas posições quantas as linhas que o ficheiro tem, certo? resumidamente, o que o meu código faz é : - verifica se o nome do ficheiro a ser abreto foi dado como argumento da aplicação if (argc < 2) - abre o ficheiro pretendido if ((fd = fopen(file, "r")) == NULL) { - lêr todas as linhas do ficheiro aberto obtendo a sua posição (byte/índice) while (ok) { // ... if ((ok = fgets(buffer, BUFFER_SIZE, fd) != NULL) != 0) pos += strlen(buffer); } Nesta secção, não sei se entendi o que queres dizer com "obtendo a sua posição/byte". Kurt Cobain - Grunge misses you Nissan GT-R - beast killer Link to comment Share on other sites More sharing options...
HappyHippyHippo Posted September 23, 2014 Report Share Posted September 23, 2014 Se percebi o que explicaste, significa em linguagem de "pedreiro" que criaste uma array com tantas posições quantas as linhas que o ficheiro tem, certo? mais ou menos isso. não é exactamente com o tamanho igual ao número de linhas do ficheiro. será igual ou superior a esse número devido ao método de reallocação do array ser incremental de um número diferente de 1 (neste caso é de REALLOC_INCREMENT) no final, em cada uma das posições terá a posição da palavras com esse índice: - primeira palavra está na posição do ficheiro guardada em array[0] - segunda palavra está na posição do ficheiro guardada em array[1] - terceira palavra está na posição do ficheiro guardada em array[2] ... Nesta secção, não sei se entendi o que queres dizer com "obtendo a sua posição/byte". eu obtenho a posição da seguinte palavra ao incrementar o valor da variável pos o número de bytes lidos anteriormente que equivale ao tamanho da string guardada no variável buffer IRC : sim, é algo que ainda existe >> #p@p Portugol Plus Link to comment Share on other sites More sharing options...
PsySc0rpi0n Posted September 23, 2014 Author Report Share Posted September 23, 2014 (edited) Mas o que fica em array[0], array[1], etc, são as palavras da linha zero e linha 1 e por aí fora do ficheiro? Ou seja: array[0] = "andar", array[1] = "andarei", por exemplo? Edited September 23, 2014 by PsySc0rpi0n Kurt Cobain - Grunge misses you Nissan GT-R - beast killer Link to comment Share on other sites More sharing options...
HappyHippyHippo Posted September 23, 2014 Report Share Posted September 23, 2014 - guarda a posição da palavra no array de índices/posições das palavras indexes[(*count)++] = pos; IRC : sim, é algo que ainda existe >> #p@p Portugol Plus Link to comment Share on other sites More sharing options...
PsySc0rpi0n Posted September 24, 2014 Author Report Share Posted September 24, 2014 Sim, mas o que é que fica em array[0], array[1]?? São as palavras em si ou é o número da linha em que a palavra está? Kurt Cobain - Grunge misses you Nissan GT-R - beast killer Link to comment Share on other sites More sharing options...
HappyHippyHippo Posted September 24, 2014 Report Share Posted September 24, 2014 nem uma nem outra ... o que o arrau indexes guarda é a posição no ficheiro. IRC : sim, é algo que ainda existe >> #p@p Portugol Plus Link to comment Share on other sites More sharing options...
PsySc0rpi0n Posted September 24, 2014 Author Report Share Posted September 24, 2014 Ok, mas essa posição no ficheiro não é um número nem nada? Kurt Cobain - Grunge misses you Nissan GT-R - beast killer Link to comment Share on other sites More sharing options...
HappyHippyHippo Posted September 24, 2014 Report Share Posted September 24, 2014 Ok, mas essa posição no ficheiro não é um número nem nada? - guarda a posição da palavra no array de índices/posições das palavras indexes[(*count)++] = pos; IRC : sim, é algo que ainda existe >> #p@p Portugol Plus Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now