为什么有些C程序在调试模式下能运行而在发布模式下不能?

5

好的,

我被卡住了。我有一个程序代码,可以根据算法系统地执行站在圆圈中的人,但是我遇到了一个问题,它在发布模式下崩溃了。如果我使用调试器(codeblocks)运行代码,它可以正常运行,但是如果不用它就会崩溃。我在网上查找,唯一找到的是未初始化变量,但是我尝试在声明时立即为变量设置值,但它并没有解决问题。

如果有人能看到我的问题,我将非常感激帮助。

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

// if the program does not work, please run in debugger mode. It will work.

void remove_person(int** array, int arraySize, int position)
{
    int i;
    for (i = 0; i < arraySize; ++i)
        printf("%d ", (*array)[i]);
    printf("\n");

    int* temp = malloc((arraySize - 1) * sizeof(int)); // create temporary array smaller by one element

    memmove(temp,*array,(position+1)*sizeof(int)); // copy entire array before position

    memmove(temp+position,(*array)+(position+1),(arraySize - position)*sizeof(int)); // copy entire array after postion

    for (i = 0; i < arraySize - 1; ++i)
        printf("%d ", (temp)[i]);
    printf("\n");

    free (*array);
    *array = temp;
}


int kill(int** a, int n)
{
    int pos = 0;
    int round = 1;
    while(n > 1)
    {
        pos = pos + 2 - (round % 2);

        while(pos >= n)
            pos = pos - n;

        remove_person(a,n,pos);
        n--;

        while(pos >= n)
            pos = pos - n;
        round++;
    }
    return *a[0];
}

void main()
{
    int n, survivor, i;
    int* people;

    printf("Enter number of people for Russian Roulette: \n");
    scanf("%d", &n);

    people = (int*) malloc(n*sizeof(int));

    for(i=0; i < n; i++)
    {
        people[i] = i;
    }

    survivor  = kill(&people, n);
    printf("The survivor is person #%d\n", survivor);
}

4
void main 是非标准用法。 - chris
你不觉得一个简单的列表比这个解决方案更好吗?要从列表中删除元素,你只需要使用 free() 函数并修改前一个元素的 next 指针。 - Eddy_Em
@chris:推荐阅读:http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/legality-of-void-main.html。简而言之,`void main()`在C99标准中以实现定义的方式被允许使用。 - nneonneo
是的,即使C11也允许使用void main。我不知道Stroustrup(他应该是规范的大师)是如何错过这一点的。我相信自C89以来就允许使用void main。(此外,标准基本上允许任何返回类型,甚至像float mainstruct foo main这样愚蠢的东西)。 - nneonneo
@nneonneo,但是关于memmove,我是正确的。哎呀。我没看到你的答案。 - Eddy_Em
显示剩余5条评论
2个回答

7

标题问题(“为什么一些C程序在调试模式下可以工作,但在发布模式下不能?”)的基本答案是“当它们调用未定义的行为时”。

在此处,

memmove(temp,*array,(position+1)*sizeof(int)); // copy entire array before position

memmove(temp+position,(*array)+(position+1),(arraySize - position)*sizeof(int)); // copy entire array after postion

你复制的内容太多了。要理解原因,请观察第一个 memmove 复制到 temp[0]temp[1]、...、temp[position],而第二个则复制到 temp[position]temp[position+1]、...、temp[position+arraySize-position-1] = temp[arraySize-1](注意在 temp[position] 重叠的问题)。但是 temp 只有空间容纳 arraySize-1 个元素——你复制的比它能容纳的还多,所以会导致未定义行为

在调试模式下它可能可以工作,但在发布模式下却不行,因为堆分配的方式有所不同(调试模式下的分配器可能会用额外的空间填充分配,以在运行时使用调试器或分析器时捕获此类错误)。


0

如果我输入4(或比4更高的数字),程序就会崩溃,但我不会去查看为什么会发生这种情况。

除此之外,程序运行得很好,问题是你看不到输出,因为我认为你在Windows上运行它。

话虽如此,你应该在结尾添加类似于scanf("%d", &n);的内容,或者运行cmd.exe,进入保存可执行文件的目录并从那里运行它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接