在 Visual Studio 中检测到堆损坏,但程序在另一个 C 编译器中运行良好:为什么?

Heap Corruption Detected in Visual Studio, but program runs fine in another C compiler: why?

我尝试搜索这个问题,但找不到任何答案。我编写了一个程序,它使用链表实现堆栈及其操作。该程序在 C Web IDE 上编译和 运行 完美。

当我 运行 Visual Studio 中的程序时,它失败并给我以下错误:

调试错误! 程序:C:\Users...我的文件路径 检测到堆损坏:在 0x011058C8 处的正常块 (#78) 之后。 CRT 检测到应用程序在堆缓冲区结束后写入内存。

因为我的代码 运行 在其他地方都很好,这一定是我使用 Visual Studio 的方式的问题。有任何想法吗?我是 Visual Studio 的新手,恐怕这可能有些愚蠢,但我似乎无法弄明白。

我在下面包含了我的代码,请注意,失败是由 Visual Studio 中的 pop() 函数引起的。

#include <stdio.h>
#include <stdlib.h>

struct Node {
    int data;
    struct Node* next;
};

struct Node* top = NULL; //initialize head

void push(int x);
void push(int x) {
    struct Node* add = (struct Node*)malloc(sizeof(struct Node*));
    add->data = x;
    add->next = top; //make add point to what top (head) points to (old 1st)
    top = add; //make top point to add (new 1st)
}

void pop();
void pop() {
    if (top == NULL) return;
    struct Node* temp = top;
    top = top->next;
    free(temp);
}

int topp();
int topp() {
    return top->data;
}

int exist();
int exist() {
    if (top->next) {
        return 1;
    }
    else {
        return 0;
    }
}

void PrintIt();
void PrintIt() {
    struct Node* temp = top;
    while (temp!= NULL) {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("\n");
}

int main() {
    push(1); PrintIt();
    push(44); PrintIt();
    push(23); PrintIt();
    pop(); PrintIt();
    push(9); PrintIt();
    return 0;
}

如果您正在做一些未定义的行为(动态内存分配是这些问题的真正温床),可能发生的未定义的事情之一是它会工作得很好。

这绝不表示您做的是正确的事情,UB 是应该避免的事情,因为它可能在另一个系统、另一个编译器甚至下周二 3:05 下午以不同方式运行: -)


提到几件事:

  • 您不需要在定义之前立即声明所有这些函数(原型)。如果定义尚未声明,则它充当声明。
  • 您的 exist() 函数很可能因空列表而崩溃,因为它取消引用 top。如果你的目的是检测一个非空列表,你可以只使用 return (top != NULL);.
  • 你不应该在 C 中显式地转换 malloc 的 return 值,它会导致某些细微的错误。

而且,事实上,在查看最后一个要点时,您有一个错误(不是特别与转换有关,只是在该特定行上):

struct Node* add = (struct Node*)malloc(sizeof(struct Node*));
//                                                        ^
//                                                      oops!

struct Node* 的大小是指向您的结构的 指针 的大小,通常(但不一定)四个或八个八位字节。鉴于您的实际结构有一个整数 一个指针,该大小将不够大。

它可能适用于某些 提供最小动态内存分配的系统,但绝对不建议这样做。你应该这样做:

struct Node *add = malloc(sizeof(struct Node));
//                               ^^^^^^^^^^^
//                      size of the node, not pointer

该行已删除演员表,并且大小正确。