非常奇怪的c++行为
Very Strange C++ Behavior
我在为学校作业编写的c++程序中遇到了一个非常奇怪的错误(代码粘贴在最后),我不明白为什么它会这样做。特别是,有时随机给出不正确的输出,有时给出正确的输出,每次都在相同的输入上运行。如果有人能告诉我为什么,我将非常感激。
我做了一个c++程序,实现一个简单的MaxHeap数据结构支持构建堆要么使用HeapInsert将元素插入堆一个接一个从空堆开始,或者从一个数组元素和使用bubbledown第一一半的元素,把它变成一堆程序需要一个命令行参数,要么HeapInsert将使用第一种方法建立一个堆,或者使用第二个方法来构建堆。
程序从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替代品的Stack Overflow问题。我建议找一个你喜欢的工具——它会使c++调试更容易
- 理解boost::asio-async_read在无需读取内容时的行为
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- arr[-1]在c++中的奇怪行为
- 继承期间显示未知行为的子类
- 如何在c++中使用引用实现类似python的行为
- G锁定铸造到基础上会释放模拟行为
- 在C++中对T*类型执行std::move的意外行为
- std::当在256字节边界上写入整数时,流的奇怪行为
- 不知道某个东西是否被忽略会引入未定义的行为吗
- 奇怪的构造函数行为
- 重载运算符new[]的行为取决于析构函数
- 不同语言中相同代码的不同行为
- 处理除以零会导致<csignal>意外行为
- 试图理解类对象的行为
- c++11评估顺序(未定义的行为)
- 从结构寻址时,MMAP变量的行为很奇怪
- 我可以做些什么来消除或最小化这种将提供相同功能和行为的代码重复
- 读取文件时运行时的未知行为
- strncpy之后的char数组的错误行为
- 此增量后语句是否会导致未定义的行为?