0

I've read many posts with the same error, unfortunately all of those deal with indexing off the end of an array. In my case I get the error when I assign the array to a variable in my constructor.

Here is my code:

Heap.cpp

#include "./Heap.h"
#include <iostream>
#include <sstream>
// Provides floor, ceil, etc.
#include <cmath>

using namespace std;

Heap::Heap() {
  arraySize = 0;
  n = 0;
  A = NULL;
}

// This assumes that every element of the array is an
// element of the heap.
Heap::Heap(int* inArray, int inArraySize, int inHeapSize) {
  // TODO: initialize your class data members. An array dynamically allocated
  // as follows:
  // A = new int[size];
  // If you allocate an array like this you MUST deallocate it in your
  // destructor. This is done for you in the destructor below.

  arraySize = inArraySize;
  n = inHeapSize;
  A = new int[arraySize];
  A = inArray;
}

// Destructor. Cleans up memory.
Heap::~Heap() {
  delete [] A;
}

// Note: the function name is prefixed by Heap:: (the class
// name followed by two colons). Any function defined in
// the .cpp file must have this prefix.
int Heap::at(int i) const {
  return A[i];
}

int Heap::parent(int i) const{
    return (int) (i - 1) / 2;
}

int Heap::left(int i) const {
    return (i + 1)* 2 - 1;
}

int Heap::right(int i) const {
    return  (i + 1) * 2;
}

bool Heap::hasLeft(int i) const {
    int leftIndex = left(i);
    std::cout << "left index = " << leftIndex<< std::endl;
    return false; 
}

bool Heap::hasRight(int i) const{
    return false;
}

void Heap::maxHeapify(int i){

}
//
void Heap::buildMaxHeap(){

}



bool Heap::operator==(const Heap& rhs) {
  if (n != rhs.n) return false;
  for (int i = 0; i < n; ++i) {
    if (A[i] != rhs.A[i]) return false;
  }
  return true;
}

bool Heap::operator==(const int* rhs) {
  for (int i = 0; i < n; ++i) {
    if (A[i] != rhs[i]) return false;
  }
  return true;
}

std::ostream& operator<<(std::ostream& out, const Heap& h) {
  out << "[";
  for (int i = 0; i < h.n; ++i) {
    out << h.A[i];
    if (i < h.n-1) {
      out << ", ";
    }
  }
  out << "]";
  return out;
}

string toDotImpl(const Heap& h, int i) {
  using namespace std;
  stringstream ss;
  if (h.hasLeft(i)) {
    ss << toDotImpl(h, h.left(i));
    ss << "\"" << h.at(i) << "\" -> \""
       << h.at(h.left(i)) << "\"\n";
  }
  if (h.hasRight(i)) {
    ss << toDotImpl(h, h.right(i));
    ss << "\"" << h.at(i) << "\" -> \""
       << h.at(h.right(i)) << "\"\n";
  }
  return ss.str();
}

string toDot(const Heap& h) {
  using namespace std;
  stringstream ss;
  ss << "digraph G {\n";
  ss << "graph [ordering=\"out\"]\n";
  ss << "\"" << h.at(0) << "\"\n";
  ss << toDotImpl(h, 0);
  ss << "}\n";
  return ss.str();
}

and

Heap.h

#pragma once

// Provides I/O
#include <iostream>
// Provides size_t
#include <cstdlib>
// Provides INT_MAX and INT_MIN
// You can consider INT_MIN to be negative infinity
// and INT_MAX to be infinity
#include <climits>

//------------------------------------------------------------
// Heap class
//------------------------------------------------------------
class Heap {
 public:
  // Constructor
  Heap();

  // This constructor assumes that every element of the array is an
  // element of the heap.
  Heap(int* inArray, int inArraySize, int inHeapSize);

  // Destructor
  ~Heap();

  // Accesses an element of the array.
  int at(int i) const; 

  // Gets parent index of element at i
  int parent(int i) const;

  // Return element to the  left of i
  int left(int i) const;

  // Return element to the right of i
  int right(int i) const;

  // Checks if an element has a left child
  bool hasLeft(int i) const;

  // Checks if an elemnt has a right child
  bool hasRight(int i) const;

  // "Max heapifies" an array
  void maxHeapify(int i);

  // builds a max heap
  void buildMaxHeap();


  // Allows comparison between results
  bool operator==(const Heap& rhs);
  bool operator==(const int* rhs);

  // Useful for debugging. To use:
  //   Heap h;
  //   cout << h << endl;
  friend std::ostream& operator<<(std::ostream& out, const Heap& h);

 private:
  // The array
  int* A;

  // Size of the array
  int arraySize;

  // The number of elements in the heap
  int n;
};

// Useful for debugging. To use:
//   Heap h;
//   cout << h << endl;
std::string toDot(const Heap& h);

