std::transform не работает для статически выделенной строки

#c #std

#c #std

Вопрос:

Может кто-нибудь помочь мне понять, почему это не работает?

 #include <vector>
#include <algorithm>

using namespace std;

struct person {
    int age;
    char name[30];
};

int main()
{
    vector<person> persons(2);
    vector<char*> names(2);
    
    persons[0].age = 1; 
    strcpy_s(persons[0].name, "mike");
    persons[1].age = 11; 
    strcpy_s(persons[1].name, "pol");
    transform(persons.begin(), persons.end(), names.begin(), 
        [](person p) -> char* {return p.name; });
    // ... names gets the same wrong pointer for both elements
}
  

[Отредактировано, чтобы удалить ненужные неправильные догадки]

Комментарии:

1. Этот код не компилируется. strcpy_s принимает 3 аргумента, но 2 заданы.

2. Проблема не только strcpy_s в этом . Все современные компиляторы C достаточно умны, чтобы сказать вам, в чем заключается основная ошибка в показанном коде. Это пример того, как никогда не игнорировать сообщения от вашего компилятора. Даже если ему удается скомпилировать показанный код, предупреждающие сообщения почти всегда являются гарантией того, что у вас ошибка. Обратите внимание на предупреждающее сообщение вашего компилятора.

3. godbolt.org/z/WKoxd9

4. Когда вы пишете C , используйте функции C и не используйте код, как если бы это был код C. В этом случае используйте std::string .

5. Это прискорбно. gcc выдает очень понятное «предупреждение: возвращен адрес локальной переменной ‘p’», в чем и заключается проблема, как описано в ответе.

Ответ №1:

В этом лямбда-выражении:

 [](person p) -> char* { return p.name; }); 
  

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

Вместо этого вы могли бы вернуть указатель на элемент ссылки:

 [](person amp; p) -> char* { return p.name; });
       // ^
  

Эти указатели действительны до тех пор, пока persons указывают на одну и ту же базовую память. Изменение persons таким образом, что указатели на него становятся недействительными, очевидно, приведет к аннулированию указателей names .