【问题标题】:Mergesort output changes when printf is used使用 printf 时合并排序输出发生变化
【发布时间】:2014-03-03 01:05:32
【问题描述】:

在尝试在 C 中构建归并排序作为练习时,我遇到了一个奇怪的问题,即算法的输出会随着 printf 的存在而变化。让我进一步详细说明。我有一个“MergeSort.h”文件,其中我的合并排序算法如下:

#ifndef _MSORT_H_
#define _MSORT_H_

void merge(int a[],int lo,int mi,int hi){
    int n1 = (mi - lo) +1;
    int n2 = hi - mi;
    int left[n1];
    int right[n2];
    int i;
    int j;
    int k;
    for(i = 0;i < n1;i++){
        left[i] = a[lo+i];
    }
    for(j = 0;j < n2;j++){
        right[j] = a[mi+j+1];
    }
    i = 0;
    j = 0;
    for(k = lo;k <= hi;k++){
        if(left[i] < right[j]){
            a[k] = left[i];
            i = i + 1;
        }else{
            a[k] = right[j];
            j = j+1;
        }
    }

}

void msorthelper(int a[],int p,int r){
    if(p < r){
        int mid = (p + r)/2;
        msorthelper(a,0,mid);
        msorthelper(a,mid+1,r);
        merge(a,p,mid,r);
    }
}

void msortex(int a[],int size){
    msorthelper(a,0,size-1);
    int counter;
    for(counter = 0;counter < size;counter++){
        printf(" %d ",a[counter]);
    }
}
#endif

我在 sorttester.c 中有对应的排序测试器:

#include <stdio.h>
#include "mergesort.h"

int main(){

    int out[] = {8,1,6};
    msortex(out,3);

}

运行 sorttester 的输出如下:

1 0 0

现在有趣的部分是,当我将任何 printf 语句放在合并的开头时,会生成正确的输出。这是一个例子:

    #ifndef _MSORT_H_
    #define _MSORT_H_

    void merge(int a[],int lo,int mi,int hi){
        printf("Hello\n"); 
        int n1 = (mi - lo) +1;
        int n2 = hi - mi;
        int left[n1];
        int right[n2];
        .................Rest of the code.....

现在的输出是:

你好你好 1 6 8

这是数组 8 6 1 的正确排序顺序。

有人能告诉我我在这里可能做错了什么,导致输出因 printf 的存在而急剧下降吗?

谢谢

【问题讨论】:

    标签: c debugging printf output mergesort


    【解决方案1】:

    看看你的合并部分代码:

    for(k = lo;k <= hi;k++){
        if(left[i] < right[j]){
            a[k] = left[i];
            i = i + 1;
        }else{
            a[k] = right[j];
            j = j+1;
        }
    }
    

    假设

    left[] = {1, 2}
    right[] = {3, 4, 5}
    

    在合并循环 (k) 的 2 次迭代后,“i”的值将是 2。从​​现在开始,您将尝试比较

    left[2] < right[j]
    

    这是无效的,因为left[2]会引用一些随机内存(左数组大小只有2,所以索引2的元素不存在,只有0和1)

    因此,如果您为 i 和 j 值添加保护,例如将第一个 if 条件更改为:

    if(i != n1 && (j == n2 || left[i] < right[j])){
    

    你应该没事的。

    无论如何,我也应该告诉你,你不应该用非 const 的值声明数组大小,例如:

    int left[n1];
    int right[n2];
    

    它实际上是按标准禁止的。您应该动态分配它,使用向量(如果是 C++)或将它们声明为具有足够大的全局(最大 n 值)

    【讨论】:

    • 感谢您指出合并问题,但您是否知道为什么 printf 的存在导致输出正确?
    • 虽然我不能确定编译器是做什么的,但我可以建议你做一个小测试。在循环之前添加这个 printf 与 'k' printf("ns1: %d, ns2: %d\n",n1, n2); 和这个在循环之后(内部)printf("left[%d]: %d, right[%d]: %d\n", i, left[i], j, right[j]);。现在,如果你在没有 hello 打印的情况下运行它,right[1](out of bound) 的值将是 0 - 很可能只是新内存。因此,为什么将 0 与 8 进行比较并选择支持 8。另一方面,如果您运行 Hello printf,它很可能会分配一些临时内存,从而导致 right[1] 为 32767,因此选择了 8。
    • 如果您的机器在这些值上没有显示任何差异,您可以看看我的输出:gist.github.com/kareth/782c8197485cd5f50c9b
    • 似乎这是一个编译器怪癖。感谢您指出问题。我将此标记为答案。
    猜你喜欢
    • 2016-02-02
    • 2017-02-05
    • 2014-02-16
    • 2021-12-15
    • 2011-09-22
    • 1970-01-01
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多