Использование динамического выделения памяти для массивов

Как я должен использовать динамическое выделение памяти для массивов?

например, вот следующий массив, в котором я читаю отдельные слова из a .txt файл и сохранить их слово за словом в массиве:

код:

char words[1000][15];

здесь 1000 определяет количество слов, которые массив может сохранить, и каждое слово может содержать не более 15 символов.

теперь я хочу, чтобы эта программа динамически выделяла память для количества слов это считается. Например,.txt-файл может содержать слова больше 1000. Теперь я хочу, чтобы программа подсчитала количество слов и выделила память соответственно.

поскольку мы не можем использовать переменную вместо [1000], я полностью пуст в том, как реализовать мою логику. Пожалуйста, помогите мне в этом.

8 ответов


вы используете указатели.

в частности, вы используете указатель на адрес и, используя стандартные вызовы функций библиотеки c, вы просите операционную систему развернуть кучу, чтобы позволить вам хранить то, что вам нужно.

теперь он может отказаться, что вам нужно будет обработать.

следующий вопрос становится - как вы спрашиваете 2D-массив? Ну, вы просите массив указателей, а затем расширяете каждый указатель.

в качестве примера рассмотрим это:

int i = 0;
char** words;
words = malloc((num_words)*sizeof(char*));

if ( words == NULL )
{
    /* we have a problem */
    printf("Error: out of memory.\n");
    return;
}

for ( i=0; i<num_words; i++ )
{
    words[i] = malloc((word_size+1)*sizeof(char));
    if ( words[i] == NULL )
    {
        /* problem */
        break;
    }
}

if ( i != num_words )
{
    /* it didn't allocate */
}

это дает вам двумерный массив, где каждый элемент words[i] может иметь другой размер, определяемый во время выполнения, так же, как и количество слов.

вам понадобится free() вся результирующая память, зацикливаясь на массиве, когда вы закончите с ним:

for ( i = 0; i < num_words; i++ )
{
    free(words[i]);
}

free(words);

если вы этого не сделаете, вы создадите утечку памяти.

вы также можете использовать calloc. Разница в том, чтобы вызвать условность и эффект -calloc инициализирует всю память в 0, тогда как malloc нет.

Если вам нужно изменить размер во время выполнения, используйте realloc.


кроме того, важно, следите за word_size+1 что я использовал. Строки в C имеют нулевое завершение, и это требует дополнительного характер, который вам нужно учитывать. Чтобы убедиться, что я помню это, я обычно устанавливаю размер переменной word_size независимо от размера слова (длина строки, как я ожидаю) и явно оставьте +1 в malloc для нуля. Тогда я знаю, что выделенный буфер может принимать строку word_size символы. Не делать этого тоже хорошо - я просто делаю это, потому что мне нравится явно учитывать ноль очевидным образом.

есть и обратная сторона этот подход - я явно видел это как отправленную ошибку в последнее время. Заметьте, я написал (word_size+1)*sizeof(type) - представьте себе, однако, что я написал word_size*sizeof(type)+1. Для sizeof(type)=1 это то же самое, но Windows использует wchar_t очень часто - и в этом случае вы зарезервируете один байт для последнего нуля, а не два - и они являются нулевыми элементами типа type, не одиночные нулевые байты. Это означает, что вы будете перегружены чтением и письмом.  

добавление: сделайте это любым способом например, просто следите за этими нулевыми Терминаторами, если вы собираетесь передать буфер тому, кто полагается на них.


пока Ninefingers предусмотренного ответ с использованием массива указателей , вы также можете использовать массив массивов, если размер внутреннего массива является постоянным выражением. Код для этого проще.

char (*words)[15]; // 'words' is pointer to char[15]
words = malloc (num_words * sizeof(char[15]);

// to access character i of word w
words[w][i];

free(words);

Если вы собираетесь перейти на C++, STL очень полезен для чего-то динамического распределения и очень прост. Вы можете использовать std:: vector ..


если 15 в вашем примере переменная, используйте один из доступных ответов (от Девятипалого или Джона Бокера или Muggen). Если 1000 - это переменная, используйте realloc:

words = malloc(1000 * sizeof(char*));
// ... read 1000 words
if (++num_words > 1000)
{
    char** more_words = realloc(words, 2000 * sizeof(char*));
    if (more_words) {printf("Too bad");}
    else {words = more_words;}
}

в моем коде выше, константа 2000 является упрощением; вы должны добавить другую переменную capacity для поддержки более 2000 слов:

if (++num_words > capacity)
{
    // ... realloc
    ++capacity; // will reallocate 1000+ words each time; will be very slow
    // capacity += 1000; // less reallocations, some memory wasted
    // capacity *= 2; // less reallocations but more memory wasted
}

Если вы работаете в C:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define WORD_LEN 15

int resizeArray(char (**wordList)[WORD_LEN], size_t *currentSize, size_t extent)
{
  int result = 1;
  char (*tmp)[WORD_LEN] = realloc(*wordList, 
                                 (*currentSize + extent) * sizeof **wordList);
  if (tmp)
  {
    *currentSize += extent;
    *wordList = tmp;
  }
  else
    result = 0;

  return result;
}

int main(void)
{
  char *data[] = {"This", "is", "a", "test", 
                  "of", "the", "Emergency", 
                  "Broadcast", "System", NULL};
  size_t i = 0, j;
  char (*words)[WORD_LEN] = NULL;
  size_t currentSize = 0;

  for (i = 0; data[i] != NULL; i++)
  {
    if (currentSize <= i)
    {
      if (!resizeArray(&words, &currentSize, 5))
      {
        fprintf(stderr, "Could not resize words\n");
        break;
      }
    }
    strcpy(words[i], data[i]);
  }

  printf("current array size: %lu\n", (unsigned long) currentSize);
  printf("copied %lu words\n", (unsigned long) i);

  for (j = 0; j < i; j++)
  {
    printf("wordlist[%lu] = \"%s\"\n", (unsigned long) j, words[j]);
  }

  free(words);

  return 0;
}

вот немного информации о динамическом распределении 2d массивов:

http://www.eskimo.com / ~scs/cclass/int/sx9b.html


char ** words = malloc( 1000 * sizeof(char *));
int i;
for( i = 0 ; i < 1000 ; i++)
     *(words+i) = malloc(sizeof(char) * 15);

//....
for( i = 0 ; i < 1000 ; i++)
     free(*(words+i));

free(words);

в современном C (C99) у вас есть дополнительный выбор, массивы переменной длины, VLA, такие как:

char myWord[N];

в принципе вы также можете сделать такую вещь в двух измерениях, но если ваши размеры становятся слишком большими, Вы можете рискнуть переполнение стека. В вашем случае проще всего будет использовать указатель на такой массив и использовать malloc / realloc чтобы изменить их размер:

typedef char Word[wordlen];
size_t m = 100000;

Word* words = malloc(m * sizeof(Word));
/* initialize words[0]... words[m-1] here */
for (size_t i = 0; i < m; ++i) words[i][0] = '';

/* array is too small? */
m *= 2;
void *p = realloc(words, m*sizeof(Word));
if (p) words = p;
else {
 /* error handling */
}
.
free(words);

этот код должен работать (по модулю опечатки), если wordlen является константой или переменной, до тех пор, пока вы держите все внутри одной функции. Если вы хотите поместить его в функцию, вы должны объявить функцию что-то вроде

void myWordFunc(size_t wordlen, size_t m, char words[m][wordlen]);

то есть параметры длины должны быть сначала известны для объявления words.