Jump to content

Novo programa - ajuda typedef


PsySc0rpi0n
 Share

Recommended Posts

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 by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

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

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
Link to comment
Share on other sites

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 by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

#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;
}
  • Vote 1
IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

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

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
Link to comment
Share on other sites

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

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
Link to comment
Share on other sites

...

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

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
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.