[英]Why does this basic linked list work on MacOS but seg fault on Linux
I have a linked list lib I use occasionally on MacOS and I just tried using it on Linux and I'm getting all sorts of problems.我有一个偶尔在 MacOS 上使用的链表库,我只是尝试在 Linux 上使用它,但遇到了各种各样的问题。 I've broken it down into a much simpler version to get to the problems.
我已经把它分解成一个更简单的版本来解决问题。 I've been able to find where the problems are with
gdb
, I just don't know why they're happening.我已经能够找到
gdb
的问题出在哪里,我只是不知道为什么会这样。 It works fine on MacOs even with address sanitizer.即使使用地址消毒剂,它也可以在 MacO 上正常工作。 I suspect I might be misusing the pointers here somehow.
我怀疑我可能会以某种方式滥用这里的指针。
here's my list structure:这是我的列表结构:
struct node {
int value;
struct node *next;
};
typedef struct node node_t;
struct list {
node_t *head;
};
typedef struct list list_t;
And the functions:和功能:
void list_init(list_t *l)
{
l = malloc(sizeof(list_t));
assert(l);
l->head = NULL;
}
static node_t *new_node(int value)
{
node_t *new = malloc(sizeof(node_t));
assert(new);
new->value = value;
new->next = NULL;
return new;
}
void push(list_t *l, int value)
{
node_t *node = new_node(value);
if (l->head == NULL) {
l->head = node;
} else {
node->next = l->head;
l->head = node;
}
}
void print_list(list_t *l)
{
node_t *tmp = l->head;
while (tmp) {
printf("%d\n", tmp->value);
tmp = tmp->next;
}
}
main function:主要 function:
int main()
{
list_t *l;
list_init(l);
push(l, 2);
push(l, 4);
push(l, 6);
print_list(l);
return 0;
}
gdb
is telling me that the NULL check in the push function ( if (l->head == NULL)
) is causing the set fault. gdb
告诉我 NULL 检查推送 function ( if (l->head == NULL)
) 导致设置错误。 But it's also telling me that l->head
is indeed NULL.但它也告诉我
l->head
确实是 NULL。 If i remove that, the seg fault just happens in the next place wherever l->head
is called.如果我删除它,则段错误只会发生在调用
l->head
的下一个位置。
If i instead I don't declare my list as a pointer...like this:相反,如果我不将我的列表声明为指针...像这样:
int main()
{
list_t l;
list_init(&l);
push(&l, 2);
push(&l, 4);
push(&l, 6);
print_list(&l);
return 0;
}
It fixes the issue.它解决了这个问题。 However, it then makes it as far as the
print_list
function.但是,它随后会到达
print_list
function。 It will print the list then print a couple more junk values and then seg fault.它将打印列表,然后打印更多的垃圾值,然后是段错误。
I appreciate any help.我很感激任何帮助。 And I know no memory is freed here.
而且我知道没有 memory 在这里被释放。 Just trying to keep the code small to fix the problem.
只是试图保持代码小以解决问题。
For example this function例如这个 function
void list_init(list_t *l)
{
l = malloc(sizeof(list_t));
assert(l);
l->head = NULL;
}
does not make a sense because the function deals with a copy of the value the argument of the type list_t *
.没有意义,因为 function 处理
list_t *
类型参数的值的副本。
So changing the copy in this statement所以更改此语句中的副本
l = malloc(sizeof(list_t));
does not influence on the original pointer used as an argument.不影响用作参数的原始指针。 So this function in fact invokes undefined behavior.
所以这个 function 实际上调用了未定义的行为。 It does not initialize a list.
它不初始化列表。
So after calling the function as in this code snippet因此,在调用 function 之后,如此代码片段
list_t *l;
list_init(l);
the pointer l
stays uninitialized and has an indeterminate value.指针
l
保持未初始化并具有不确定的值。 On the other hand, the function produces a memory leak.另一方面,function 会产生 memory 泄漏。
And nothing is changed in this code snippet此代码段中没有任何更改
list_t l;
list_init(&l);
because within the function list_init
after this statement因为在此语句之后的 function
list_init
内
l = malloc(sizeof(list_t));
the function deals with a dynamically allocated object of the type list_t
instead of the passed by reference object l
declared in main. function 处理类型为
list_t
的动态分配的 object,而不是在 main 中声明的通过引用传递的l
。
To fix the problem define the function list_init
like要解决此问题,请定义 function
list_init
类的
void list_init(list_t *l)
{
assert(l);
l->head = NULL;
}
and call it like并称它为
list_t l;
list_init(&l);
The function push can be written simpler function push 可以写得更简单
int push( list_t *l, int value )
{
node_t *node = new_node( value, l->head );
int success = node != NULL;
if ( success )
{
l->head = node;
}
return success;
}
Correspondingly the function new_node
can be defined like相应地,function
new_node
可以定义为
static node_t * new_node( int value, node_t *next )
{
node_t *node = malloc( sizeof( node_t ) );
if ( node != NULL )
{
node->value = value;
node->next = next;
}
return node;
}
Your list_init
can't possibly work.你的
list_init
不可能工作。 C is pass-by-value, so nothing that list_init
does will have any effect on the pointer variable l
in main()
, which remains full of uninitialized garbage. C 是按值传递的,因此
list_init
所做的任何事情都不会对main()
中的指针变量l
产生任何影响,它仍然充满了未初始化的垃圾。 You ought to get a compiler warning for it (enable -Wall
.!).你应该得到一个编译器警告(启用
-Wall
.!)。
You probably want to have list_init()
return its pointer instead of trying to pass by reference, so:您可能希望
list_init()
返回其指针,而不是尝试通过引用传递,因此:
list_t *list_init(void)
{
list_t *l = malloc(sizeof(list_t));
assert(l);
l->head = NULL;
return l;
}
//...
int main()
{
list_t *l = list_init();
// ...
}
Your second version is likewise broken because when list_init()
assigns to its local variable l
, it just loses the pointer it was passed, so again nothing that it does has any effect on the l
in main
.你的第二个版本同样被破坏了,因为当
list_init()
分配给它的局部变量l
时,它只是丢失了它传递的指针,所以它所做的一切对main
中的l
没有任何影响。 You do not need to allocate anything in this version since you are already passed a pointer to a valid list_t
object.您不需要在此版本中分配任何内容,因为您已经传递了指向有效
list_t
object 的指针。 So if you want to write it this way, then you would simply want所以如果你想这样写,那么你只需要
void list_init(list_t *l)
{
l->head = NULL;
}
// ...
int main()
{
list_t l;
list_init(&l);
// ...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.