簡體   English   中英

非常奇怪的C ++行為

[英]Very Strange C++ Behavior

我在為學校作業編寫的C ++程序中遇到了一個非常奇怪的錯誤(末尾粘貼了代碼),但我不知道它為什么要這樣做。 特別是,它有時會隨機輸出錯誤的信息,有時會給出正確的輸出,每次都在相同的輸入上運行。 如果有人對為什么有見識,我將不勝感激:

我已經制作了一個C ++程序,該程序實現了一個簡單的MaxHeap數據結構,該結構支持使用HeapInsert從空堆開始將元素逐個插入堆中,或者從元素數組開始並使用在元素的前半部分上執行bubbledown以便將其轉換為堆-程序采用一個命令行參數,要么使用HeapInsert(將使用第一種方法來構建堆),要么使用BubbleDown來使用第二種方法來構建堆。

該程序從cin中獲取用戶輸入:首先將提供使堆變出的元素數量,然后是要放入堆中的元素。 完成后,它輸出在bubbleup / bubbledown中執行的交換次數,然后輸出堆中的元素,以便它們位於存儲堆的數組中。

我們已經得到了一個示例輸入(100個隨機數)和一個示例輸出,我的代碼應該產生這些示例才能知道我們的實現是正確的。 我在命令行上執行以下操作:

g++ HeapTest.cpp
./a.out BubbleDown < 100.txt > out
diff out s100b.txt

100.txt是樣本輸入,s100b.txt是正確的樣本輸出。

執行線

./a.out BubbleDown < 100.txt > out
diff out s100b.txt

反復,我得到不一致的結果。 看來我得到輸出的一半時間完全與示例文件匹配,但有一半時間卻不匹配,尤其是當我查看輸出文件時,似乎隨機大數已插入到堆中,沒有原因,使我的輸出錯誤。

對我來說,在完全相同的輸入下重復運行代碼時,結果將不一致,這對我來說絕對沒有意義。 這僅在我在命令行上使用“ BubbleDown”選項時發生。 下面是我的代碼:

#include <cstdlib>
#include <stdint.h>       
#include <iostream>
#include <string>
#include <cstring>
#include <cassert>
#include <cmath>
using namespace std;

struct MaxHeap { //MaxHeap data structure
    int n;      //size of the heap
    int numex;  //number of exchanges in building the heap
    int* A;     //Array storing the actual heap
    MaxHeap(int a){     //First Constructor: initializes an empty heap of size 0 in an array of size a
        n=0;    //initialize size to 0
        numex=0;//initialize numex to 0
        A = new int[a]; //allocate space for array of size A on heap
    }
    MaxHeap(int * data, int a){ //Second Constructor: consumes array of a elements and creates a heap
                            //out of thoses elements using bubbledown
        n = a;
        A = data;
        numex = 0;

        for(int k = (int)(floor((n-1)/2)); k > -1 ; k-=1){
            bubbledown(k);
        }
    }
    ~MaxHeap(){}    //necessary since MaxHeaps made with first constructor are non-contiguous
    void bubbleup(int v){//bubble-up algorithm as described in class
        int j;
        while( (v != 0) && (A[(int)(floor((v-1)/2))] < A[v]) ){
            numex +=1;
            j = A[v];
            A[v] = A[(int)(floor((v-1)/2))];
            A[(int)(floor((v-1)/2))] = j;
            v = (int)(floor((v-1)/2));

        }

    }
    void bubbledown(int v){//bubbledown algorithm as described in calss

        int j;
        int k;
        int L;
        int temp;
        while(true){

            j = 2*v+1;
            k = 2*v+2;
            if((j <= n) && (A[j] > A[v])){L = j;}
            else{L = v;}
            if((k <= n) && (A[k] > A[L])){L = k;}
            if(L == v){break;}
            else{numex +=1; temp = A[v]; A[v] = A[L]; A[L] = temp; v=L;}
        }

    }
    void HeapInsert(int i, int k){//heapinsert algorithm as described in class

        n=k+1;
        A[n-1] = i;
        bubbleup(n-1);

    }
};

void error(){

    cerr << "Usage: " << endl;
    exit(-1);

}

int main(int argc, char * argv[]){

    int flag;
    char hins[] = "HeapInsert";
    char bdwn[] = "BubbleDown";

    switch(argc){    
        case 2:
            if(strcmp(argv[1], hins) == 0){flag=0; break;}
            else if(strcmp(argv[1], bdwn) == 0){flag=1; break;}
            else{error();}
        default: error();
    }

    if(flag==0){//If HeapInsert option selected, the below creates a heap via HeapInsert

        int nelem;
        cin >> nelem;       //read in number of elements that are going to be given
        struct MaxHeap H = MaxHeap(nelem);  //call first constructor

        for(int k=0; k < nelem; k+=1){      //insert elements into the heap one by one as they are read in
            int i;
            cin >> i;
            H.HeapInsert(i,k);
        }

        cout << H.numex << endl;            //print number of exchanges

        for(int k =0;k < nelem; k+=1){      //print elements of heap 1 by 1

            cout << H.A[k] << endl;

        }

    }
    else{       //if BubbleDown option chosen by user

        int nelem;
        cin >> nelem;   //read in number of elements
        int data[nelem];    //initialize array to store that number of elements

        for(int k=0; k < nelem; k+=1){  //build array of elements in order given

            int i;
            cin >> i;
            data[k] = i;

        }

        struct MaxHeap H = MaxHeap(data, nelem);    //use second constructor to create a heap out of the array

        cout << H.numex << endl;            //print number of exchanges

        for(int k =0;k < nelem; k+=1){      //print out elements 1 by 1

            cout << H.A[k] << endl;

        }

    }
}

如果有人對我的代碼在不依賴任何隨機性或內存分配(給出BubbleDown選項時不使用內存分配)的情況下如何產生這樣的不一致結果有任何想法,將不勝感激!

我用調試符號編譯了程序...

gcc -g -O0 -o stuff stuff.cpp

然后在Valgrind中運行它...

echo '4 2 3 4 5 6' | valgrind ./stuff BubbleDown

它說的是:

==28605== Conditional jump or move depends on uninitialised value(s)
==28605==    at 0x401186: MaxHeap::bubbledown(int) (stuff.cpp:52)
==28605==    by 0x400FCD: MaxHeap::MaxHeap(int*, int) (stuff.cpp:26)
==28605==    by 0x400E08: main (stuff.cpp:125)

似乎與此相對應:

if((j <= n) && (A[j] > A[v])){L = j;}

問題似乎在於您正在讀取數組的末尾。 如果j == n ,那么它的經過所述陣列的端部的一個元素。 k == n相同。 如果將bubbledown更改為此,則問題將消失:

void bubbledown(int v){//bubbledown algorithm as described in calss
    while(true){
        const int j = 2*v+1;
        const int k = 2*v+2;
        int L;

        // notice < instead of <=
        if((j < n) && (A[j] > A[v])){
            L = j;
        }
        else{
            L = v;
        }

        // notice < instead of <=
        if((k < n) && (A[k] > A[L])){
            L = k;
        }
        if(L == v){
            break;
        }
        else{
            numex +=1;
            const int temp = A[v];
            A[v] = A[L];
            A[L] = temp;
            v = L;
        }
    }
}

注意:我使用了一些Linux命令來執行此操作(最重要的是Valgrind)。 無論您使用的是哪種編譯器工具鏈/ IDE,都應該有自己的調試器,大概可以為您提供類似的輸出。 Windows中存在有關Valgrind替代品堆棧溢出問題 我建議找到一個喜歡的工具-這將使C ++調試容易得多

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM