Как не «возвращать адрес локальной переменной» при изменении копии структуры?

У меня есть структура:

struct mystruct {
        int a;
};

Если я создаю функцию со структурой в качестве аргумента, и попробуйте напрямую вернуть его адрес:

struct mystruct *
modifystruct1(struct mystruct s)
{
        s.a = 5;
        return &s;
}

Компиляция с c99 -Wall -Wextra -pedantic предупредит warning: function returns address of local variable [-Wreturn-local-addr], чего я знаю, что не должен делать.

Однако, если я сохраню адрес в другую переменную и попробуйте вернуть это, предупреждение исчезнет:

struct mystruct *
modifystruct2(struct mystruct s)
{
        struct mystruct *sptr = &s;
        sptr->a = 5;
        return sptr;
}

Это нормально или ничем не отличается от вышеописанного? (и если да, то почему больше нет предупреждений?)

Если нет, как я могу изменить копию структуры внутри функции и вернуть указатель на эту структуру, безопасно, желательно без использования malloc?

Да. Попросите вызывающую сторону предоставить буфер «копии» в качестве второго параметра в вызове функции и ничего не возвращать (или, возможно, какое-то указание на успех или неудачу).

Fe2O3 12.02.2023 22:14

Просто отпустите указатель и верните struct mystruct modifystruct2(){ .... return s; }

Andrew Henle 12.02.2023 22:16

Если передано struct, почему вы не можете вернуть его (вместо указателя)? struct mystruct t = s; t.a = 5; return t;

Weather Vane 12.02.2023 22:20

После редактирования Q вы по-прежнему возвращаете указатель на локальную переменную.

Weather Vane 12.02.2023 22:23

Кстати: копирование больших структур в стек / из стека неэффективно.

Fe2O3 12.02.2023 22:26

@ Fe2O3 Копирование больших структур также неэффективно, когда они находятся в куче.

n. m. 12.02.2023 22:59

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

Fe2O3 12.02.2023 23:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
78
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

  1. Передайте ссылку на структуру вместо самой структуры (но это изменит исходную структуру)
struct mystruct *
modifystruct2(struct mystruct *s)
{
        s->a = 5;
        return s;
}
  1. Динамически выделять новую структуру
struct mystruct *
modifystruct2(struct mystruct s)
{
        struct mystruct *sptr = malloc(sizeof(*sptr));

        if (sptr)
        {
            *sptr = s;
            sptr->a = 5;
        }
        return sptr;
}

или не передавать всю структуру в функцию

struct mystruct *
modifystruct2(struct mystruct *s)
{
        struct mystruct *sptr = malloc(sizeof(*sptr));
        if (sptr)
        {
            *sptr = *s;
            sptr->a = 5;
        }
        return sptr;
}
  1. вернуть структуру по значению
struct mystruct 
modifystruct2(struct mystruct s)
{
        s.a = 5;
        return s;
}

Будет ли static продолжительность хранения приемлемым вариантом?

Haris 13.02.2023 01:55

@Haris нет, это делает функцию нереентерабельной

0___________ 13.02.2023 11:19

при вызове функции:modifystruct2(&s); (передайте адрес структуры) Я бы использовал typedefstruct.

void modifystruct2(struct mystruct *s)
{
        s->a = 5;
        return ;
}

Что делать, если не хочет изменять исходную структуру?

0___________ 12.02.2023 22:20

@0___________ Тогда ОП должен переименовать modifystruct() в copyandmodifystruct().

Andrew Henle 12.02.2023 22:36
Ответ принят как подходящий

Это нормально или ничем не отличается от вышеописанного? (и если так, почему больше нет предупреждений?)

На самом деле это то же самое. После выхода из функции

struct mystruct *
modifystruct2(struct mystruct s)
{
        struct mystruct *sptr = &s;
        sptr->a = 5;
        return sptr;
}

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

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

Обратите внимание, что параметр функции не имеет смысла, так как он сразу изменяется внутри функции.

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

void modifystruct2(struct mystruct *s)
{
        s->a = 5;
}

Если вы хотите создать объект структурного типа внутри функции и вернуть его, то определите функцию, например, следующим образом

struct mystruct modifystruct2( void )
{
        struct mystruct s = { .a = 5 };
        return s;
}

Другие вопросы по теме