Не можете преобразовать из int * в int []? - PullRequest
9 голосов
/ 27 июня 2011

Я знаю, что это может быть распространенный вопрос, но я пытался найти, но все еще не могу найти четкий ответ.

У меня есть следующий код:

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 ]

21 голосов
/ 27 июня 2011

В этом коде на самом деле есть две ошибки.

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

Во-вторых, не существует неявного преобразования указателей в типы массивов в C ++.Они похожи, но не идентичны.Массивы могут распадаться на указатели, но не работают наоборот, так как информация теряется в пути - указатель просто представляет адрес памяти, а массив представляет адрес непрерывной области, обычно с определенным размером.Также нельзя назначать массивы.

Например, мы можем использовать [i] вместо * (a + i)

Это, однако, имеетмало что связано с различиями между массивами и указателями, это просто синтаксическое правило для типов указателей.Поскольку массивы распадаются на указатели, это работает и для массивов.

11 голосов
/ 27 июня 2011

Тип 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;в лучшем случае ваша программа зависнет (и вы сразу заметите, что сделали что-то не так), в худшем случае она будет работать некоторое время, а затем начнет давать странные результаты.

2 голосов
/ 27 июня 2011

int * и int [] похожи, но различны.int * - это реальный указатель, а int [] - ссылка на массив (своего рода «постоянный указатель» на начало данных), который нельзя изменить.Таким образом, int * может рассматриваться как int [], но не наоборот.

0 голосов
/ 27 июня 2011

Вы можете использовать a[b] и *(a+b) взаимозаменяемо, потому что именно так определяется a[b], когда один из a или b является указателем, а другой имеет целочисленный тип или тип перечисления.

Примечание. Это также означает, что выражения типа 42[a] совершенно допустимы. Люди-читатели могут сильно возразить, но компилятор на это не пойдет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...