在结构中分配内存时出现不可预测的行为
Unpredictable behaviour while allocating memory in struct
我是 C 的新手,想了解内存分配和指针的工作原理。但是我为我的代码的一些奇怪行为而苦苦挣扎。请参阅下面的代码和输出。我正在使用 mingw,gcc 版本 4.9.2 (tdm-1),不确定这是一个错误还是我遗漏了什么?发送结构 to/from 函数的正确方法是正确的吗?可以简单地将静态分配的数组分配给指针吗?顺便说一句,没有来自 gcc 的警告。
#include <stdlib.h>
#include <stdio.h>
typedef struct S {
int *a;
} s_t;
s_t
create_s () {
s_t s;
s.a = malloc ( sizeof ( int ) * 5 );
for ( int i = 0; i < 5; ++i ) {
s.a [ i ] = i << 1;
}
return s;
}
void
fill_s ( s_t s ) {
for ( int i = 0; i < 5; ++i ) {
s.a [ i ] = i;
}
}
void
kill_s ( s_t s ) {
free ( s.a );
}
void
fill1_s_from_const ( s_t s ) {
int array [ 5 ] = { 11, 21, 31, 41, 51 };
s.a = array;
}
s_t
fill2_s_from_const () {
int array [ 5 ] = { 12, 22, 32, 42, 52 };
s_t s;
s.a = array;
return s;
}
void
copy_s_from_const ( s_t s ) {
int array [ 5 ] = { 111, 222, 333, 444, 555 };
for ( int i = 0; i < 5; ++i ) {
s.a [ i ] = array [ i ];
}
}
int
main () {
s_t s = create_s ();
printf ( "\ncreate_s\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
fill_s ( s );
printf ( "\nfill_s\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
copy_s_from_const ( s );
printf ( "\ncopy_s_from_const\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
kill_s ( s );
// not working at all (array filled with garbage)
fill1_s_from_const ( s );
printf ( "\nfill1_s_from_const\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
// works partly (array filled correctly but some fields are still full of garbage)
s = fill2_s_from_const ();
printf ( "\nfill2_s_from_const\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
// same as fill1_s_from_const or fill2_s_from_const (imo) but works perfectly fine
int b [ 5 ] = { 11, 22, 33, 44, 55 };
s.a = b;
printf ( "\ninline\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
}
Output
void
fill1_s_from_const ( s_t s ) {
int array [ 5 ] = { 11, 21, 31, 41, 51 };
s.a = array;
}
结构是按值传递的,所以这个函数什么都不做。在你调用它之后,调用者的 s.a
仍然是之前的样子,在你的例子中是指向你刚刚释放的内存的指针。
s_t
fill2_s_from_const () {
int array [ 5 ] = { 12, 22, 32, 42, 52 };
s_t s;
s.a = array;
return s;
}
通过引用将数组分配给指针,因此调用此函数会导致在 s.a
.
中为调用者提供一个悬空指针
// same as fill1_s_from_const or fill2_s_from_const (imo) but works perfectly fine
int b [ 5 ] = { 11, 22, 33, 44, 55 };
s.a = b;
printf ( "\ninline\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
之所以有效,是因为与 fill2_s_from_const
不同,指针在您在这里使用之前不会悬空。
好的,我知道了。
fill_s 有效,因为我按值发送 s 所以 fill_s 中的 s.a 与 main 中的 s.a 具有相同的值(指向相同的内存块) ,而两个 s 都是单独的结构实例。
fill1_s_from_const 的工作方式不同,因为我将值分配给在函数调用时创建的本地 s.a,它与 main 中的 s.a 不同(值是).如果 s 将作为指针传递,函数将作为 fill2_s_from_const 工作。
fill2_s_from_const 只是将指向本地内存块的指针设置为 s.a。当程序 returns 回到主程序时,存储在其中的数据已经被破坏(在我的情况下 - 部分,这让我感到困惑)。
抱歉这个愚蠢的问题(无法删除)。
我是 C 的新手,想了解内存分配和指针的工作原理。但是我为我的代码的一些奇怪行为而苦苦挣扎。请参阅下面的代码和输出。我正在使用 mingw,gcc 版本 4.9.2 (tdm-1),不确定这是一个错误还是我遗漏了什么?发送结构 to/from 函数的正确方法是正确的吗?可以简单地将静态分配的数组分配给指针吗?顺便说一句,没有来自 gcc 的警告。
#include <stdlib.h>
#include <stdio.h>
typedef struct S {
int *a;
} s_t;
s_t
create_s () {
s_t s;
s.a = malloc ( sizeof ( int ) * 5 );
for ( int i = 0; i < 5; ++i ) {
s.a [ i ] = i << 1;
}
return s;
}
void
fill_s ( s_t s ) {
for ( int i = 0; i < 5; ++i ) {
s.a [ i ] = i;
}
}
void
kill_s ( s_t s ) {
free ( s.a );
}
void
fill1_s_from_const ( s_t s ) {
int array [ 5 ] = { 11, 21, 31, 41, 51 };
s.a = array;
}
s_t
fill2_s_from_const () {
int array [ 5 ] = { 12, 22, 32, 42, 52 };
s_t s;
s.a = array;
return s;
}
void
copy_s_from_const ( s_t s ) {
int array [ 5 ] = { 111, 222, 333, 444, 555 };
for ( int i = 0; i < 5; ++i ) {
s.a [ i ] = array [ i ];
}
}
int
main () {
s_t s = create_s ();
printf ( "\ncreate_s\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
fill_s ( s );
printf ( "\nfill_s\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
copy_s_from_const ( s );
printf ( "\ncopy_s_from_const\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
kill_s ( s );
// not working at all (array filled with garbage)
fill1_s_from_const ( s );
printf ( "\nfill1_s_from_const\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
// works partly (array filled correctly but some fields are still full of garbage)
s = fill2_s_from_const ();
printf ( "\nfill2_s_from_const\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
// same as fill1_s_from_const or fill2_s_from_const (imo) but works perfectly fine
int b [ 5 ] = { 11, 22, 33, 44, 55 };
s.a = b;
printf ( "\ninline\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
}
Output
void
fill1_s_from_const ( s_t s ) {
int array [ 5 ] = { 11, 21, 31, 41, 51 };
s.a = array;
}
结构是按值传递的,所以这个函数什么都不做。在你调用它之后,调用者的 s.a
仍然是之前的样子,在你的例子中是指向你刚刚释放的内存的指针。
s_t
fill2_s_from_const () {
int array [ 5 ] = { 12, 22, 32, 42, 52 };
s_t s;
s.a = array;
return s;
}
通过引用将数组分配给指针,因此调用此函数会导致在 s.a
.
// same as fill1_s_from_const or fill2_s_from_const (imo) but works perfectly fine
int b [ 5 ] = { 11, 22, 33, 44, 55 };
s.a = b;
printf ( "\ninline\n" );
for ( int i = 0; i < 5; ++i ) {
printf ( "%d\n", s.a [ i ] );
}
之所以有效,是因为与 fill2_s_from_const
不同,指针在您在这里使用之前不会悬空。
好的,我知道了。
fill_s 有效,因为我按值发送 s 所以 fill_s 中的 s.a 与 main 中的 s.a 具有相同的值(指向相同的内存块) ,而两个 s 都是单独的结构实例。
fill1_s_from_const 的工作方式不同,因为我将值分配给在函数调用时创建的本地 s.a,它与 main 中的 s.a 不同(值是).如果 s 将作为指针传递,函数将作为 fill2_s_from_const 工作。
fill2_s_from_const 只是将指向本地内存块的指针设置为 s.a。当程序 returns 回到主程序时,存储在其中的数据已经被破坏(在我的情况下 - 部分,这让我感到困惑)。
抱歉这个愚蠢的问题(无法删除)。