Вы используете указатели.
В частности, вы используете указатель на адрес, и, используя стандартные вызовы функций библиотеки 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
, а не один ноль байтов. Это означает, что вы переполните чтение и запись.
Приложение: делайте это так, как вам нравится, просто следите за этими нулевыми терминаторами, если вы собираетесь передать буфер чему-то, что зависит от них.