Не удается преобразовать из ' 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 *, т. е. указатель на первый элемент массива. Никакой другой информации с ним не ведется, в частности ничего сохранила размер. То же самое происходит, когда вы возвращаете указатель

обратите внимание, что массив не указатель: указатель можно изменить, чтобы указать на другие вещи, в то время как массив всегда ссылается на ту же память; указатель ничего не знает о том, насколько велико пространство памяти, на которое он указывает, в то время как размер массива всегда известен во время компиляции. Путаница возникает из-за того, что массив распады к указателю на его первый элемент во многих случаях и передача его функции/возврат его из функции являются некоторыми из этих обстоятельств.

Итак, почему ваш код не работает? Есть две большие ошибки:

  1. вы пытаетесь инициализировать массив с указателем. Мы сказали, что int * не несет никакой информации о в размере массива. Это просто указатель на первый элемент. Поэтому компилятор не может знать, насколько большой a должно быть сделано для разместить вещи, возвращенные f().

  2. на 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] совершенно законно. Читатели-люди могут сильно возражать, но компилятор и глазом не моргнет.