The code is called with I can include the entire main.cpp if needed but it has several hundred lines of just test cases that are commented out. int A[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; Heap h(A, 8, 8);

if I comment out A = inArray; the program runs so I'm pretty confident that is where the issue is.

A is defined in Heap.h as `int* A;

Here is the full error:

*** Error in `./project': free(): invalid size: 0x00007ffd84786660 *** Aborted (core dumped)

this is probably quite a simple issue, but I can't figure out what is causing this since I believe this should allocate an array of size inArraySize of type int and then assign the given array inArray to A.

Full disclosure: this is part of an assignment so feel free to just point me in the right direction, but my professor is fine with us using stackoverflow as long as we site it.

Cœur
  • 37,241
  • 25
  • 195
  • 267
kalenpw
  • 695
  • 3
  • 10
  • 34
  • ... and what is the error? (and what line is it on, etc.) – qxz Feb 08 '17 at 06:56
  • 3
    You're allocating memory and then on the next line you immediately throw away the address of that memory by reassigning `A`. Is that really what you want to be doing? – Greg Kikola Feb 08 '17 at 06:57
  • 1
    Possible duplicate of [Cleanest way to copy a constant size array in c++11](http://stackoverflow.com/questions/12328301/cleanest-way-to-copy-a-constant-size-array-in-c11) – Ken Y-N Feb 08 '17 at 06:57
  • 1
    Please post complete, minimum and compilable example. The code you provide lacks for example declarations of `arraySize` and `n`. – Resurrection Feb 08 '17 at 06:57
  • What line is that error happening on? Please create a [Minimal, _Complete_, Verifiable Example](http://stackoverflow.com/help/mcve). – qxz Feb 08 '17 at 06:59
  • Are you kidding? You've just changed the code in the original question. That makes all previous answers obsolete! – barak manos Feb 08 '17 at 07:07
  • @Resurrection sorry about that, I left out the code as most of it isn't relevant here, but I added in the files. – kalenpw Feb 08 '17 at 07:07
  • @barakmanos the original code is still there unedited, I just added in the rest of the file for context – kalenpw Feb 08 '17 at 07:08
  • 1
    Where's the line `A = inArray;`??? – barak manos Feb 08 '17 at 07:08
  • @barakmanos ah shoot, my bad I was testing that and forgot to change it. Fixed – kalenpw Feb 08 '17 at 07:09
  • @keny-n is there a way to do this without using the std::array or other functions part off std? My professor usually tells us what other functions we are allowed to use and he didn't mention those so I believe there is a way to do it with what is provided – kalenpw Feb 08 '17 at 07:11
  • @kalenpw `memcpy` see my answer – acraig5075 Feb 08 '17 at 07:13
  • @n.m. I'll send you my professors email if you wanna try and convince him of that :) – kalenpw Feb 08 '17 at 07:15
  • I didn't pay for that course so I can't complain, but if I were to complain I would skip the professor and go straight to the rector (provost? How do you call the head of the uni?) (If it's specifically a C++ course and not some kind of low level programming course that happens to use a C++ compiler. In this latter case I would have no right to complain.) – n. m. could be an AI Feb 08 '17 at 07:22
  • @n.m. it's a data structures and algorithms class and we're just using c++ to implement the various data structures and algorithms after learning about them – kalenpw Feb 08 '17 at 07:24
  • I see. I don't see a reason to use new and delete in this specific assignment and throughout most of this course. It would work perfectly well with std::vector. I would ask the professor why std::vector is not allowed. – n. m. could be an AI Feb 08 '17 at 07:29

4 Answers4

2

You're trying to copy an array, but assigning pointers like that is not how to do it. There are various ways.

Standard C++:

#include <algorithm>

std::copy(inArray, inArray + inArraySize, A);

Using standard containers:

#include <vector>

std::vector<int> A(inArray, inArray + inArraySize);

Old style C way

memcpy(A, inArray, sizeof(int) * inArraySize);
acraig5075
  • 10,588
  • 3
  • 31
  • 50
  • This did the trick, sorry for the duplicate question I'm new to c++ and thought just assigning the value would copy it, but after reading the answers in the duplicate link I see why it doesn't – kalenpw Feb 08 '17 at 07:13
1

Doing:

A = new int[arraySize];
A = inArray;

Is like doing:

i = 5;
i = 6;

The second assignment overrides the first one.


Hence as a result, the member variable A is pointing to the same memory block pointed by the input argument inArray.

If you haven't dynamically allocated this memory block (with new), then you cannot dynamically deallocate it (with delete).

barak manos
  • 29,648
  • 10
  • 62
  • 114
  • Thanks for pointing out that I was just overwriting the A, I didn't realize that before. Sorry for editing the code in my question, your answer was helpful. – kalenpw Feb 08 '17 at 07:16
1

The lines

A = new int[arraySize];
A = inArray;

are cause of two problems.

  1. There is a memory leak. The value returned by new int[arraySize] is lost and cannot be deallocated.

  2. If you are calling delete [] A in the destructor, that would be cause of the second problem.

    • If inArray was dynamically allocated and deallocated in the calling function, you will be calling delete on the same pointer twice.
    • If inArray was an array created in the stack, calling delete on it is also a problem. delete can be called only on memory that was returned by call to new.
R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

A = inArray; is not doing what you think it is doing. This line does not copy inArray into the memory you allocated for A. Instead it changes A to point to a new location (the address of inArray), causing the previously allocated memory to leak. Later on when you call delete on A you'll be trying to free memory at inArray's address.

If you just want to copy an array, you could do something like

A = new int[inArraySize];
for (i = 0; i < inArraySize; ++i)
    A[i] = inArray[i];

Or better yet, with std::copy:

std::copy(inArray, inArray + inArraySize, A);
Greg Kikola
  • 573
  • 3
  • 6