Как C получает адрес строки для 2d массива

Может кто-нибудь объяснить мне, как C получает правильный адрес памяти для строки, когда вы используете только один индекс для доступа к 2d массиву?

Пример -

int array2D[2][2] = {1,2,3,4};
printf ( "starting address of row2 = %p" , array2D[1]);

Я понимаю, что при подписке на C то, что на самом деле происходит, это добавление указателя, поэтому для массива 1d имя массива указывает на элемент 0. В этом случае, если бы я хотел элемент 1, компилятор взял бы начальный адрес (скажем, 4000) и добавьте 4 к нему (предполагая 4-битное целое число), так что возвращаемым является элемент по адресу памяти 4004.

Насколько я понимаю, когда вы заполняете 2d массив, как в моем примере, они распределяются последовательно, поэтому я бы

1 2
3 4
по адресам

4000 4004

4008 4012

Так как же получается, что C в этом случае array2D[1] должен указывать на 4008, а не на 4004? Он запускает оператор sizeof() или я неправильно понял здесь фундаментальное значение?

заранее спасибо

4 ответа

Решение

C знает, какова длина каждой строки, поэтому он умножает, чтобы найти строку.

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

затем &x[1][0] является &x[0][0] плюс 3 * sizeof(int),

Вот почему в объявлении многомерного массива C должны быть указаны все измерения, кроме первого.

sizeof(array2D[1]) == 8;
если адрес array2D равен 4000;
поэтому адрес array2D [1] равен 4000+sizeof(array2D[1]) == 4000+8;

Арифметика указателя зависит от типа элемента, на который указывает. Дан указатель p печатать T, p + 1 указывает на следующий элемент типа T, не обязательно следующий байт p, Если T является char, затем p + 1 указывает на следующее char объект после p, который начинается с байта, следующего сразу p; если T является char [10], затем p + 1 указывает на следующий 10-элементный массив char после p, который начинается с 10-го байта следующего p,

Тип выражения array2d в это "2-элементный массив 2-элементный массив int ", который" распадается ", чтобы набрать" указатель на 2-элементный массив int ", или же int (*)[2] 1 Таким образом, выражение array2d[1] интерпретируется как *(array2d + 1), поскольку array2d указывает на объект типа int [2], array2d + 1 указывает на следующий 2-элементный массив int следующий array2d, который 2 * sizeof int байтов от array2d,


1. За исключением случаев, когда это операнд sizeof или одинарный & операторы, или строковый литерал, используемый для инициализации другого массива в объявлении, выражение типа "массив N-элемента T "будет преобразован в выражение типа" указатель на T "и его значением будет адрес первого элемента в массиве.

Это будет немного скучно, но терпите меня до сих пор.

Подписка на массив - это просто сокращение: (p[N]) равняется (*(p + N)) во всех контекстах для типов указателей (оба являются недопустимыми выражениями для void*, хоть).

Сейчас если p это тип массива, он будет распадаться на тип указателя в выражении, как (*(p + N)); int[2][2] будет распадаться на указатель типа (*)[2] (т.е. указатель на int[2]).

Арифметика указателей учитывает типы; нам нужно преобразовать вещи в char* чтобы визуализировать, что компилятор делает с нами:

T *p;
p[N] equals *(p + N) equals *(T*)((unsigned char*)p + N * sizeof *p)

Сейчас если T были int[2] (чтобы соответствовать ситуации, которую мы описали выше), то sizeof *p было бы sizeof(int[2])т.е. 2 * sizeof(int),

Так работает подписка в так называемых многомерных массивах.

Другие вопросы по тегам