Что не так с тем, как я динамически распределяю пространство для этого 2d массива? - PullRequest
0 голосов
/ 15 февраля 2020

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

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

Это то, что я до сих пор делал для mallo c it. (это было скопировано с GeeksForGeeks)

char *arr[rownum2];

for (i = 0; i < rownum2; i++) {
    arr[i] = (char *)malloc(colnum * sizeof(char));

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

Могу ли я получить наиболее подходящий способ динамического выделения памяти для двумерного массива в этом конкретном c сценарии?

Ответы [ 3 ]

1 голос
/ 15 февраля 2020

Код, который вы опубликовали, - «ОК», если вы помните, чтобы вызывать free() в выделенной памяти, а затем в своем коде, например:

for (i=0;i<rownum2;i++) free(arr[i]);

.. И мне также сказали, что некоторые части этого не нужны.

Явное приведение не нужно , поэтому вместо:

arr[i] =  (char *)malloc(colnum*sizeof(char));

просто используйте:

arr[i] =  malloc(colnum*sizeof(char));

Строго говоря, sizeof(char) также не нужен (char всегда будет иметь размер 1), но вы можете оставить это для ясности.

0 голосов
/ 16 февраля 2020

Единственная серьезная проблема, которую я вижу в вашем коде, заключается в том, что вы приводите возвращаемое значение malloc(3), и, вероятно, вы забыли также #include <stdlib.h> (это опасный коктейль), и таким образом вы уничтожаете возвращаемое значение вызова с приведенным вами актом до malloc(3). Позвольте мне объяснить:

  • Во-первых, у вас есть (или нет, но я должен догадаться) 64-битная архитектура (как это принято сегодня), а указатели имеют ширину 64 бит в вашей системе, тогда как int целые числа 32-битные.
  • Вы, вероятно, забыли #include <stdlib.h> в своем коде (что я тоже должен догадаться), поэтому компилятор предполагает, что malloc(3) на самом деле функция, возвращающая int (это унаследовано в C, если вы не предоставите прототип для функции, внешней по отношению к модулю компиляции), поэтому компилятор генерирует код, чтобы получить только 32-битное значение из функции malloc(3), и не 64-битный указатель, который (вероятно, но я должен также догадываться) malloc(3) на самом деле возвращает.
  • Вы приводите это int 32-битное значение (уже неверное) к 64-битному указателю (гораздо более неправильный, но Я должен догадаться ...), делая любое предупреждение о преобразованиях типов между целочисленными значениями и указателями, чтобы исчезнуть, и замолчать, когда вы ставите приведение (компилятор предполагает, что в качестве мудрой программы Более того, вы специально поставили приведение и знаете, что делаете)
  • Первое (неопределенное поведение) возвращаемое значение (неопределенное поведение) просто сокращается до 32 бит, а затем преобразован (от int до char *, с более неопределенным поведением) для использования в вашем коде. Это делает исходный указатель, возвращаемый из malloc(3), совершенно другим значением при повторной интерпретации и приведении к (char *). Это заставляет ваши указатели указывать на другое место и прерывать выполнение вашей программы.

Ваш код должен быть примерно таким (опять же, должен использоваться фрагмент, так как ваш код не завершен) :

#include <stdlib.h> /* for malloc() */

/* ... */

char *arr[rownum2];

for (i = 0; i < rownum2; i++) {
    arr[i] = malloc(colnum); /* sizeof(char) is always 1 */

Мне, наконец, нужно дать вам рекомендацию:

Пожалуйста, прочитайте (и следуйте) , как создать минимальную, проверяемую страницу примера , как Ваша вероятная ошибка #include - это то, о чем я должен был догадаться .... Публикация фрагментов кода много раз делает ваши ошибки на go, и мы должны угадать, что здесь может происходить. Это самая важная вещь, которую вы должны извлечь из этого ответа. Размещать полный, компилируемый и проверяемый код (т. Е. Код, который вы можете проверить, перед отправкой не проходит, а не фрагмент, который вы выбрали, где вы предполагаете проблема может быть). Размещенный вами код не позволяет никому проверить причину сбоя, потому что он должен быть завершен (и, вероятно, исправлен), чтобы сделать его исполняемым.

0 голосов
/ 15 февраля 2020

Технически это не двумерный массив, а массив массивов. Разница в том, что вы не можете создать 2D-массив со строками разного размера, но вы можете сделать это с вашим массивом массивов.

Если вам это не нужно, вы можете выделить rownum2*colnum элементов и получить доступ к каждому элементу как arr[x+colnum*y] (он часто используется, потому что все данные хранятся в одном месте, что уменьшает нагрузку на кэш ЦП и некоторые внутренние потребности системы в хранении каждого указателя каждого выделенного фрагмента).

Кроме того, даже массив линии разных размеров могут быть помещены в массив 1D и доступны как 2D (по крайней мере, если они не меняют размер или даже RO). Вы можете выделить char body[total_size], прочитать весь массив, выделить char* arr[rownum2] и установить каждую arr[i]=body+line_beginning_offset.

Кстати, не забывайте, что нет фактических C строк, потому что они не заканчиваются нулем. Вам понадобится дополнительный столбец для нулевого термина. Если вы храните ASCII art, 2D-массив - очень хорошее решение.

...