【问题标题】:variables vary mysteriously变量神秘地变化
【发布时间】:2011-12-01 22:02:57
【问题描述】:

问题:是什么导致这些值随机变化?


信息:

我的代码:

int q = nonZero;
for(j = nonZero;j>1;j--)
{
    printf("Top: %i %i\n",j,q);
    qsort(tree,j,sizeof(Node),cmp);
    printf("Bottom: %i %i\n",j,q);
    Node t = {tree[0],tree[1],-1};
    tree[0] = &t;
    tree[1] = tree[j];
    tree[j] = NULL;
}

不是一个复杂的小程序。从树上的前两个节点中创建一个节点,使其成为新的顶部节点,使用数组,重复。我添加了“q”作为调试值,我完全不知道到底发生了什么。如果我尝试让它运行,j 通常从 73 开始,它应该是这样,预期它会是 72,71,70,69,68...3,2,并且 q 将无限期地保持 73。这是我的输出:

Top: 73 73
Bottom: -796584576 32767
Segmentation fault

但这还不是全部,没有重新编译,我得到了:

Top: 73 73
Bottom: 0 0
Segmentation fault

它始终会给我这两个输出之一。几次运行后,我看到 32767 从未改变,q 值,但 j 值,这里 -796584576,总是一些不同的、荒谬的大负数。任何人都知道为什么 qsort 似乎在改变我的 j 值,以及似乎完全不相关的 q 值?

【问题讨论】:

  • 一种解释是堆栈指针值已损坏。使用调试器并仔细检查其值在 qsort 调用前后是否相同。
  • 一个完整的例子会很好。您让我们猜测和推断变量的数据类型以及 cmp() 的可能副作用。

标签: c variables memory


【解决方案1】:

我不确定这是否是您的问题,但由于t 是一个局部变量,它会在该循环结束时超出范围,因此将其分配给tree[0] 会使tree[0] 未定义。

【讨论】:

  • 不,不是我的问题。问题完全在于 q 和 j。特别是q。我注释掉了与 t 相关的所有内容并且没有任何更改,除了现在它会在顶部和底部之间引发分段错误。
  • @Narcolapser:你不知道编译器可能会选择在哪里存储 j 和 q 或其他一些临时变量。在循环体的开头,它们可能正是 t 上次所在的位置。然后你可以对该位置进行排序并破坏它们。
  • @Narc:这可能不是您要问的问题,但仍然不正确。 t 在后续} 之后不再在范围内,但是当内存可能被其他人使用时,内存仍可能通过tree[0] 引用。因此,树可能会损坏,任何依赖于 tree[0] 内容的操作都可能是不正确的。
  • 但是 j 和 q 不是临时的,它们是本地的,两者都是在循环之外声明的,j 实际上是在更早的循环中使用的。我有点明白为什么如果我在循环中声明它可能会被覆盖,但即使那样,我也不明白为什么编译器会选择覆盖仍在使用的变量(我知道这可能发生在指针上,但这些是整数,而不是指针)。这似乎是一种非常糟糕的做事方式。
【解决方案2】:

qsort() 调用表明tree[]Nodes 的数组,但语句tree[0] = &t; 却暗示它是一个指针数组。既然如此,那么:

qsort( tree, j, sizeof(&Node), cmp ) ;

或更好

qsort( tree, j, sizeof(*tree), cmp ) ;

后者确保大小是任何树的大小,无论其类型如何,都是数组,因此更安全且更易于维护。

t的地址分配给范围大于t的变量也是注定的。

【讨论】:

  • 啊啊啊。那么这里的大小是整个数组的大小还是每个元素的大小?
  • @Narc:它是每个元素的大小。 qsort 需要知道要移动什么大小的对象而不是特定类型的。该功能在许多地方都有很好的记录。 A particularly clear documentation.
【解决方案3】:

t 是一个局部变量,其生命周期在每次迭代结束时结束。因此,在该迭代之后保留该地址是未定义的行为。您必须使用malloc 分配树节点的副本。

【讨论】:

    【解决方案4】:

    qsort 正在破坏内存。如果这是您编写的 qsort,它可能会出现写入无效位置的错误。如果这是一个库 qsort,它可能是一个递归函数,它会溢出堆栈,破坏你的本地变量。

    【讨论】:

    • 它是标准库 qsort。你会如何建议修复它以破坏我的记忆?我听到你关于溢出堆栈的论点,但我有 6gb 的内存可用,我真的不明白递归调用 > 73 次如何做到这一点......
    • 您的计算机有 6GB,但操作系统为您的程序提供了一些固定(小得多)的内存用于其堆栈。如何更改取决于您使用的操作系统。
    • @Narcolapser:无论你有多少 RAM,分配给任何单个进程或线程的堆栈的数量都要少得多。在 Win32 中通常为 2Mb。也就是说,虽然 qsort() 调用导致损坏,但它更多地与您传递的参数的有效性有关,几乎可以肯定与堆栈或递归无关。
    • 我同意 Clifford 的观点,如果您进行大量递归,您确实需要担心堆栈。但在这种情况下,你会遇到更大的争论问题。
    • @Clifford Ubuntu 64。但此时这并不重要。 xD
    猜你喜欢
    • 2014-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多