Прочитать текстовый файл в массив в простом C - PullRequest
2 голосов
/ 27 декабря 2011

Есть ли способ прочитать текстовый файл в одномерный массив в простой C? Вот что я попробовал (пишу палач):

int main() {
    printf("Welcome to hangman!");

    char buffer[81];
    FILE *dictionary;
    int random_num;
    int i;
    char word_array[80368];

    srand ( time(NULL) );

    random_num = rand() % 80368 + 1;
    dictionary = fopen("dictionary.txt", "r");

    while (fgets(buffer, 80, dictionary) != NULL){
        printf(buffer); //just to make sure the code worked;
        for (i = 1; i < 80368; i++) {
            word_array[i] = *buffer;
        }
    }

    printf("%s, \n", word_array[random_num]);
    return 0;
}

Что здесь не так?

Ответы [ 2 ]

3 голосов
/ 27 декабря 2011

Попробуйте изменить пару вещей;

Сначала;вы храните один символword_array[i] = *buffer; означает копирование одного символа (первого в строке / в буфере) в каждый (и каждый) слот с одним символом в word_array.

Во-вторых, ваш массив будет содержать 80К символов, а не 80К слов.Предполагая, что это длина вашего файла словаря, вы не можете уместить все это, используя этот цикл.

Я предполагаю, что у вас есть 80 368 слов в файле словаря.Это примерно на 400 000 слов меньше, чем /usr/share/dict/words на моей рабочей станции, но звучит как разумный размер для палача…

Если вы намеренно по какой-то причине захотите одномерный массив, вынужно сделать одно из трех:

  • представьте, что вы находитесь на мэйнфрейме, и используйте 80 символов для каждого слова:

      char word_array[80368 * 80];
    
    memcpy (&(word_array[80 * i]), buffer, 80);
    
  • создать параллельный массив с индексами для начала каждой строки в огромном буфере

       int last_char = 0;
       char* word_start[80368];
       char word_array[80368 * 80];
       for ( … i++ ) {
           memcpy (&word_array[last_char], buffer, strlen(buffer));
           word_start[i] = last_char;
           last_char += strlen(buffer);
       }
    
  • переключиться на использование массива указателей на символ, одно слово на слот.

      char* word_array[80368];
    
      for (int i = 0; i < 80368, i++) {
           fgets (buffer, 80, dictionary);
           word_array[i] = strdup (buffer);
      }
    

Я бы порекомендовал последнее, так как в противном случае вам придется угадывать максимальный размер или тратить много ОЗУ во время чтения.(Если ваша средняя длина слова составляет около 4-5 символов, как в английском, вы в среднем тратите 75 байт на слово.)

Я бы также рекомендовал динамически распределять слово_арра:

   int max_word = 80368;
   char** word_array = malloc (max_word * sizeof (char*));

… который может привести вас к более безопасному чтению, если размер словаря изменится:

   int i = 0;
   while (1) {
        /* If we've exceeded the preset word list size, increase it. */
        if ( i > max_word ) {
            max_word *= 1.2; /* tunable arbitrary value */
            word_array = realloc (word_array, max_word * sizeof(char*));
        }
        /* Try to read a line, and… */
        char* e = fgets (buffer, 80, dictionary);
        if (NULL == e) { /* end of file */
            /* free any unused space */
            word_array = realloc (word_array, i * sizeof(char*));
            /* exit the otherwise-infinite loop */
            break;
        } else {
            /* remove any \r and/or \n end-of-line chars */
            for (char *s = &(buffer[0]); s < &(buffer[80]); ++s) {
               if ('\r' == *s || '\n' == *s || '\0' == *s) {
                  *s = '\0'; break;
               }
            }
            /* store a copy of the word, only, and increment the counter.
             * Note that `strdup` will only copy up to the end-of-string \0,
             * so you will only allocate enough memory for actual word
             * lengths, terminal \0's, and the array of pointers itself. */
            *(word_array + i++) = strdup (buffer);
        }
    }
    /* when we reach here, word_array is guaranteed to be the right size */
    random = rand () % max_word;
    printf ("random word #%d: %s\n", random, *(word_array + random));

Извините, это опубликовано в спешке, поэтому я не проверял выше.Будьте бдительны.

3 голосов
/ 27 декабря 2011

Эта часть неверна:

while (fgets(buffer, 80, dictionary) != NULL){
    printf(buffer); //just to make sure the code worked;
    for (i = 1; i < 80368; i++) {
        word_array[i] = *buffer;
    }
}

Вы копируете 80368 символов из buffer размером 81. Измените его на:

i = 0;
while (fgets(buffer, 80, dictionary) != NULL){
    printf(buffer); //just to make sure the code worked;
    for (j = 0; j < 80; j++) {
        word_array[i++] = buffer[j];
    }
}
...