c - 结构体字段中的数组在返回时是否始终保留?

标签 c memory struct return c99

我知道我无法从函数返回本地声明的数组,因为该数组位于函数的堆栈空间中,返回后,指针将悬空。

无效

int* test() {
    int x[3] = {1,2,3};
    return x;
}

main() {
    int* x = test();
}

因此,我对返回包含数组的结构感到紧张;由于它们只是结构体连续内存空间的一部分,因此在返回时会被复制。

即这完全没问题

typedef struct Container {
    int arr[3][3];
} Container;
Container getContainer() {
    Container c = {.arr = {{1,2,3}, {4,5,6}, {7,8,9}} };
    return c;
}

int main() {
    Container c = getContainer();
    // c.arr is "deep copied" to main's stack space
}

不过,我有一种强烈的本能去做类似的事情

void populateContainer(Container* c) {
    int arr[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
    memcpy(c->arr, arr, 3*3 * sizeof(arr));
}

int main() {
    Container c;
    populateContainer(&c);
}

所以我的问题是,我是否应该相信在返回结构时数组将始终安全地按值复制,并避免后一种模式?我一直使用 C99 标准。是否有编译器不尊重这一点,而我应该使用更丑陋但看起来更安全的地址传递模式?

最佳答案

根据6.9.1p3 :

The return type of a function shall be void or an object type other than array type.

关于对象类型的定义,来自 6.2.5p1 :

The meaning of a value stored in an object or returned by a function is determined by the type of the expression used to access it. (An identifier declared to be an object is the simplest such expression; the type is specified in the declaration of the identifier.) Types are partitioned into object types (types that fully describe objects), function types (types that describe functions), and incomplete types (types that describe objects but lack information needed to determine their sizes).

另请参阅this question关于对象类型。

<小时/>

总之,因为这是一个有效的对象类型:

struct Container {
    int arr[3][3];
};

如果您的编译器符合标准,即使 Container 是在函数堆栈内创建的,您也可以预期 Container c = getContainer(); 可以正常工作然后返回,因为标准没有指定返回值的来源。

关于c - 结构体字段中的数组在返回时是否始终保留?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57738142/

相关文章:

c - uint32_t 和其他 stdint 类型的 atoi 或 strtoul 等价物是什么?

c - 如何在C中将数组拆分为两个数组

java - 清理内存后Android应用程序崩溃

go - 在编写可能最终被传递给任何类型的结构的函数时,我可以使用接口(interface)作为参数吗?

c - C (Linux) 中的管道问题

c - C 中的一次性伪通用 header

c++ - 在范围内创建指针时,当指针超出范围时,指向的变量会发生什么?

c - x64 处理器上的 C 语法有何不同

c - 指向 C 中结构表的指针

c - C语言struct数组