Не удается преобразовать из ' int * 'в 'int []'?
Я знаю, что это может быть общий вопрос, но я пытался искать, но все еще не могу найти четкого ответа.
у меня есть следующий код:
int* f() {
int a[] = {1,2,3};
return a;
}
int main() {
int a[] = f(); // Error here
getch();
return 0;
}
этот код выдает сообщение об ошибке:"Cannot convert from 'int *' to 'int []'
"
Я нашел это довольно странным, потому что я прочитал, что указатель и массив похожи. Например, мы можем использовать[i] вместо *(a + i). Кто-нибудь может дать мне ясное объяснение, пожалуйста?
4 ответов
на самом деле в этом коде есть две ошибки.
во-первых, вы возвращаете адрес временного (массив int внутри f
), поэтому его содержимое не определено после завершения функции. Любая попытка доступа к памяти, на которую указывает возвращаемый указатель, вызовет неопределенное поведение.
во-вторых, в C++нет неявного преобразования указателей в типы массивов. Они похожи, но не идентичны. Массивы могут распадаться на указатели, но это не работает наоборот, поскольку информация теряется по пути-указатель просто представляет адрес памяти, а массив представляет адрес непрерывной области, как правило, с определенным размером. Также вы не можете назначить массивам.
например, мы можем использовать[i] вместо *(a + i)
это, однако, имеет мало общего с различиями между массивами и указателями, это просто синтаксическое правило для типов указателей. Поскольку массивы распадаются на указатели, он работает для массивов, а также.
тип int[]
фактически не существует.
когда вы определяете и инициализируете массив как
int a[] = {1,2,3};
компилятор подсчитывает элементы в инициализаторе и создает блок нужного размера; в этом случае он становится волшебным образом:
int a[3] = {1,2,3};
int[]
используется в качестве параметра функции, вместо этого, это просто int *
, т. е. указатель на первый элемент массива. Никакой другой информации с ним не ведется, в частности ничего сохранила размер. То же самое происходит, когда вы возвращаете указатель
обратите внимание, что массив не указатель: указатель можно изменить, чтобы указать на другие вещи, в то время как массив всегда ссылается на ту же память; указатель ничего не знает о том, насколько велико пространство памяти, на которое он указывает, в то время как размер массива всегда известен во время компиляции. Путаница возникает из-за того, что массив распады к указателю на его первый элемент во многих случаях и передача его функции/возврат его из функции являются некоторыми из этих обстоятельств.
Итак, почему ваш код не работает? Есть две большие ошибки:
вы пытаетесь инициализировать массив с указателем. Мы сказали, что
int *
не несет никакой информации о в размере массива. Это просто указатель на первый элемент. Поэтому компилятор не может знать, насколько большойa
должно быть сделано для разместить вещи, возвращенныеf()
.-
на
f
вы возвращаете указатель на переменную, которая является локальной для этой функции. Это неправильно, потому что указатель не хранит данные, он только точки туда, где хранятся данные, т. е. в вашем случае вa
местные кf
. Потому что этот массив местные функции, он перестает существовать, когда функция завершает работу (т. е. вreturn
).это означает, что вы возвращаете указатель указывает на вещи, которые больше не существуют; рассмотрим код:
int * a = f();
инициализация работает, и вы можете попробовать использовать
a
далее в функции, ноa
будет указывать на больше не существующий массивf
; в лучшем случае ваша программа рухнет (и вы сразу заметите, что вы сделали что-то не так), в худшем это будет работать в течение некоторого времени, а затем начать дает странные результаты.
int * и int [] похожи, но разные. int * является реальным указателем, между тем int[] является ссылкой на массив ( своего рода "постоянным указателем" на начало данных), который не может быть изменен. Таким образом, int * может быть threated как int [], но не viceversa.
можно использовать a[b]
и*(a+b)
взаимозаменяемо, потому что именно так a[b]
определяется, когда один из a
или b
является указателем, а другой-целочисленным или перечислительным типом.
Примечание: это также означает, что такие выражения, как 42[a]
совершенно законно. Читатели-люди могут сильно возражать, но компилятор и глазом не моргнет.