遍历 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 编写的语法分析器的一部分。整个代码可以在下面找到。这是一篇很长的文章,还没有完成,但是上面的代码已经过测试并按照解释的那样工作。

词法分析器:http://pastebin.com/1TEzzHie

解析器:http://pastebin.com/vwCtMhX4

查看提供的源代码时,探索链表的算法在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.

的错误实现而留下的旧数据