В чем может быть причина предупреждения, которое появляется при компиляции следующего фрагмента кода - PullRequest
0 голосов
/ 25 мая 2011

Это простой кусок кода, который я написал, чтобы проверить, законно ли возвращать адрес локальной переменной, и мои предположения были подтверждены компилятором, который выдает предупреждение, говорящее то же самое:

warning: function returns address of local variable

Но правильный адрес печатается при исполнении ... Кажется странным!

#include<stdio.h>
char * returnAddress();
main()
{
    char *ptr;
    ptr = returnAddress();
    printf("%p\n",ptr);
}

char * returnAddress()
{
    int x;
    printf("%p\n",&x);
    return &x;
}

Ответы [ 6 ]

5 голосов
/ 25 мая 2011

Поведение не определено.

Когда вы вызываете неопределенное поведение, допускается все, что угодно, в том числе и полусанитарное поведение.

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

Вы должны получать предупреждения о преобразовании между указателем int и указателем char, а также предупреждения о возврате адреса локальной переменной.

4 голосов
/ 25 мая 2011

То, что вы пытаетесь сделать, обычно опасно:

В returnAddress() вы объявляете локальную нестатическую переменную i в стеке.Затем вы возвращаете его адрес, который будет недействительным после возврата функции.Кроме того, вы пытаетесь вернуть char *, в то время как у вас действительно есть int *.

Чтобы избавиться от предупреждения, вызванного возвращением указателя на локальную переменную, вы можете использовать этот код:

void *p = &x;
return p;

Конечно, печать совершенно безвредна, но разыменование (например, int x = *ptr;) может привести к сбою вашей программы.

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

3 голосов
/ 25 мая 2011

Да, один и тот же адрес печатается оба раза.Кроме того, когда адрес печатается в main(), он больше не указывает на какой-либо действительный адрес памяти.(Переменная x была создана в кадре стека returnAddress(), который был удален при возврате функции.)

Вот почему выдается предупреждение: поскольку теперь у вас есть адрес, который вы не должны использовать.

1 голос
/ 25 мая 2011

Это не странно. Локальные переменные функции размещаются в стеке этой функции. Когда управление выходит из функции, локальные переменные становятся недействительными. У вас может быть ссылка на адрес, но то же пространство памяти может быть заменено некоторыми другими значениями. Вот почему поведение не определено. Если вы хотите ссылаться на память во всей вашей программе, выделите ее с помощью malloc. Это выделит память в куче, а не в стеке. Вы можете безопасно ссылаться на него, пока не освободите память явно.

#include<stdio.h>
#include<stdlib.h>
char * returnAddress();
main()
{
    char *ptr;
    ptr = returnAddress();
    printf("%p\n",ptr);
}

char * returnAddress()
{
    char *x = malloc(sizeof(char));
    printf("%p\n",x);
    return x;
}
1 голос
/ 25 мая 2011

Какое предупреждение?Я получаю ошибку типа (вы возвращаете int *, но тип говорит char *) и предупреждение о возвращении адреса локальной переменной.

Ошибка типа заключается в том, что тип, который вы объявили для функции, является ложью (или статистикой?).

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

1 голос
/ 25 мая 2011

Поскольку вы можете получить доступ к памяти локальной переменной, это не значит, что это правильно. После завершения вызова функции указатель стека возвращается к своей предыдущей позиции в памяти, чтобы вы могли получить доступ к локальным переменным функции, поскольку они не стираются. Но нет никакой гарантии, что такая вещь не подведет (например, ошибка сегментации), или что вы не будете читать мусор.

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