У меня есть структура:
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
?
Просто отпустите указатель и верните struct mystruct modifystruct2(){ .... return s; }
Если передано struct
, почему вы не можете вернуть его (вместо указателя)? struct mystruct t = s; t.a = 5; return t;
После редактирования Q вы по-прежнему возвращаете указатель на локальную переменную.
Кстати: копирование больших структур в стек / из стека неэффективно.
@ Fe2O3 Копирование больших структур также неэффективно, когда они находятся в куче.
@н.м. OP, кажется, хочет, чтобы вызывающий абонент в конечном итоге получил оригинал и измененную копию данных. Являются ли они «локальными переменными» (для вызывающей стороны) или в куче, зависит от вызывающей стороны. Передача/копирование больших кусков данных в/из функций неэффективно. Я думаю, мы говорим об одном и том же.
struct mystruct *
modifystruct2(struct mystruct *s)
{
s->a = 5;
return s;
}
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;
}
struct mystruct
modifystruct2(struct mystruct s)
{
s.a = 5;
return s;
}
Будет ли static
продолжительность хранения приемлемым вариантом?
@Haris нет, это делает функцию нереентерабельной
при вызове функции:modifystruct2(&s); (передайте адрес структуры) Я бы использовал typedefstruct.
void modifystruct2(struct mystruct *s)
{
s->a = 5;
return ;
}
Что делать, если не хочет изменять исходную структуру?
@0___________ Тогда ОП должен переименовать modifystruct()
в copyandmodifystruct()
.
Это нормально или ничем не отличается от вышеописанного? (и если так, почему больше нет предупреждений?)
На самом деле это то же самое. После выхода из функции
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;
}
Да. Попросите вызывающую сторону предоставить буфер «копии» в качестве второго параметра в вызове функции и ничего не возвращать (или, возможно, какое-то указание на успех или неудачу).