C Переменная сфера Специальный вопрос - PullRequest
0 голосов
/ 17 сентября 2009

Вот особый сценарий, о котором мне неясно (с точки зрения охвата) долгое время.

рассмотрим код

#include <stdio.h>


typedef struct _t_t{
    int x;
    int y;
} t_t;

typedef struct _s_t{
    int a;
    int b;
    t_t t;
}s_t;

void test(s_t & s){
    t_t x = {502, 100};
    s.t = x;
}


int main(){
    s_t s; 
    test(s);

    printf("value is %d, %d\n", s.t.x, s.t.y);
    return 0;
}

вывод

value is 502, 100

Что меня смущает, так это следующее. Декларация

t_t x

объявлено в объеме функционального теста. Итак, из того, что я читал о программировании на C, это должно быть мусором из этой области. Тем не менее он возвращает правильный результат. Это потому что "=" в строке s.t = x; копирует значения x в s.t?

редактировать ---

после некоторых экспериментов

#include <stdio.h>


typedef struct _t_t{
    int x;
    int y;
} t_t;

typedef struct _s_t{
    int a;
    int b;
    t_t t;
}s_t;

void test(s_t & s){
    t_t x = {502, 100};
    t_t * pt = &(s.t);
    pt = &x;
}


int main(){
    s_t s; 
    test(s);

    printf("value is %d, %d\n", s.t.x, s.t.y);
    return 0;
}

на самом деле выводит

value is 134513915, 7446516

как и ожидалось.

Ответы [ 5 ]

7 голосов
/ 17 сентября 2009

Это потому, что "=" в строке s.t = x; копирует значения x в s.t?

Да.

Кстати, это C ++. Вы передали "s" local to main как ссылку на функцию, которая ее модифицирует. Поскольку это ссылка, а не копия, она влияет на "s" вызывающего абонента.

6 голосов
/ 17 сентября 2009
   t_t x = {502, 100};
   s.t = x;

В первом тесте вы указываете компилятору скопировать значение x в s.t - это работает, как и ожидалось. Локальная переменная x выходит из области видимости, но никогда не упоминается вне функции - данные, которые она изначально содержала, копируются в t член локальной переменной main() s. Было бы эффективно то же самое, если бы вы вместо этого написали:

t_t x = {502, 100};
s.t.x = x.x;
s.t.y = x.y;

Во втором тесте вы назначаете указатель на другой указатель, оба из которых объявлены как локальные переменные. Это ничего не дает - значение в s.t остается неинициализированным. Я прокомментировал код, чтобы помочь вам следовать ему:

t_t x = {502, 100}; // local variable x initialized with 502, 100
t_t * pt = &(s.t); // local variable pt initialized with ADDRESS OF s.t
pt = &x; // local variable pt re-assigned to hold address of local variable x

// local variables go out of scope, output parameter s remains unmodified
1 голос
/ 17 сентября 2009

Читать это: Конструкторы копирования по умолчанию и операторы присваивания

Не предоставляя оператор присваивания, структура _s_t будет делать мелкую копию всех своих членов при назначении. Поскольку вы храните все в _t_t по значению, все данные копируются по значению.

Проблема, которую вы описываете, заключается в том, что _t_t содержит указатель на данные.

в случае:

typedef struct _s_t{
        int a;
        int b;
        t_t* t;
}s_t;

void test(s_t & s){
        t_t x = {502, 100};
        s.t = &x;
}

Это может вызвать проблему, поскольку t_t будет уничтожен в конце test (), и в этот момент этот указатель будет недействительным.

ETA: потому что вы добавили больше к вопросу ...

void test(s_t & s){
     t_t x = {502, 100};
     t_t * pt = &(s.t);
     pt = &x;
}

Вы создали другую проблему здесь. То, что там произошло, вы создали указатель на адрес s.t, и это нормально. Однако затем вы переназначили этот указатель так, чтобы он указывал на x (это назначение ничего не сделало для s.t, вы просто меняете то, на что указывает указатель pt) Причина, по которой вывод «как положено», заключается в том, что вы просто читаете неинициализированное состояние структуры.

0 голосов
/ 17 сентября 2009

Назначение копирует значение из одной переменной в другую. Таким образом, хотя оригинальная локальная буква x исчезла, у вас есть копия в s.

Это было бы совсем иначе, если бы вы только что указали указатель на x:

typedef struct _s_t{
        int a;
        int b;
        t_t* t;
}s_t;

void test(s_t & s){
        t_t x = {502, 100};
        s.t = &x;
}

Тогда у вас возникнет проблема: у вас есть только адрес x, но x пропал. Таким образом, у вас есть ссылка на недопустимое место в памяти. Тогда поведение этой программы будет неопределенным.

0 голосов
/ 17 сентября 2009

Ты прав, линия

s.t = x;

скопирует значения.

...