指针丢失引用的问题
problem with lost reference with pointers
我正在尝试做一棵 children 和父亲的树,但是当他们出生在一个函数中时,我失去了对孩子的引用,这里将以狗为例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
typedef struct Dog{
int id;
double amound_of_bones;
int *bones;
int *gifts;
struct Dog *other_dog;
}Dog;
void have_children(Dog *father){
Dog pancho;
pancho.id=5;
pancho.amound_of_bones=1544.5;
(*father).other_dog=&pancho;
}
int main(int argc, char *argv[]) {
Dog pepi;
have_children(&pepi);
printf("the dog id: %d, have %f bones\n",(*pepi.other_dog).id,(*pepi.other_dog).amound_of_bones);
printf("the dog id: %d, have %f bones\n",(*pepi.other_dog).id,(*pepi.other_dog).amound_of_bones);
return 1;
}
这是奇怪的输出:
the dog id: 5, have 1544.500000 bones
the dog id: 0, have 0.000000 bones
你会看到第一个输出很好,但另一个失去了参考,我不知道如何解决它
Dog pancho;
是 have_children()
函数中的局部变量。当函数 returns 时,该内存被释放。您保存了指向不再有效的内存的指针。此行为未定义。
在函数have_children
中,变量pancho
是局部变量。这意味着变量的生命周期仅与函数 have_children
一样长。当该函数 returns 时,变量 pancho
不复存在,内存将不再为该对象保留。这意味着内存可以被程序的其他部分使用,这将导致内存被覆盖。
因为您将 pancho
的地址分配给 pepi->other_dog
,所以在 pancho
的生命周期结束后,即在函数 [=11] 之后,该指针将指向一个无效的对象=] return秒。这意味着 pepi->other_dog
将变成 dangling pointer.
取消引用这样的悬空指针会导致 undefined behavior。
第一个printf
调用成功的原因可能是对象的内存还没有被覆盖。第二个 printf
调用给你一个不同的结果,可能是因为内存地址被第一个 printf
调用在内部用于其他东西,所以它被其他一些值覆盖。
要修复此未定义的行为,您必须确保您指向的对象的生命周期不会过早过期。例如,您可以改用函数 malloc
。这样,对象的生命周期将持续到您调用 free
.
这是一个示例,说明如何重写函数 have_children
以使用 malloc
:
#include <assert.h> //this header is required for the "assert" macro used below
void have_children(Dog *father){
Dog *pancho = malloc( sizeof(Dog) );
assert( pancho != NULL );
pancho->id = 5;
pancho->amound_of_bones = 1544.5;
father->other_dog = pancho;
}
assert
宏不是必需的,但检查 malloc
的 return 值以确保它不为 NULL 通常是一个好习惯。
我正在尝试做一棵 children 和父亲的树,但是当他们出生在一个函数中时,我失去了对孩子的引用,这里将以狗为例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
typedef struct Dog{
int id;
double amound_of_bones;
int *bones;
int *gifts;
struct Dog *other_dog;
}Dog;
void have_children(Dog *father){
Dog pancho;
pancho.id=5;
pancho.amound_of_bones=1544.5;
(*father).other_dog=&pancho;
}
int main(int argc, char *argv[]) {
Dog pepi;
have_children(&pepi);
printf("the dog id: %d, have %f bones\n",(*pepi.other_dog).id,(*pepi.other_dog).amound_of_bones);
printf("the dog id: %d, have %f bones\n",(*pepi.other_dog).id,(*pepi.other_dog).amound_of_bones);
return 1;
}
这是奇怪的输出:
the dog id: 5, have 1544.500000 bones
the dog id: 0, have 0.000000 bones
你会看到第一个输出很好,但另一个失去了参考,我不知道如何解决它
Dog pancho;
是 have_children()
函数中的局部变量。当函数 returns 时,该内存被释放。您保存了指向不再有效的内存的指针。此行为未定义。
在函数have_children
中,变量pancho
是局部变量。这意味着变量的生命周期仅与函数 have_children
一样长。当该函数 returns 时,变量 pancho
不复存在,内存将不再为该对象保留。这意味着内存可以被程序的其他部分使用,这将导致内存被覆盖。
因为您将 pancho
的地址分配给 pepi->other_dog
,所以在 pancho
的生命周期结束后,即在函数 [=11] 之后,该指针将指向一个无效的对象=] return秒。这意味着 pepi->other_dog
将变成 dangling pointer.
取消引用这样的悬空指针会导致 undefined behavior。
第一个printf
调用成功的原因可能是对象的内存还没有被覆盖。第二个 printf
调用给你一个不同的结果,可能是因为内存地址被第一个 printf
调用在内部用于其他东西,所以它被其他一些值覆盖。
要修复此未定义的行为,您必须确保您指向的对象的生命周期不会过早过期。例如,您可以改用函数 malloc
。这样,对象的生命周期将持续到您调用 free
.
这是一个示例,说明如何重写函数 have_children
以使用 malloc
:
#include <assert.h> //this header is required for the "assert" macro used below
void have_children(Dog *father){
Dog *pancho = malloc( sizeof(Dog) );
assert( pancho != NULL );
pancho->id = 5;
pancho->amound_of_bones = 1544.5;
father->other_dog = pancho;
}
assert
宏不是必需的,但检查 malloc
的 return 值以确保它不为 NULL 通常是一个好习惯。