Законен ли этот оператор присваивания структуры C?

Вот пример кода, за которым следует мой вопрос:

#include <stdio.h>
#include <string.h>

struct st {

    char stringField[100];
    int intField;
};

typedef struct st st;

void test(st *parameterStruct)
{
    st localStruct;
    strcpy(localStruct.stringField, "HELLO");
    localStruct.intField = 5;

    *parameterStruct = localStruct;
}

int main()
{
    st myStruct;
    strcpy( myStruct.stringField, "XXX" );
    myStruct.intField = 9;

    printf("%s,%i\n", myStruct.stringField, myStruct.intField );

    test(&myStruct);

    printf("%s,%i\n", myStruct.stringField, myStruct.intField);

    return 0;
}

ВЫХОД:

XXX,9
HELLO,5

Я думал, что, поскольку структура «localStruct» была создана внутри функции (НЕ с использованием malloc), она имела локальную область действия, и поэтому области памяти, в которых она хранилась, можно было переопределить после прекращения выполнения функции. Однако я попытался запустить этот образец программы, и он выполнился без проблем. Я думал, что второй оператор печати будет печатать тарабарщину на экране, поскольку я присвоил «myStruct» локальной переменной «localStruct» (в отличие от динамического выделения «localStruct»). Я знаю, что если бы «localStruct» был создан с использованием malloc, таких проблем не было бы.

Мой вопрос: можно ли присваивать структурную переменную myStruct (нединамическая локальная переменная) y с помощью указателя в функциональном тесте, это нормально и безопасно? Я надеюсь, что вопрос ясен.


c
person Rob L    schedule 08.06.2014    source источник
comment
Хорошо написанный вопрос с SSCCE, вы, уважаемый, заслуживаете +1.   -  person Matteo Italia    schedule 08.06.2014
comment
(Только придирка: возможно, заголовок можно улучшить до чего-то менее общего?)   -  person Jongware    schedule 08.06.2014


Ответы (3)


Присвоение всегда копируется.

Если бы вы сделали что-то вроде *x = &y (при условии, что типы совпадают — например, если бы параметр был объявлен как st** x), вы бы скопировали адрес y, но поскольку y скоро выйдет из области видимости, это назначение будет небезопасным, так как ты боялся.

Но поскольку вместо этого вы выполняете *x = y (где параметр объявлен как st* x), вы копируете содержимое y в *x, поэтому даже после того, как y выйдет из области видимости, данные, хранящиеся в *x, должны быть действительными.

person Theodoros Chatzigiannakis    schedule 08.06.2014
comment
Я думаю, вы имеете в виду x = &y, а не *x = &y. По крайней мере, это лучше подходит к вопросу ИМО. Ну, если вы не имеете в виду, что x является указателем на указатель. - person luk32; 08.06.2014
comment
@ luk32 Верно, но это не изменит адрес внешнего выражения, что не продемонстрирует тот факт, что назначенное выражение выходит за рамки области действия. Вот почему я (неудобно) отмахнулся от него, предполагая, что типы действительны. - person Theodoros Chatzigiannakis; 08.06.2014
comment
Да, это верно, чтобы пример не работал, как ожидалось, он должен быть test( st **x ). В 1-м классе было немного запутанно. - person luk32; 08.06.2014
comment
Историческая справка: присвоение структуры было стандартизировано в C89, но отсутствовало в K&R1. Время от времени вы сталкиваетесь с кем-то, кто учился на K&R1 и не знает об этом :) - person M.M; 09.06.2014

Да. Это безопасно.

Когда вы назначаете:

*x = y;

Элементы y копируются в соответствующие элементы *x. Это работает так, как если бы вы копировали себя от члена к члену.

person P.P    schedule 08.06.2014

C разрешить присвоение структуры. Две структуры могут быть назначены, если они имеют совместимый тип. Две структуры, объявленные одновременно, совместимы, и структуры, объявленные с использованием одного и того же «тега структуры» или одного и того же имени типа, также совместимы.

В приведенном вами примере и *x, и y объявлены с использованием одного и того же имени типа структуры st, оба совместимы, и, следовательно, назначение *x = y является допустимым. Поскольку st x в main создает структуру полного типа, передача ее адреса в функцию допустима. В вашей функции назначение *x = y просто копирует содержимое локальной переменной y в *x, и это изменение в *x сохраняется и отражается в x в main.

person haccks    schedule 08.06.2014