Я бездельничаю с многомерными массивами и указателями. Я смотрел на программу, которая распечатывает содержание, и адреса, простой массив. Вот мое объявление массива:
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?
Когда объявляется многомерный массив, компилятор рассматривает его как одномерный массив. Многомерные массивы - это всего лишь абстракция, облегчающая нашу жизнь. У вас есть недоразумение: Это не один массив, указывающий на 4 массива, это всегда один сплошной блок памяти.
В вашем случае, делать:
int zippo[4][2]
на самом деле то же самое, что делать
int zippo[8]
С математикой, необходимой для 2D адресации, обрабатываемой компилятором.
Подробности смотрите в этом учебном пособии по массивам на языке Си++.
Это очень отличается от выполнения:
int** zippo
или
int* zippo[4]
В данном случае вы делаете массив из четырех указателей, который может быть выделен для других массивов.
Очень хорошо объяснил Рид, добавлю еще несколько пунктов для упрощения, когда мы ссылаемся на zippo
или zippo[0]
или zippo[0][0]
, мы все еще ссылаемся на тот же самый базовый адрес массива zippo
. Причина, по которой массивы всегда являются смежными блоками памяти, а многомерные массивы - это несколько одномерных массивов, размещенных непрерывно.
Когда нужно увеличивать значение на каждую строку, нужен указатель int *p = &zippo[0][0]
, и при этом p++
увеличивает значение указателя на каждую строку.
В вашем примере это массив 4 X 2, при выполнении p++
его указатель в настоящее время указывает на второе множество из 4 элементов.
Важно то, что int zippy[4][2]
не является тем же самым типом объекта, что int **zippo
.
Так же как и int zippi[5]
, zippy
является адресом блока памяти. Но компилятор знает, что вы хотите обратиться к восьми ячейкам памяти, начинающимся с zippy
, с двухмерным синтаксисом, но хотите обратиться к пяти ячейкам памяти, начинающимся с zippi
, с одномерным синтаксисом.
zippo
- это совсем другое. It содержит адрес блока памяти, достаточно большого, чтобы содержать два указателя, и если Вы сделаете их точкой на некоторых массивах целых чисел, Вы можете разыменовать их с синтаксисом доступа к двухмерным массивам.
Когда выражение массива появляется в большинстве контекстов, его тип неявно преобразуется из «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] ]
все имеют одинаковое значение; все они указывают на основание массива (адрес массива совпадает с адресом первого элемента массива). Однако типы различных выражений различаются.
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 #.... Я думаю, что ваши общие
переменные - это ваша проблема. Сделайте их переменными экземпляра и это должно работать.
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);
, но указатели отличаются тем, что указывают на всю матрицу, строку и одно целое число соответственно.