Что означает * p, когда ** p уже объявлено - PullRequest
1 голос
/ 29 января 2020

Код

short **p = (short **)malloc(sizeof(short *));
*p = malloc(sizeof(short));
**p = 10;
printf("**p = %d", **p);

Выход

** p = 10

В этом коде объявляется множественный указатель **p и *p используется без какого-либо объявления (возможно, это **p).

Что означает *p в моем случае ? Извините за очень простой вопрос.

Я видел C стандарт и переполнение стека, но я не смог что-то выяснить.

Ответы [ 4 ]

2 голосов
/ 29 января 2020
short **p = (short **)malloc(sizeof(short *));

Эта строка объявляет указатель на указатель p. Кроме того, значение p устанавливается равным возвращаемому значению malloc. Это эквивалентно

short **p;
p = (short **)malloc(sizeof(short *));

Вторая строка

*p = malloc(sizeof(short));

Здесь *p - это значение p. *p имеет указатель типа. *p устанавливается на возвращаемое значение mallo c. Это эквивалентно

p[0] = malloc(sizeof(short));

Третья строка

**p = 10;

**p является значением значения p. Это типа short. Это эквивалентно

p[0][0] = 10

По сути, приведенный выше код выделяет двумерный массив short, затем выделяет память для первой строки и затем устанавливает элемент p[0][0] равным 10.

Как общий комментарий к вашему коду, вы не должны использовать typecast в malloc. См. Я разыгрываю результат Малло c?

2 голосов
/ 29 января 2020

Что означает * p, когда ** p уже объявлено?

short **p = (short **)malloc(sizeof(short *));

(лучше записано как)

short **p = malloc (sizeof *p);

Объявляет указатель-на-указатель-на short p и выделяет память для указателя знака с помощью malloc и назначает начальный адрес для этого блока памяти для p. Смотрите: в C нет необходимости разыгрывать возврат malloc, это не нужно. См .: Разыгрываю ли я результат mallo c?

*p = malloc(sizeof(short));

(эквивалентно)

p[0] = malloc (sizeof *p[0]);

Выделяет хранилище для одного short и присваивает начальный адрес для этого блока памяти p[0].

**p = 10;

(эквивалентно)

*p[0] = 10;

(или)

p[0][0] = 10;

Назначает значение 10 указателю разыменования *p[0] (или **p или p[0][0]), обновляющее значение по этому адресу памяти до 10.

printf("**p = %d", **p);

Печатает значение, хранящееся в блоке память, на которую указывает p[0] (значение, к которому обращаются путем разыменования указателя как *p[0] или **p)

Способ сохранить это прямо в вашей голове, это p - единственный указатель типа указатель на указатель на short. Есть 2 уровня косвенности (например, указатель на указатель ). Чтобы удалить один уровень косвенности, вы используете унарный оператор *, например,

*p          /* has type pointer-to short */

или [..] также действует как разыменование, так что:

p[0]        /* also has type pointer-to short */

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

**p         /* has type short */

и

*p[0]       /* also has type short */

, как если бы

p[0][0]     /* also has type short */

Другой элемент, который нужно держать прямо, - это type control указатель arithmeti c. Таким образом, p++ добавляет 8 байтов к адресу указатель-указатель, так что теперь он указывает на следующий указатель . Если вы делаете short *q = (*p)++; (или short *q = p[0]++, adds 2-bytes to the address for the pointer-to-short, so q now points to the next short in the block of memory beginning at* p (or p [0] `). (2-го короткого короткого номера нет, потому что вы выделили только 1 - но вы получите очко)

Дайте мне знать, если у вас есть дополнительные вопросы.

2 голосов
/ 29 января 2020

Для любого массива или указателя p и индекса i выражение p[i] точно равно *(p + i) (где * - унарный оператор разыменования, результатом его для указателя является значение на который указывает указатель).

Так что если у нас есть p[0], то это точно равно *(p + 0), что равно *(p), что равно *p. Если вернуться назад, то *p равно p[0].

То есть

*p = malloc(sizeof(short));

равно

p[0] = malloc(sizeof(short));

И

**p = 10;

равно

p[0][0] = 10;

(**p равно *(*(p + 0) + 0), что равно *(p[0] + 0), что затем равно p[0][0])


Важно отметить, что звездочка * может означать разные вещи в разных контекстах.

Она может использоваться при объявлении переменной, а затем означает «объявить как указатель»:

int *p;  // Declare p as a pointer to an int value

Может использоваться для разыменования указателя, для получения значения, на которое указывает указатель:

*p = 0;  // Equal to p[0] = 0

И может использоваться в качестве оператора умножения:

r = a * b;  // Multiply the values in a and b, store the resulting value in r
1 голос
/ 29 января 2020

Позвольте мне сказать это по-другому,

рассмотрим пример,

int x;
int *y = &x;
int **z = &y;
x = 10;

Что упрощает это,

enter image description here

Примечание : Только для иллюстрации я выбрал адрес x, y, z в качестве 0x1000,0x2000,0x3000 соответственно.

Что означает * p в моем случае?

Короче говоря, фрагмент short **p = (short **)malloc(sizeof(short *)); динамически выделяет указатель на указатель типа short, т. Е. Такой же, как y в моем примере.

...