使用传递引用/解除引用的奇怪行为

问题描述 投票:1回答:2

这是我的演示代码:

#include <stdio.h>

#define WORK 0

typedef struct FooStruct {
    int x;
} FooStruct;

void setX(FooStruct *foo_ptr) {
    FooStruct foo = *foo_ptr;

    if (WORK) {
        foo_ptr->x = 10;
    } else {
        foo.x = 10;
    }
}

FooStruct makeFoo() {
    FooStruct foo = { 0 };

    setX(&foo);

    return foo;
}

int main(void) {
    FooStruct foo = makeFoo();

    printf("X = %d\n", foo.x);

    return 0;
}

如果WORK定义为1,则代码按预期执行并打印“X = 10”。

但是,如果WORK设置为0,则它​​会打印“X = 0”,或者如果FooStruct没有默认初始化(即将FooStruct foo = {}更改为FooStruct foo;),则valgrind将抛出一个未初始化的错误值printf线。

我确信这是由于我的理解存在差距,但对我来说,两个不同的WORK分支在操作上应该基本相同,所以我不确定误解的来源。

这是使用带有/不带valgrind的gcc 8.2.0编译的,结果相同。

=======================

编辑:

简化示例:

#include <stdio.h>

#define WORK 0

void setX(int *x_ptr) {
    if (WORK) {
        *x_ptr = 5;
    } else {
        int x = *x_ptr;
        x = 5;
    }
}

int main(void) {
    int x = 0;
    setX(&x);

    printf("X = %d\n", x);

    return 0;
}
c pass-by-reference dereference
2个回答
3
投票

当你#define WORK 0时,代码似乎正如预期的那样工作。如果在结构的副本中设置成员,则不应期望修改原始成员。

你有:

void setX(FooStruct *foo_ptr) {
    FooStruct foo = *foo_ptr;

    if (WORK) {
        foo_ptr->x = 10;    // Modify the structure pointed to by foo_ptr
    } else {
        foo.x = 10;         // Modify the local copy of the structure
    }
}

因为你已经制作了一个MCVE(Minimal, Complete, Verifiable Example - 谢谢!),所以在setX()中没有完成结构的修改副本。


3
投票

在这个功能:

void setX(FooStruct *foo_ptr) {
    FooStruct foo = *foo_ptr;

    if (WORK) {
        foo_ptr->x = 10;
    } else {
        foo.x = 10;
    }
}

fooFooStruct类型的局部变量。因此,函数在foo上执行的任何修改都不会产生在函数外部可见的任何效果。

使用foo指向的FooStruct内容的副本初始化foo_ptr是无关紧要的。特别是,它不会使函数的本地foo成为foo_ptr指向的别名。

另一方面,如果函数修改了foo_ptr指向的对象,那么当然可以直接或间接地看到任何其他可以看到该对象的代码。

© www.soinside.com 2019 - 2024. All rights reserved.