Адрес указателя в многомерном массиве C

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

int zippo[4][2] = { {2,4},
            {6,8},
            {1,3},
            {5,7}   };

Мое текущее понимание - это zippo указатель, и он может содержать адрес нескольких других указателей. По умолчанию, zippo содержит адрес указателя zippo[0], и это может также содержать адреса указателей zippo[1], zippo[2], и zippo[3].

Теперь, возьмите следующее утверждение:

printf("zippo[0] = %p\n", zippo[0]);
printf("  *zippo = %p\n", *zippo);
printf("   zippo = %p\n", zippo);

На моей машине, которая дает следующий вывод:

zippo[0] = 0x7fff170e2230
  *zippo = 0x7fff170e2230
   zippo = 0x7fff170e2230

Я отлично понимаю почему zippo[0] и *zippo имейте то же значение. Они - оба указатели, и они оба хранят адрес (по умолчанию) целого числа 2, или zippo[0][0]. Но что произошло с zippo также совместно используя тот же адрес памяти? Не был должен zippo сохраните адрес указателя zippo[0]? Whaaaat?

28
задан Ichimonji10 5 January 2010 в 02:14
поделиться

5 ответов

Когда объявляется многомерный массив, компилятор рассматривает его как одномерный массив. Многомерные массивы - это всего лишь абстракция, облегчающая нашу жизнь. У вас есть недоразумение: Это не один массив, указывающий на 4 массива, это всегда один сплошной блок памяти.

В вашем случае, делать:

int zippo[4][2]

на самом деле то же самое, что делать

int zippo[8]

С математикой, необходимой для 2D адресации, обрабатываемой компилятором.

Подробности смотрите в этом учебном пособии по массивам на языке Си++.

Это очень отличается от выполнения:

int** zippo

или

int* zippo[4]

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

32
ответ дан 28 November 2019 в 02:39
поделиться

Очень хорошо объяснил Рид, добавлю еще несколько пунктов для упрощения, когда мы ссылаемся на zippo или zippo[0] или zippo[0][0], мы все еще ссылаемся на тот же самый базовый адрес массива zippo. Причина, по которой массивы всегда являются смежными блоками памяти, а многомерные массивы - это несколько одномерных массивов, размещенных непрерывно.

Когда нужно увеличивать значение на каждую строку, нужен указатель int *p = &zippo[0][0], и при этом p++ увеличивает значение указателя на каждую строку. В вашем примере это массив 4 X 2, при выполнении p++ его указатель в настоящее время указывает на второе множество из 4 элементов.

.
2
ответ дан 28 November 2019 в 02:39
поделиться

Важно то, что int zippy[4][2] не является тем же самым типом объекта, что int **zippo.

Так же как и int zippi[5], zippy является адресом блока памяти. Но компилятор знает, что вы хотите обратиться к восьми ячейкам памяти, начинающимся с zippy, с двухмерным синтаксисом, но хотите обратиться к пяти ячейкам памяти, начинающимся с zippi, с одномерным синтаксисом.

zippo - это совсем другое. It содержит адрес блока памяти, достаточно большого, чтобы содержать два указателя, и если Вы сделаете их точкой на некоторых массивах целых чисел, Вы можете разыменовать их с синтаксисом доступа к двухмерным массивам.

2
ответ дан 28 November 2019 в 02:39
поделиться

Когда выражение массива появляется в большинстве контекстов, его тип неявно преобразуется из «N-элементного массива T» в «указатель на T», а его значение устанавливается так, чтобы указывать на первый элемент в массиве. Исключениями из этого правила являются случаи, когда выражение массива является операндом операторов sizeof или адреса ( & ), или когда массив является строковым литералом, используемым в качестве инициализатор в объявлении.

Таким образом, выражение zippo «распадается» от типа int [4] [2] (4-элементный массив из 2-элементных массивов int) до int (*) [2] (указатель на двухэлементный массив int). Аналогично, тип zippo [0] - int [2] , который неявно преобразуется в int * .

Учитывая объявление int zippo [4] [2] , в следующей таблице показаны типы различных выражений массива, включающих zippo и любые неявные преобразования:

Expression    Type            Implicitly converted to  Equivalent expression
----------    ----            -----------------------  ---------------------
zippo         int [4][2]      int (*)[2]               
&zippo        int (*)[4][2]       
*zippo        int [2]         int *                    zippo[0]
zippo[i]      int [2]         int *
&zippo[i]     int (*)[2]                               
*zippo[i]     int                                      zippo[i][0]
zippo[i][j]   int
&zippo[i][j]  int *
*zippo[i][j]  invalid

Обратите внимание, что zippo , & zippo , * zippo , zippo [0] , & zippo [0] и & zippo [0] [0] ] все имеют одинаковое значение; все они указывают на основание массива (адрес массива совпадает с адресом первого элемента массива). Однако типы различных выражений различаются.

34
ответ дан 28 November 2019 в 02:39
поделиться

1. У вас есть правильное представление о том, как проектировать ваши ресурсы, IMHO. Я бы ничего не изменил.

