#c #c
#c #c
Вопрос:
В чем разница между типом ** name и типом * name[]?
Зачем кому-то использовать одно поверх другого?
Спасибо
Комментарии:
1. Фактически нет никакой разницы. Например, мы всегда видим, что char **argv и char *argv[] взаимозаменяемо используются для объявления аргументов main в программе на C. Вы можете выбрать один из них по соображениям ясности или согласованности.
Ответ №1:
Ну, это зависит от того, находится ли это в объявлении переменной или в аргументе функции? Если в объявлении переменной:
Type** name = amp;pointer_to_type;
Type* name[] = { amp;pointer_to_type, 0, amp;pointer_to_type };
Первый — это указатель на указатель на тип, а второй — массив указателей на тип длиной 3.
Если в аргументе функции, это одно и то же. Массивы распадаются на указатели, и оба Type** name
и Type* name[]
точно такие же, как аргументы функции. Однако вторая форма дает понять, что name представляет собой массив указателей неизвестной длины, в то время как первая этого не делает. Я бы использовал Type**
для указания одного элемента и Type*[]
для указания массива.
Комментарии:
1. Я боюсь тебя, маленькая лошадка. Участник на 32 дня и 6000 репутации. Что это за метод?
2. Также хотелось бы добавить немного о распределении памяти: использование
Type* name[]
в качестве объявления переменной автоматически дает вам допустимую память при первом разыменовании (массив указателей размещается в стеке). Вы могли бы использовать эти команды последовательно:Type* name[4]; name[3] = NULL;
но если бы вы попробовали это сType** name
помощью, вы бы выполнили segfault, если бы вы вручную не указали на validType*
.3. @sidyll: Энтузиазм, я бы предположил? У меня даже есть значок для этого: P
4. Ну, и у меня есть значок фанатика 🙂 В любом случае, поздравляю вас с вашими усилиями и талантом отвечать с точностью.
5. @sidyll, спасибо за смех… Я тоже не мог не заметить, что маленькая лошадка в огне. @K, вот тебе еще один значок!
Ответ №2:
Разница между ними в основном проявляется при объявлении / определении объектов любого типа.
Обозначение Type *name[]
создает массив неизвестного размера (может быть выведено из инициализатора), Type** name
создает указатель. Это означает:
char *array[]={"hello", "world", 0}; /* OK, array of size 3 */
char **ptr={"hello", "world", 0}; /* not possible */
В некоторых выражениях они ведут себя по-разному. В частности, массивы не могут быть назначены, но переменные указателя могут:
ptr , ptr=array; /* assignment and mutation of ptr possible */
// array=whatever /* impossible */
Оператор sizeof работает по-разному на двух. sizeof(array)
будет зависеть от количества элементов массива (в данном случае может быть 12), но sizeof(ptr)
возвращает всегда один и тот же размер (например, 4 на основных 32-разрядных архитектурах)
Кроме того, при объявлении глобальных переменных вы не должны смешивать их:
extern char* data[];
должно сопровождаться в .c
файле
char* data[N];
и наоборот. По сути, определение массива означает выделение нескольких последовательных объектов, тогда как определение указателя означает выделение одной переменной. Компилятор обрабатывает оба по-разному и должен знать, что есть что.
Однако при объявлении или передаче параметров функциям они одинаковы. Итак
int main(int argc, char** argv)
int main(int argc, char* argv[]) /* the same */
Комментарии:
1. » массивы не являются значениями lvalues «, они являются значениями lvalues. » таким образом, они не могут быть назначены «, и это все равно не будет следовать: (x не является значением lvalue) не подразумевает («x = что угодно;» неверно сформирован). C — не простой язык. 😉
Ответ №3:
Зависит от контекста.
Если он определяет переменную, которая не является параметром функции, то in Type** name
— name
это указатель на указатель на переменную типа Type
, а in Type* name[SOME_POSITIVE_INTEGER_CONSTANT]
— это массив указателей на переменные типа Type
.
Если это параметр функции, то оба они одинаковы и name
являются указателем на указатель на переменную типа Type
.
Комментарии:
1. В объявлении переменной, которое не является определением, вы можете опустить
SOME_POSITIVE_INTEGER_CONSTANT
2. @curiousguy: в области действия файла «int * ga[];» выдает «предупреждение: массив
ga' assumed to have one element". In function scope "int* ma[];" results in "error: array size missing in
ma'». Вы хотите избежать таких ситуаций. однако «extern int * ega[];» в порядке. Это с помощью gcc (3.3.4), скомпилированного как C со всеми включенными предупреждениями.3. Не существует такого понятия, как «область действия файла». Вы, вероятно, имеете в виду глобальную область. В любой области объявление переменной без спецификатора класса хранения
extern
также является определением .
Ответ №4:
По сути, тип ** — это указатель на указатель. Подумайте, что это похоже на (Тип *) * . Таким образом, он указывает на тип *, который может быть типом или типом [] .
А другой, Type * — это указатель на тип или, в данном случае, на тип массива[]. Таким образом, они «почти» одинаковы.
Комментарии:
1. Пожалуйста, не думайте об этом как
(Type*)*
! Грамматика так не работает. Подумайте об этом какType *(*)
, или, скорееType (*(*name))
: выражение(*(*name))
имеет типType
. (Но это не работает для ссылок или функций.)