Какая разница между типами - int * и int * [100] в C?
Природу нуба, так что не убивай меня здесь.
Какая разница между следующими кодами?
int *p; //As i understand, it creates a pointer to an variable of size int.
int *p[100]; //Don't really know what this is.
int (*p)[100]; // I have come to understand that this is a pointer to an array.
Ответы
Ответ 1
-
Это указатель на int
:
int *p;
┌────┐
│int*│
└────┘
Он должен указывать на int
, что-то вроде этого:
┌────┐
│int*│
└─┃──┘
▼
┌───┐
│int│
└───┘
-
Это массив из 100 указателей на int
:
int *p[100];
То есть, это дает вам 100 указателей.
┌────┬────┬────┬────┬────┬────┬┄
│int*│int*│int*│int*│int*│int*│
└────┴────┴────┴────┴────┴────┴┄
Каждый указатель должен указывать int
, возможно, так:
┌────┬────┬────┬────┬────┬────┬┄
│int*│int*│int*│int*│int*│int*│
└─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴┄
▼ ▼ ▼ ▼ ▼ ▼
┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌┄
│int││int││int││int││int││int││
└───┘└───┘└───┘└───┘└───┘└───┘└┄
Конечно, нет причин, по которым они не могут указывать на один и тот же int
или что-то еще.
Вы можете использовать массив указателей, если вы хотите, чтобы многие указатели вы могли легко
перебирать. Вы можете, например, динамически распределять объекты и иметь каждую точку указателя на другом объекте:
p[0] = new int(0);
p[1] = new int(0);
// ...
Возможно, динамическое выделение int
- не лучший пример, но я думаю, что точка понятна.
-
Это указатель для массива из 100 int
:
int (*p)[100];
То есть, он дает вам всего один указатель:
┌───────────┐
│int(*)[100]│
└───────────┘
Он должен указывать на массив, содержащий 100 int
s:
┌───────────┐
│int(*)[100]│
└─┃─────────┘
▼
┌───┬───┬───┬───┬───┬───┬┄
│int│int│int│int│int│int│
└───┴───┴───┴───┴───┴───┴┄
Вы получите указатель на массив, когда вы используете адрес-оператора (&
) для имени массива. Например:
int arr[100] = { /* some initial values */ };
int (*p)[100] = &arr;
Здесь я взял адрес массива arr
, который дает мне указатель на этот массив. Если вы хотите получить доступ к элементу массива, сначала нужно разыменовать указатель: (*p)[3]
получит доступ к элементу 3.
Боковое примечание:
Всегда помните, что массивы не являются указателями. Как мы только что видели, мы можем взять адрес массива, чтобы получить указатель на него, как и любой другой (невременный) объект в С++. Единственное специальное соединение между массивами и указателями состоит в том, что имя массива может быть неявно преобразовано в указатель на первый элемент массива. Это означает, что действует следующее:
int arr[100] = { /* some initial values */ };
int* p = arr;
Указатель p
будет указывать на первый элемент в arr
. Обратите внимание: p
не является указателем на массив, а указателем на элемент массива.
(Также обратите внимание, что аргумент функции типа массива отсутствует. Если вы пишете что-то вроде int p[]
как аргумент функции, он преобразуется компилятором как int*
.)
Ответ 2
Похоже, вы могли бы использовать введение в Спиральное правило.
Начните с переменной и "спирально" со своим направлением справа налево:
+-------+
| +--+ | // So we have:
| | | | p // p
int * p | | * p // p is a pointer
^ ^ | | int * p // p is a pointer to an int
| +----+ |
+----------+
Следующий:
+--------+
| +--+ | p // p
| | V | p[100] // p is an array of 100
int * p[100] | * p[100] // p is an array of 100 pointers
^ ^ | | int * p[100] // p is an array of 100 pointers to ints
| +----+ |
+-----------+
Наконец, новая часть правила сначала сделайте в скобках:
+-----+
| +-+ |
| ^ | | ( p) // p
int (* p) [100]; (*p) // p is a pointer
^ ^ | | (*p)[100] // p is a pointer to an array of 100
| +---+ | int (*p)[100] // p is a pointer to an array of 100 ints
+---------+
Если вы в сети/имеете доступ к компьютеру, он всегда использует fule для использования cdecl.org сайта, но важно быть возможность чтения кода в автономном режиме, и это правило позволит вам сделать именно это.
Ответ 3
Природу нуба, так что не убивай меня здесь.
Разработка того, что тип означает в C, может быть сложным даже для экспертов. Не беспокойтесь.
Какая разница между следующими кодами?
Другие ответы хороши, и я не собираюсь им противоречить. Скорее, здесь есть еще один способ подумать об этом. Нам нужно определить три вещи:
-
Переменная - это вещь, которая поддерживает три операции. Операция fetch принимает переменную и производит ее текущее значение. Операция выборки не имеет обозначений; вы просто используете переменную. Операция хранилища принимает переменную и значение и сохраняет значение в переменной. Операция адреса принимает переменную и создает указатель.
-
Указатель - это то, что поддерживает одну операцию. Операция разыменования, написанная как префикс *pointer
, принимает указатель и создает переменную. (Указатели поддерживают другие операции, такие как арифметика и индексирование, - это форма арифметики, но не туда.)
-
Массив - это вещь, которая поддерживает одну операцию. Операция index принимает массив и целое число и создает переменную. Это синтаксис postfix: array[index]
Хорошо, теперь мы подошли к вашему вопросу. Что делает декларация
int p;
означает? То, что выражение p
является переменной типа int
. Обратите внимание, что это переменная; вы можете хранить вещи до p
. Что делает декларация
int *p;
означает? То, что выражение *p
является переменной типа int
. Теперь, когда мы знаем, что мы можем определить, что такое p
. Поскольку *p
является разыменованием и создает переменную, p
должен быть указателем на int. Что делает декларация
int *p[100];
означает? Это означает, что * выражение *p[i]
является переменной типа int
при условии, что i
является целым значением от 0
до 99
. Мы получили переменную, но мы могли бы получить ее от указателя или массива, поэтому нам нужно выяснить, что. Мы консультируемся с таблицей приоритетов операторов и обнаруживаем, что оператор индексирования связывает "более жесткий", чем оператор разыменования. То есть:
*p[i]
- это то же самое, что и
*(p[i])
и помните, что это переменная типа int
. Содержимое parens разыменовывается, чтобы создать переменную типа int
, поэтому содержимое parens должно быть указателем на int
. Поэтому
p[i]
является указателем на int. Как это возможно? Это должно быть выборка переменной типа pointer-to-int! Итак, p[i]
- это переменная типа указателя на int. Поскольку это операция индекса, p
должен быть массивом указателей на int
.
Теперь вы выполните следующий.
int (*p)[100];
означает что?
Ответ 4
int *p;
→ Объявляет указатель на целочисленный тип.
int *p[100];
→ Объявляет массив из 100 указателей на целочисленный тип.
int (*p)[100];
→ Объявляет указатель на массив из 100 целых чисел.
Используйте cdecl для перевода таких типов.