#c #struct
#c #структура
Вопрос:
Я написал простую функцию, которая находит самого старого пользователя в массиве структур. В структуре хранится информация о возрасте и имени.
#include <iostream>
struct Person
{
int age;
char name[16];
};
char* oldest(Person* arr, int len)
{
int max = 0;
char* ptr = nullptr;
Person elem;
for (int i = 0; i < len; i )
{
elem = arr[i];
if (max < elem.age)
{
max = elem.age;
ptr = arr[i].name;
}
}
return ptr;
}
int main()
{
Person list[3] = {
{20, "Alice"},
{70, "Bob"},
{25, "James"}
};
std::cout << oldest(list, 3) << 'n';
}
Это дает правильный результат (а именно я вижу Bob
на экране), но когда я использую elem
вместо arr[i]
в строке ptr = arr[i].name;
(что не что иное, как присвоение другого имени arr[i]
, верно ??) программа внезапно начинает выдавать какие-то странные результаты (непечатаемые символы). Я понятия не имею, почему он так себя ведет.
Для справки, это код, который не работает:
char* oldest(Person* arr, int len)
{
int max = 0;
char* ptr = nullptr;
Person elem;
for (int i = 0; i < len; i )
{
elem = arr[i];
if (max < elem.age)
{
max = elem.age;
ptr = elem.name;
}
}
return ptr;
}
Комментарии:
1. пожалуйста, опубликуйте код, в котором есть проблема, а не тот, который в порядке.
2. @largest_prime_is_463035818 ок
3.
Person elem;
это «копия», которую вы хотите/*const*/Personamp; elem = arr[i];
использовать в качестве псевдонима.4.
elem = arr[i]
присваиваетсяelem
как копияarr[i]
. Butelem
является локальной переменной с автоматической продолжительностью хранения, поэтому она (и ее содержимое) перестают существовать при возврате функции. Еслиptr
указывает на (первый символ)elem.name
, вызывающий получает висячую ссылку, то есть указатель на что-то, чего больше не существует. Разыменование этого указателя вызывающим объектом (например, доступ к массиву, который больше не существует) приводит к неопределенному поведению. Для сравнения,arr
передается вызывающей стороной, поэтому все еще существует после возврата функции.
Ответ №1:
ptr = elem.name;
присваивает ptr
адрес первому элементу elem.name
(поскольку архив elem.name
автоматически преобразуется в указатель на его первый элемент). elem.name
конечно, это внутренний массив elem
и elem
объект с автоматическим сроком хранения, что означает, что он создается автоматически в блоке, в котором он определен, и уничтожается при завершении выполнения этого блока. Итак, когда функция возвращает, elem
перестает существовать в модели вычислений C , и указатель на ее часть становится недействительным.
… это не что иное, как присвоение другого имени arr[i], верно??
Нет, в заявлении elem = arr[i];
содержится копия arr[i]
elem
В. Это не создает elem
альтернативного имени для arr[i]
. Эта копия перестает существовать, когда функция возвращается.
Если бы вы удалили Person elem;
объявление и внутри цикла использовали Person amp;elem = arr[i];
вместо elem = arr[i];
, это определило elem
бы как ссылку на arr[i]
. Тогда это было бы фактически альтернативным именем для arr[i]
, и ptr = elem.name;
было бы установлено ptr
, чтобы указывать на первый элемент arr[i].name
.
Ответ №2:
(это не что иное, как присвоение другого имени arr[i], верно??)
Не правильно. elem
это отдельный объект. Это не имя arr[i]
.
но когда я использую elem вместо arr[i] в строке ptr = arr[i].name; … программа внезапно начинает выдавать какие-то странные результаты
С этим изменением вы возвращаете указатель на (член) автоматической переменной. Когда функция возвращается, автоматическая переменная уничтожается, а возвращенный указатель будет недействительным. Когда вы проходите через недопустимый указатель и пытаетесь получить доступ к освобожденной памяти, производительность программы не определена.