Подтвердить что ты не робот

Разве это не устаревший код, который возвращает локальный массив char неправильно?

Я наткнулся на какой-то старый код, который содержит такую ​​функцию:

LPCTSTR returnString()
{
    char buffer[50000];
    LPCTSTR t;

    /*Some code here that copies some string into buffer*/

    t = buffer;
    return t; 
}

Теперь я сильно подозреваю, что это неправильно. Я попытался вызвать функцию, и она возвращает строку, которую вы ожидаете, что она вернется. Тем не менее, я действительно не вижу, как это происходит: не является ли массив char, который должен быть сохранен в стеке, и таким образом освобожден после выхода из функции? Если я ошибаюсь, и он хранится в куче, разве эта функция не создает утечку памяти?

4b9b3361

Ответ 1

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

Ответ 2

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

Правильный способ передачи данных по цепочке вызовов - предоставить буфер и размер функции для заполнения.

Ответ 3

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

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

[Изменить] Чтобы уточнить, он работает, потому что стек не имел возможности вырастить 50 000 байт. Попробуйте изменить его на char buffer[10]; и вызовите некоторые функции после returnString(), и вы увидите, что он поврежден.

Ответ 4

Ваше чувство правильно; код очень неправильный.

Память действительно находится в стеке и исчезает с завершением функции.

Если буфер был статичным, вы могли хотя бы ожидать, что он будет работать для одного вызова за раз (в однопоточном приложении).

Ответ 5

Существует очень мало различий между массивом и указателем на C/С++. Итак, утверждение:

t = buffer;

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

Ответ 6

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

вместо этого вы можете использовать статический буфер:

static char buffer[50000];

который не выделяется в стеке, поэтому указатель на него остается действительным. (очевидно, это не является потокобезопасным).

Ответ 7

Вы правы, код неправильный.:)

Вы должны изучить распределение памяти в C/С++. Данные могут находиться в двух областях: стек и куча. Локальные переменные хранятся в стеке. malloc ed и new ed данные хранятся в куче. Состояние стека является локальным для функции - переменные живут в стеке стека - контейнер, который будет освобожден при возврате функции. Так что указатели сломаются.

Куча глобальна, поэтому все данные хранятся там до явно delet ed или free d программистом. Вы можете положиться на эту область.

Ответ 8

В то время как все думают, что поведение undefined, и в этом случае оно кажется истинным, в таких случаях важно учитывать другие возможности.

Например, перегруженный operator=(const char*) может быть за кулисами, выделяя память требований. Хотя это не так (насколько мне известно) с помощью typedefs Microsoft, важно помнить о таких случаях.

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

Ответ 9

Это опасная ошибка, скрывающаяся в вашем коде. В C и С++ вам запрещено возвращает указатель на данные стека в функции. Это приводит к поведению undefined. Я объясню, почему.

Программа C/С++ работает, нажимая данные в стеке программ и выключая их. Когда вы вызываете функцию, все параметры помещаются в стек, а затем все локальные переменные также помещаются в стек. По мере выполнения программы она может вытолкнуть и поместить больше элементов в стек и в стеке в вашей функции. В вашем примере буфер помещается в стек, а затем t нажимается на стек. Стек может выглядеть так:

  • Предыдущий стек
  • Параметры
  • (другие данные)
  • буфер (50000 байт)
  • t (указатель размера)

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

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

Хорошая новость - это не безнадежно. Существуют автоматические инструменты, которые могут эти ошибки в вашем программном обеспечении и сообщить о них. Они называются статическими инструменты анализа. Sentry является одним из таких примеров программы, которая может сообщить об этом вид дефекта.

Ответ 10

Я согласен с тем, что наиболее похоже на то, что здесь происходит некорректное возвращение адреса автоматической переменной, однако я эхо KevenK, что это не гарантируется, если это С++, как указывает тег. Мы не знаем, что такое LPCTSTR. Что делать, если включенный заголовок содержит что-то вроде этого:

(да, я знаю, это утечка, а не точка)


class LPCTSTR{
private:
  char * foo;

public:
  LPCTSTR & operator=(char * in){
    foo = strdup(in);
  }

  const char * getFoo(){
    return foo;
  }


};