遍历 C 指针列表:奇怪的 printf 行为
Traversing C pointer list: weird printf behaviour
我声明了一个用C实现的链表如下:
struct node_List {
int i;
char * name;
struct node_List* next;
};
typedef struct node_List nodeList;
然后我将列表头全局声明为:
nodeList list; // head of the list - does not contain relevant data
最后,我有一个函数 id(char * s)
,其中一个字符串 s
作为唯一的参数。
nodeType id(char *s)
{
nodeType *p; // another List type
if ((p = malloc(sizeof(nodeType))) == NULL) {
// error: out of memory;
}
nodeList * node = &list;
// printf(" ");
while (node->next != NULL){
node = node->next;
if (strcmp(node->name, s) == 0){
// printf(" ");
// assign node to an attribute in p
return p;
}
}
// error: not found;
}
问题是,当我 运行 这个程序并调用 foo("somestring")
程序执行 error: not found
部分并中止执行时,尽管字符串 somestring
在列表。
为了调试目的,我尝试通过插入一些 printf()
来执行完全相同的程序,并且它工作得很好,除了它会在输出的同时打印其他字符。
每次我添加一些打印行时都会发生这种情况,例如如果我取消注释我在上面的例子中写的两个 printf()
s(其中一个或两个,我得到相同的成功结果)。如果调用 printf 时不带参数或使用空字符串 ""
.
则它不起作用
我不知道发生了什么,我仔细检查了列表创建和填充函数,我完全确定它们工作正常。我尝试更改 while
中断条件,但这也不起作用。我在 Linux(使用 gcc)和 Windows(使用 CodeBlocks 编辑器的集成编译器)
上观察到了类似的行为
printf 指令怎么会对程序产生如此大的影响?
编辑:此代码是用 Yacc 编写的语法分析器的一部分。整个代码可以在下面找到。这是一篇很长的文章,还没有完成,但是上面的代码已经过测试并按照解释的那样工作。
查看提供的源代码时,探索链表的算法在while-loop比较中有两种遗漏节点的方法。
方式 1 - 仅从列表的第二个节点开始。
在比较之前放置 node = node->next;
将强制第一个比较为 &(list)->next
而不是 &(list)
。
To start from the first node, simply place node = node->next;
after
the comparison.
方式 2 - 永远不会结束到列表的最后一个节点。
在 while 条件中使用 (node->next != NULL)
将在比较最后一个节点之前强制退出循环 => node->next = NULL;
.
To end by the last node, simply change the while condition to (node != NULL)
.
解法:
while (node != NULL){ // end from the last node
if (strcmp(node->name, s) == 0){
// printf(" ");
// assign node to an attribute in p
return p;
}
node = node->next; // explore link after comparison
}
实际错误是函数 return 编辑的变量类型声明错误:
nodeType* createPoint(char* l){
nodeList* p;
if((p=malloc(sizeof(nodeList))) == NULL){
yyerror("out of memory");
} else {
// do stuff with p
}
return p;
}
函数 return 的值是 nodeType*
并且 p 被实例化为 nodeList*
。
这两种类型的声明非常简单,这就是程序可以运行的原因。
可以找到工作代码here。
printf()
的奇怪行为可能是由 printf 参数所需的堆 space 引起的:由于此函数接受任意数量的参数,因此它将它们保存在列表中。这个列表在堆中实例化,那里覆盖了因 createPoint
.
的错误实现而留下的旧数据
我声明了一个用C实现的链表如下:
struct node_List {
int i;
char * name;
struct node_List* next;
};
typedef struct node_List nodeList;
然后我将列表头全局声明为:
nodeList list; // head of the list - does not contain relevant data
最后,我有一个函数 id(char * s)
,其中一个字符串 s
作为唯一的参数。
nodeType id(char *s)
{
nodeType *p; // another List type
if ((p = malloc(sizeof(nodeType))) == NULL) {
// error: out of memory;
}
nodeList * node = &list;
// printf(" ");
while (node->next != NULL){
node = node->next;
if (strcmp(node->name, s) == 0){
// printf(" ");
// assign node to an attribute in p
return p;
}
}
// error: not found;
}
问题是,当我 运行 这个程序并调用 foo("somestring")
程序执行 error: not found
部分并中止执行时,尽管字符串 somestring
在列表。
为了调试目的,我尝试通过插入一些 printf()
来执行完全相同的程序,并且它工作得很好,除了它会在输出的同时打印其他字符。
每次我添加一些打印行时都会发生这种情况,例如如果我取消注释我在上面的例子中写的两个 printf()
s(其中一个或两个,我得到相同的成功结果)。如果调用 printf 时不带参数或使用空字符串 ""
.
我不知道发生了什么,我仔细检查了列表创建和填充函数,我完全确定它们工作正常。我尝试更改 while
中断条件,但这也不起作用。我在 Linux(使用 gcc)和 Windows(使用 CodeBlocks 编辑器的集成编译器)
printf 指令怎么会对程序产生如此大的影响?
编辑:此代码是用 Yacc 编写的语法分析器的一部分。整个代码可以在下面找到。这是一篇很长的文章,还没有完成,但是上面的代码已经过测试并按照解释的那样工作。
查看提供的源代码时,探索链表的算法在while-loop比较中有两种遗漏节点的方法。
方式 1 - 仅从列表的第二个节点开始。
在比较之前放置 node = node->next;
将强制第一个比较为 &(list)->next
而不是 &(list)
。
To start from the first node, simply place
node = node->next;
after the comparison.
方式 2 - 永远不会结束到列表的最后一个节点。
在 while 条件中使用 (node->next != NULL)
将在比较最后一个节点之前强制退出循环 => node->next = NULL;
.
To end by the last node, simply change the while condition to
(node != NULL)
.
解法:
while (node != NULL){ // end from the last node
if (strcmp(node->name, s) == 0){
// printf(" ");
// assign node to an attribute in p
return p;
}
node = node->next; // explore link after comparison
}
实际错误是函数 return 编辑的变量类型声明错误:
nodeType* createPoint(char* l){
nodeList* p;
if((p=malloc(sizeof(nodeList))) == NULL){
yyerror("out of memory");
} else {
// do stuff with p
}
return p;
}
函数 return 的值是 nodeType*
并且 p 被实例化为 nodeList*
。
这两种类型的声明非常简单,这就是程序可以运行的原因。
可以找到工作代码here。
printf()
的奇怪行为可能是由 printf 参数所需的堆 space 引起的:由于此函数接受任意数量的参数,因此它将它们保存在列表中。这个列表在堆中实例化,那里覆盖了因 createPoint
.