Вопрос

Я знаю, что в C я могу динамически разместить двумерный массив в куче, используя следующий код:

int** someNumbers = malloc(arrayRows*sizeof(int*));

for (i = 0; i < arrayRows; i++) {
    someNumbers[i] = malloc(arrayColumns*sizeof(int));
}

Очевидно, что на самом деле это создает одномерный массив указателей на группу отдельных одномерных массивов целых чисел, и «Система» может понять, что я имею в виду, когда спрашиваю:

someNumbers[4][2];

Но когда я статически объявляю 2D-массив, как в следующей строке...:

int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];

... создается ли в стеке аналогичная структура или она имеет совершенно другую форму?(т.е.это одномерный массив указателей?Если нет, то что это такое и как выясняются ссылки на него?)

Кроме того, когда я сказал «Система», что на самом деле отвечает за это?Ядро?Или компилятор C разбирается во время компиляции?

Это было полезно?

Решение

Статический двумерный массив выглядит как массив массивов — он просто расположен в памяти последовательно.Массивы — это не то же самое, что указатели, но поскольку их часто можно использовать как взаимозаменяемые, иногда это может сбить с толку.Однако компилятор отслеживает правильно, благодаря чему все хорошо выстраивается.Вы должны быть осторожны со статическими 2D-массивами, как вы упомянули, поскольку, если вы попытаетесь передать его в функцию, принимающую int ** параметр, произойдут плохие вещи.Вот краткий пример:

int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}};

В памяти выглядит так:

0 1 2 3 4 5

точно такой же как:

int array2[6] = { 0, 1, 2, 3, 4, 5 };

Но если вы попытаетесь пройти array1 к этой функции:

void function1(int **a);

вы получите предупреждение (и приложение не сможет правильно получить доступ к массиву):

warning: passing argument 1 of ‘function1’ from incompatible pointer type

Поскольку 2D-массив — это не то же самое, что int **.Автоматическое преобразование массива в указатель идет, так сказать, только «на один уровень».Вам необходимо объявить функцию как:

void function2(int a[][2]);

или

void function2(int a[3][2]);

Чтобы все было счастливо.

Эта же концепция распространяется и на н-мерные массивы.Однако использование подобных забавных возможностей в вашем приложении обычно только усложняет понимание.Так что будьте осторожны там.

Другие советы

Ответ основан на идее, что C на самом деле не иметь 2D-массивы - есть массивы массивов.Когда вы заявляете об этом:

int someNumbers[4][2];

Вы просите someNumbers быть массивом из 4 элементов, где каждый элемент этого массива имеет тип int [2] (который сам по себе является массивом из 2 intс).

Другая часть загадки заключается в том, что массивы в памяти всегда располагаются подряд.Если вы попросите:

sometype_t array[4];

тогда это всегда будет выглядеть так:

| sometype_t | sometype_t | sometype_t | sometype_t |

(4 sometype_t объекты, расположенные рядом друг с другом, без промежутков между ними).Итак, в вашем someNumbers массив массивов, это будет выглядеть так:

| int [2]    | int [2]    | int [2]    | int [2]    |

И каждый int [2] элемент сам по себе является массивом, который выглядит следующим образом:

| int        | int        |

В общем, вы получаете следующее:

| int | int  | int | int  | int | int  | int | int  |
unsigned char MultiArray[5][2]={{0,1},{2,3},{4,5},{6,7},{8,9}};

в памяти равно:

unsigned char SingleArray[10]={0,1,2,3,4,5,6,7,8,9};

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

В случае статически выделенных массивов компилятором будет «Система».Он зарезервирует память, как и для любой переменной стека.

В случае с массивом malloc «Система» будет реализатором malloc (обычно ядро).Все, что компилятор выделит, — это базовый указатель.

Компилятор всегда будет обрабатывать тип так, как он объявлен, за исключением примера, приведенного Карлом, где он может определить взаимозаменяемое использование.Вот почему, если вы передаете [][] функции, она должна предполагать, что это статически выделенный плоский объект, где ** считается указателем на указатель.

Чтобы получить доступ к конкретному 2D-массиву, рассмотрите карту памяти для объявления массива, как показано в коде ниже:

    0  1
a[0]0  1
a[1]2  3

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

int a[2][2] ={{0,1},{2,3}};

void f1(int *ptr);

void f1(int *ptr)
{
    int a=0;
    int b=0;
    a=ptr[0];
    b=ptr[1];
    printf("%d\n",a);
    printf("%d\n",b);
}

int main()
{
   f1(a[0]);
   f1(a[1]);
    return 0;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top