堆栈的奇怪行为没有正确弹出

时间:2013-06-06 05:52:35

标签: c stack

我正在尝试刷新我对C的记忆。我有一个简单的程序,它检查文本文件中的HTML标记,以确保它们彼此匹配。我为此使用了一个堆栈。这是有问题的代码:

char *tag, *endTag;
stackADT stack = newStack();
while (!feof(input))
{
    tag = (char *)malloc(sizeof(char));
    tag = getNextTag(input, &line);
    printf("tag is %s\n", tag);     
    if (*(tag + 1) != '/') //if it is not a closing tag
    {
        push(stack, tag);
        printf("%s was pushed\n", tag);
    }
    else
    {
        endTag = (char *)malloc(sizeof(char));
        endTag = pop(stack);
        printf("%s was popped\n", endTag);
        check = doTagsMatch(endTag, tag);
        if (check == 0)
        {
            printf("Error at line %d: %s and %s do not match.\n", line, endTag, tag);
            exit(1);
        }
    }
    free(tag);
}

从包含html,body和p标签的简单文件中输出如下:

tag is <html>
<html> was pushed
tag is <body>
<body> was pushed
tag is <p>
<p> was pushed
tag is </p>
 was popped
Error at line 1:  and </p> do not match.

我知道堆栈本身工作正常,因为我做了一个单独的SSCCE有几个整数,它工作正常。这是我使用endTag的程序中唯一的地方,所以我无法弄清楚为什么它没有从pop获得任何东西。我唯一能想到的是它是某种指针问题(我的堆栈元素是空的*,如果重要的话)。

2 个答案:

答案 0 :(得分:1)

在每次迭代中,您从tag分配getNextTag,然后致电free(tag)。释放tag后,它指向的内存内容不再有效(如果您尝试使用它们,C标准不会定义行为)。

您尚未向我们展示push的定义,但我怀疑它只是记录了传递的值(tag),并没有复制tag指向的内容。因此,当您调用pop时,它会返回按下开始标记时的值tag,但该值是指向不再有效的内存的指针。

要么push必须复制它传递的字符串,要么在从堆栈弹出并且不再需要值之后才能调用free(tag)。 (例如,在弹出标记的else子句的末尾,同时调用free(endTag)free(tag)。请勿在{{1​​}的末尾调用free(tag) }循环。)

此外,这些序列毫无意义且泄漏记忆:

while

在每种情况下,tag = (char *)malloc(sizeof(char)); tag = getNextTag(input, &line); endTag = (char *)malloc(sizeof(char)); endTag = pop(stack); tag都会分配一个从endTag返回的值,但该值会被另一个分配立即覆盖。这意味着malloc返回的值丢失,内存仍然分配但从未使用过。在每种情况下,您都应删除包含malloc

的行

答案 1 :(得分:0)

这些行是可疑的

tag = (char *)malloc(sizeof(char));
tag = getNextTag(input, &line);

因为你覆盖了刚从malloc收到的指针。然后,你只分配一个char,这也可能是错误的。

稍后会为endTag复制类似的模式。

也许malloc应该由getNextTag完成(或者你应该将malloc-ed区域作为参数赋予函数),并且它必须不小于标签的长度(加上字符串终止符为1),例如: sizeof(char) * (length+1)sizeof(char) == 1所以你可以省略它。)

然后你释放tag(错误的,因为你没有释放你分配的东西),但不是endTag ......