遍历C指针列表:奇怪的printf行为

时间:2017-02-06 19:33:50

标签: c list pointers printf yacc

我声明了一个用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()(其中一个或两个,我得到相同的成功结果)。如果在没有参数或空字符串""的情况下调用printf,它就不起作用。

我无法弄清楚发生了什么,我仔细检查了列表创建和填充函数,我完全确定它们正常工作。我尝试更改while休息条件,但这也不起作用。我在Linux(使用gcc)和Windows(使用CodeBlocks编辑器的集成编译器)上观察到类似的行为

printf指令如何影响程序呢?

编辑:此代码是Yacc编写的语法分析器的一部分。整个代码可以在下面找到。这是一个很长的阅读,并没有完成,但上面的代码已经过测试并用于解释。

lexer:http://pastebin.com/1TEzzHie

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

2 个答案:

答案 0 :(得分:0)

查看提供的源代码时,探索链表的算法有两种方法可以在while循环比较中错过节点。

方式1 - 仅从列表的第二个节点开始。

在比较之前放置node = node->next;会强制第一次比较为&(list)->next而不是&(list)

  

要从第一个节点开始,只需将node = node->next;放在后面   比较。

方式2 - 永远不会以列表的最后一个节点结束。

在while条件下使用(node->next != NULL)将强制退出循环,然后再比较最后一个节点=> node->next = NULL;

  

要以最后一个节点结束,只需将while条件更改为(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
}

答案 1 :(得分:0)

实际错误是函数返回的变量的错误类型声明:

nodeType* createPoint(char* l){
    nodeList* p;

    if((p=malloc(sizeof(nodeList))) == NULL){
         yyerror("out of memory");
    } else {
        // do stuff with p
    }

    return p;
}

函数返回值为nodeType*,p被实例化为nodeList*。 这两种类型的声明非常简单,这就是程序可以运作的原因。

可以找到工作代码here

printf()的奇怪行为可能是由printf参数所需的堆空间引起的:由于此函数接受任意数量的参数,因此将它们保存在列表中。这个列表在堆中实例化,从那里错误的createPoint实现中覆盖旧数据。