Почему массивы символов теряются при возврате из функции в C ++?

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

Следующий код напечатает:

(null)
5
char* getString() 
{ 
  char arr[] = "SomeText";
  return arr;  
}      

int getInt()
{
    int b = 5;
    return b;
}

int main() 
{ 
  printf("%s", getString());
  printf("\n");
  printf("%d", getInt());

  return 0; 
} 

Обе переменные arr и b создаются в стеке, поэтому они обе должны быть уничтожены по завершении функций. У меня вопрос: почему переменная b не теряется, а переменная arr потеряна?


person No N    schedule 09.11.2019    source источник
comment
неопределенное поведение. Может произойти все, что угодно.   -  person tkausl    schedule 09.11.2019
comment
Разница в том, что функция getInt() возвращает значение, а функция getString() возвращает указатель (... на область памяти, которая была удалена). Попробуйте int *getInts() { int x[2] = {-1, 42}; return x; }   -  person pmg    schedule 09.11.2019
comment
Локальные переменные, которые включают в себя массивы, выходят за пределы области действия и заканчивают свой жизненный цикл, когда функция завершается. Указатели на такие переменные (и вы возвращаете указатель на первый элемент массива) станут недействительными, как только функция завершится.   -  person Some programmer dude    schedule 09.11.2019
comment
Локальная переменная b потеряна, но ее значение возвращается функцией. Будет такая же ситуация, как и с arr, если вы вернете указатель на b.   -  person Weather Vane    schedule 09.11.2019
comment
В C ++ мы решаем эту проблему, возвращая std::string. Указатели - это строительные блоки для классов. std::string, вероятно, содержит несколько указателей внутри. Тебя это не волнует.   -  person MSalters    schedule 09.11.2019
comment
Насколько я понимаю, память, используемая переменной b, может использоваться для чего угодно. Если это произойдет, я также потеряю переменную b. @pmg Почему значение не теряется?   -  person No N    schedule 09.11.2019
comment
Предположим, что передача вещей между функциями осуществляется с помощью конвертов. Когда getInt() достигает оператора return b;, он помещает внутрь конверта значение, содержащееся в переменной b в то время. Функция getString() помещает внутрь конверта что-то вроде 0xdeadbeef (распавшийся arr).   -  person pmg    schedule 09.11.2019
comment
Обе функции возвращают значения. getInt() возвращает целочисленное значение, а getString() возвращает значение char*. К сожалению, возвращаемое значение char* - это адрес массива, который вышел за пределы области видимости и больше не существует.   -  person Blastfurnace    schedule 09.11.2019
comment
Посмотрите здесь. Теперь посмотрите здесь.   -  person n. 1.8e9-where's-my-share m.    schedule 09.11.2019


Ответы (2)


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

Разыменование адреса объекта с автоматическим временем хранения, который больше не входит в область действия, приводит к неопределенному поведению.

Когда вы возвращаете значение из функции, вызывающей стороне возвращается копия значения.

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

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


Есть 3 исключения: (1) как операнд для &; (2) Как операнд sizeof; и (3) строковый литерал, используемый для инициализации массива. В C ++ есть и другие исключения: (4) как операнд decltype; (5) Как аргумент функции для ссылочного параметра; (6) объект для инициализации ссылочной переменной; ... наверное что-то еще забываю ...

person jxh    schedule 09.11.2019

Оба getInt и getString возвращают значение.

getInt возвращает int значение 5. В вызывающей программе остается 5.

getString возвращает значение char *, указывающее на arr. В то время как вызывающий объект получает указатель, то, на что он указывает, arr, больше не существует (в модели вычислений стандарта C), когда функция возвращается.

Таким образом, проблема заключается не в значении, возвращаемом функцией, а в его значении. Число 5 сохраняет свое значение. Указатель на вещь, которая перестает существовать, не сохраняет своего значения.

person Eric Postpischil    schedule 09.11.2019