2. Вместо того, чтобы пытаться расширить HTTP с помощью большего количества глаголов, подумайте о том, до чего можно сократить предлагаемые глаголы с точки зрения основных методов и ресурсов HTTP. Например, вместо команды activate _ login можно настроить такие ресурсы, как /api/users/1/login/active , что является простым логическим значением. Чтобы активировать вход, просто ПОМЕСТИТЕ туда документ, в котором написано «истинно» или 1 или что-либо еще. Для деактивации PUT документ, который пуст или говорит 0 или false.

Чтобы изменить или установить пароли, просто выполните команду PUT для /api/users/1/password .

Всякий раз, когда вам нужно добавить что-то (например, кредит) думать с точки зрения POST s. Например, можно выполнить POST для такого ресурса, как /api/users/1/credits с телом, содержащим количество кредитов для добавления. PUT на том же ресурсе может использоваться для перезаписи значения, а не для добавления. POST с отрицательным числом в теле будет вычитаться и так далее.

3. Я настоятельно советую не расширять основные коды состояния HTTP. Если вы не можете найти ту, которая точно соответствует вашей ситуации, выберите ближайшую и поместите сведения об ошибке в тело ответа. Также помните, что заголовки HTTP расширяемы; приложение может определить все пользовательские заголовки, которые вам нравятся. Например, одно приложение, над которым я работал, может вернуть 404 Not Found при различных обстоятельствах. Вместо того, чтобы заставить клиента анализировать тело ответа по этой причине, мы просто добавили новый заголовок X-Status-Extended , который содержал наши собственные расширения кода состояния. Таким образом, вы можете увидеть ответ, как:

HTTP/1.1 404 Not Found    
X-Status-Extended: 404.3 More Specific Error Here

Таким образом HTTP клиент, как веб-браузер, все еще будет знать, что делать с обычным кодом 404, и более сложный HTTP клиент может выбрать посмотреть на X-Status-Extended заголовок для более конкретной информации.

4. Для аутентификации рекомендуется использовать проверку подлинности HTTP, если это возможно. Но IMHO не имеет ничего плохого в использовании аутентификации на основе файлов cookie, если вам это проще.

-121--1784406-

статические переменные также вызовут проблемы и будут похожи на состояние приложения.... Я думаю, что Shared - это как static в C #.... Я думаю, что ваши общие переменные - это ваша проблема. Сделайте их переменными экземпляра и это должно работать.

-121--4780524-

zippo не является указателем. Это массив значений массива. zippo и zippo [i] для i в 0.. 4 может «распадаться» на указатель в определенных случаях (в частности, в контексте значений). Попробуйте напечатать sizeof zippo для примера использования zippo в контексте, отличном от значения.В этом случае sizeof сообщит размер массива, а не размер указателя.

Имя массива в контекстах значений распадается до указателя на его первый элемент. Так, в контексте значения zippo совпадает с & zippo [0] и, таким образом, имеет тип «указатель на массив [2] из int »; * zippo , в контексте значения совпадает с & zippo [0] [0] , т.е. «указатель на int ». Они имеют одно и то же значение, но разные типы.

Для ответа на второй вопрос рекомендуется прочитать Массивы и указатели . Указатели имеют одно и то же «значение», но указывают на различные объемы пространства. Попробуйте напечатать zippo + 1 и * zippo + 1 , чтобы увидеть это более четко:

#include <stdio.h>

int main(void)
{
    int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
    printf("%lu\n", (unsigned long) (sizeof zippo));
    printf("%p\n", (void *)(zippo+1));
    printf("%p\n", (void *)(*zippo+1));
    return 0;
}

Для моего запуска он печатает:

32
0xbffede7c
0xbffede78

Сообщая мне, что sizeof (int) на моем компьютере 4, и

Кроме того, для «% p» спецификатора формата требуется void * в функциях * printf () , поэтому указатели должны указываться на void * в вызовах printf () ( printf () является переменной функцией, поэтому компилятор может

Edit : Когда я говорю, что массив «распадается» на указатель, я имею в виду, что имя массива в контексте значения эквивалентно указателю. Таким образом, если у меня есть T pt [100]; для некоторого типа T , то имя pt имеет тип T * в контексте значений. Для операторов sizeof и унарных и имя pt не уменьшается до указателя. Но можно сделать T * p = pt; - это совершенно верно, потому что в данном контексте pt имеет тип T * .

Обратите внимание, что это «затухание» происходит только один раз. Итак, допустим:

int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };

Тогда zippo в контексте значения распадается на указатель типа: указатель на массив [2] из int . В коде

int (*p1)[2] = zippo;

является допустимым, в то время как

int **p2 = zippo;

инициирует предупреждение «несовместимое назначение указателя».

С zippo , определенным как выше,

int (*p0)[4][2] = &zippo;
int (*p1)[2] = zippo;
int *p2 = zippo[0];

являются действительными. Они должны печатать одно и то же значение при печати с помощью printf («% p\n», (void *) name); , но указатели отличаются тем, что указывают на всю матрицу, строку и одно целое число соответственно.

5
ответ дан 28 November 2019 в 02:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: