2D Array of pointers to structs. Memory access issue - c++

I am attempting to write a program to compute the Hungarian method for a set of Jobs:Workers.
I know how I am going to code the bulk of the program, but I am stuck at loading my matrix.
I have created a class to store info in, and I have created a 2d array of pointers to objects of this class. Each entry of the matrix should hold a cost value assigned to that Worker:Job combo.
Every time I try to load the costs into the objects within the array, I keep getting a memory access violation, and I can't figure out why. Any help would be greatly appreciated.
Thanks,
Chris
using namespace std;
class costPtr{
int cost;
int fillRow;
int fillColumn;
public:
costPtr()
{
int fillRow = 0;
int fillColumn = 0;
cost = 0;
}
void fillCost(int costInput)
{
cost = costInput;
}
int printCost() const
{
return cost;
}
};
void fillMatrix(costPtr*** matrix, int workers, int jobs);
void methodMain();
void printMatrix(costPtr*** matrix, int workers, int jobs);
int main()
{
methodMain();
}
void methodMain()
{
int jobs, workers;
cout << "How many jobs are there: ";
cin >> jobs;
cout << "How many workers are there: ";
cin >> workers;
costPtr*** matrix = new costPtr**[workers];
for (int i = 0; i < workers; i++)
matrix[i] = new costPtr*[jobs];
fillMatrix(matrix, workers, jobs);
printMatrix(matrix, workers, jobs);
}
void fillMatrix(costPtr*** matrix, int workers, int jobs)
{
int cost;
for (int i = 0; i < workers; i++)
{
for (int j = 0; j < jobs; j++)
{
cout << "What is the cost for worker " << i + 1 << " doing job " << j + 1 << ": ";
cin >> cost;
(matrix[i][j])->fillCost(cost);
cout << endl;
}
}
}
void printMatrix(costPtr*** matrix, int workers, int jobs)
{
cout << endl << endl;
for (int i = 0; i < workers; i++)
{
for (int j = 0; j < jobs; j++)
cout << (matrix[i][j])->printCost() << " ";
cout << endl;
}
}

The specific cause of the error is here:
(matrix[i][j])->fillCost(cost);
You have declared the pointer, but then you give a command to the object that the pointer points to-- which does not exist. You never constructed it.
The deeper problem is that you attempted this with an array of arrays of pointers, before you tried it with a pointer. When you write code, you should start with something small and simple that works perfectly, then add complexity a little at a time, testing at every step. (For some reason, this rule never comes up in programming courses.)

If you want it to be a "2d" matrix, it should be costPtr** matrix.
// An array of pointers
costPtr** matrix = new costPtr*[workers];
// Each element in the array is (a pointer to) another array
for (int i = 0; i < workers; i++)
matrix[i] = new costPtr[jobs];
Of course, there are always the standard containers like std::vector. You can have a vector of vectors:
// Create and initialize a workers x jobs matrix
std::vector<std::vector<costPtr>> matrix(workers, vector<costPtr>(jobs));
matrix[2][3].printCost(); // Example usage
No explicit memory allocations or pointers.
Edit: After re-reading I see you wanted a "2d array of pointers" so costPtr*** matrix is correct, but you need one more step:
costPtr*** matrix = new costPtr**[workers];
for (int i = 0; i < workers; i++) {
matrix[i] = new costPtr*[jobs];
for (int j = 0; j < jobs; j++) {
matrix[i][j] = new costPtr;
}
}

Take a look at the dynamic allocation of you matrix container. To reach your goal, every "star" in the container type must have a "new".
You successfully dealt with the first 2 pointers, like so:
costPtr*** matrix = new costPtr**[workers];
for (int i = 0; i < workers; i++)
matrix[i] = new costPtr*[jobs];
Now all you need to do is deal with the third pointer:
for (int i =0; i < workers; i++)
for (int j = 0; j < jobs; j++)
matrix [i][j] = new costPtr;
Without the last pointer allocation, all elements would point to a null.

Related

Scope of dynamic (multidimm) array when initialized with pointer and new

I'm royally confused right now. I have seen similar questions asked, and my implementation seems to be along the lines of these solutions, but I just can't get it to work.
I need to have a UtilClass that can initialize and dump a multi-dimensional dynamic array. I just want to pass the pointer the the array in BaseClass that I want initialized along with the dims. I chose to use the new keyword instead of malloc(), but I'm worried that the scope of the pointers is limited to the init function and not to the lifetime of the BaseClass (or the array pointer for that matter) and that's why the dump function produces a SEGFAULT.
Here is some code to explain:
// BaseClass.h
#pragma once
include "UtilClass.h"
class BaseClass
{
public:
UtilClass* util{nullptr};
double** array{nullptr};
};
// BaseClass.cpp
#include "BaseClass.h"
BaseClass::BaseClass() {
util = new UtilClass();
util->init(array, 4, 6);
util->dump(array, 4, 6);
}
// UtilClass.h
#pragma once
class UtilClass {
void init(double** array, int rows, int cols);
void dump(double** array, int rows, int cols);
};
// UtilClass.cpp
#include "UtilClass.h"
void UtilClass::init(double **darray, int rows, int cols) {
int i,j;
array = new double*[rows];
for (i = 0; i < rows; i++)
array[i] = new double[cols];
for (i = 0; s < rows; i++)
for (j = 0; a < cols; j++) {
data[i][j] = 1;
std::cout << "Data in array " << data[i][j] << std::endl; // This obviously works
}
}
void dump(double** array, int rows, int cols) {
int i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
std::cout << array[i][j] << " "; // But this produces a SEGFAULT
std::cout << std::endl;
}
Let me start off with a piece of advice: it's best to reuse existing tools. Consider using std::vector for dynamically-allocated array. This is well tested, optimized and easy to use. Otherwise, you'll need to deal with conundrums of memory management (e.g. deallocate the allocated chunks of memory in the dtor of BaseClass).
Regarding your question: when you call init, you pass the pointer by value. This means that the init method allocates some memory and stores the pointer to it in its local copy of darray. At the end of init this local variable is gone (you lose access to it, leaking whole allocated memory). Change the method to:
void UtilClass::init(double ***array, int rows, int cols) {
int i,j;
*array = new double*[rows];
for (i = 0; i < rows; i++)
(*array)[i] = new double[cols];
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++) {
(*array)[i][j] = i*j;
std::cout << "Data in array " << (*array)[i][j] << std::endl; // This obviously works
}
}
When calling dump, you need to pass 4 and 6 (and not 5 and 6).

how to create huge 2D arrays in C++

I am trying to create a huge 2D array in c++ like this :
float array[1000000][3];
I have to store some values in this array which has 3 components. This will be done iteratively by two for loops of 1000 loops.
When I try to run this I get an error :
Segmentation fault
Here is a bit of my code :
int m=0,c=0;
float error;int count=0;
array<array<float, 1000000>, 3> errors;
for(int i=0; i<1000; i++){
for(int j=0; j<1000; j++){
error=distance(j+20,m,c,1000-matrix(1,j));
errors[count][0]=error;
errors[count][1]=m;
errors[count][2]=c;
c++;
count++;
}
m++;
c=0;
}
sort(errors.begin(), errors.end());
cout<<errors[0][0]<<endl<<errors[0][1]<<endl<<errors[0][2]<<endl;
The error continues even after commenting out the sort...
matrix(1,j) is a matrix and I am accessing its elements using this method.
I want minimum value of error and the set of values of m and c for which error is minimum.
Is there any way I can achieve this?
Thanks in advance.
You can use array to easily perform your task. Here what you can:
#include<array>
using namespace std;
Then, let create your data array:
const int N = 1000000;
const int M = 3;
array<array<float, N>, M> my_array;
You can fill this newly created array by doing:
for(int i=0; i < N; i++){
for(int j=0; j < M; j++){
my_array[i][j] = 0.0f; // Just for example
}
}
For more information on how to use array library, please see here
If you don't want to use array, you can also proceed as follows:
const int N = 10000000;
const int M = 3;
float *my_array
my_array = new float[N*M]; // give it a memory on the stack
if(my_array == nullptr){
cerr << "ERROR: Out of memory" << endl;
}
for(int i=0; i < N; i++){
for(int j=0; j < M; j++){
*(my_array + i*N + j) = 0.0f; // Just for example
}
}
Make sure you release the memory you acquired by doing:
delete [] my_array;

Deleting Arrays With Pointers--Multidimensional and Multipointer---in C++

So I know multiple dimensions/arrays can get confusing, but how do I delete these types of arrays properly? I know the syntax, but adding multiple dimensions/pointers gets tricky. Here's some snippet code:
//FIRST PROBLEM
//function to add an item to a pointer array
//due to problems in adding something directly, I created a temp
//temp is not necessary if there's a way without it
int y = 6;
int x = 5;
int *myList = new int[x];
void List::add(int newInt)
{
void List::add(int newInt){
int *temp = new int[x+1];
temp = myList;
temp[x+1] = newInt;
delete [] myList;
int *myList = temp;
}
//SECOND PROBLEM----tricky multidimensional
// not getting any errors, but not sure if done properly
int x;
int y;
int** myMatrix;
cout << "How many rows?" << endl;
cin >> x;
myMatrix = new int*[x];
cout << "How many columns?" << endl;
cin >> y;
for (int i=0; i<x; i++)
myMatrix[i] = new int[y];
for(int i=0; i<10; ++i){
for(int j=0; j<10; ++j){
myMatrix[i][j] = rand();
}
for(int i = 0 ; i < x ; ++i)
{
for(int j = 0 ; j < col ; ++j){
// delete[] myMatrix[i][j]; (tried this method, did not work)
}
delete[] myMatrix[i];
}
delete[] myMatrix;
//looked around for examples, but were all different enough to not help
//
// delete[] myMatrix[i][j]; (tried this method, did not work)
The code you have here
myMatrix[i][j] = rand();
doesn't allocate any new heap memory for myMatrix[i][j] (which is of a non pointer type, but a simple int BTW), but just assigns the result of rand() as a value there.
Thus it's not necessary/wrong, you ever call delete for it.
You only call delete/delete[] as counterparts of new/new[] in the reverse order as they were allocated.
Further, to get redeemed from struggling with memory management, I'd seriously recommend using a c++ standard container like std::vector<std::vector<int>> myMatrix; instead of managing raw pointers.

Segmentation Fault (Cored Dumped) When Creating 3D Array w/ Pointers

Thanks in advance for any help!
I'm currently working my way through "Jumping into C++" by Alex Allain and so far its a great book as far as a crash course in C++. At least for me it is. Anywho I'm on chapter 14 which discusses using pointers for 2D arrays and one of the practice problems challenges the reader to create a 3D multiplication table array with arbitrary length, width, and height as chosen by the user at runtime. I think I've got the code up and working and thanks to someone on here I was able to get rid of all my compile errors associated with creating a 3D array using pointers.
I would post a picture of my problem but of course my reputation isn't high enough. Basically after I compile and run the program I enter 3 separate dimensions for height, width, and depth of the 3D array and then I get the exciting message of "Segmentation fault (core dumped). I have some debugging cout messages in my code but none of them show up which confuses me. I don't understand why my code would crash before the first debug message at the earliest. The only time it makes it anywhere is if I enter 1 for all three values. But then only the debugging messages show up and nothing actually prints like I think it should.
And here is my code:
#include <iostream>
using namespace std;
void printMultTable(int*** p_cube, int height, int width, int depth);
int main() {
int height = 0;
int width = 0;
int depth = 0;
// Get user input for height, witdth, and depth of multiplication cube
cout << "Enter height: ";
cin >> height;
cout << "Enter width: ";
cin >> width;
cout << "Enter depth: ";
cin >> depth;
cout << "Made it to point A";
// Create pointer to pointer for multiplication tables
int ***p_cube = new int**[depth]; // Creates pointer to 2D pointer array (Layers of Cube)
cout << "Made it to point B";
for (int i = 0; i < height; i ++) {
p_cube[i] = new int*[height]; // Creates pointer to 1D array (Columns of Cube)
for (int j = 0; i < width; i++) {
p_cube[i][j] = new int[width]; // Creats pointers that are arrays (Rows of Cube)
}
}
cout << "Made it to point C";
// Create multiplication table
for (int i = 0; i < depth; i++) {
for (int j = 0; j < height; j++) {
for (int k = 0; k < width; k++) {
p_cube[i][j][k] = (j+1) * (k+1);
}
}
}
cout << "Made it to point D";
// Use printMultTable to print out multiplication table
printMultTable(p_cube, height, width, depth);
// Deallocate memory taken by pointers
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++){
delete[] p_cube[i][j];
}
delete p_cube[i];
}
delete[] p_cube;
}
void printMultTable(int*** p_cube, int height,int width,int depth) {
for (int i = 0; i < depth; i++) {
for (int j = 0; j < height; j++) {
for (int k = 0; k < width; k++) {
cout << p_cube[i][j][k] << "\t";
}
cout << "\n";
}
cout << "\n\n\n";
}
}
As you might notice I have 4 separate debugging checkpoints that say "Made it to point __". The problem is it doesn't even make it to point "A". I'm not sure if this is an error that the compiler skipped over because it thought the code was kosher or if its something with my computer or something else I can't think of. Pointers have got to be the most confusing thing that almost makes sense that I've ever learned haha.
Any and all help or thoughts would be greatly appreciated!
Thanks!
Zak
This code:
for (int i = 0; i < height; i ++) {
p_cube[i] = new int*[height]; // Creates pointer to 1D array (Columns of Cube)
for (int j = 0; i < width; i++) {
p_cube[i][j] = new int[width]; // Creats pointers that are arrays (Rows of Cube)
}
}
Should be:
for (int i = 0; i < depth; i ++) {
p_cube[i] = new int*[height]; // Creates pointer to 1D array (Columns of Cube)
for (int j = 0; j < height; j++) {
p_cube[i][j] = new int[width]; // Creats pointers that are arrays (Rows of Cube)
}
}
first for loop must go from 0 to depth
second for loop must go from 0 to height
you were comparing and increasing i instead of j in the second for loop
The immediately obvious problem is that you are using height as the range of the first loop while there are depth objects.
int ***p_cube = new int**[depth];
// ...
for (int i = 0; i < height; i ++) {
p_cube[i] = new int*[height];
// ...
}
If depth != height you'll either have out of bound accesses or you'll access uninitialized memory.
The other issue is you don't check your points which is an extremely bad idea! If the input fails you'll get a random value. Always check after reading that it was successful:
if (std::cin >> depth) { ... }
If the author of the book promotes naked allocations and unchecked reads he does you a great disservice!
and good luck learning!
first, i think learning about int*** like this is not a good way to start, as it is very confusing AND inefficient. i recommend simply allocating one block of memory with width*height*depth elements. to traverse through the elements, you can simply iterate index from [0 .. width*height*depth]. to access a particular element, you can calculate it like so: index = i*(width*height) + j*(width) + k.
but to answer your question, i noticed you made a mistake here:
int ***p_cube = new int**[depth];
for (int i = 0; i < height; i ++) {
p_cube[i] = new int*[height];
...
you've made a new array of int** of size 'depth', but then you iterate over it as if it had 'height' elements in it. the correct thing to do is iterate over 'depth' elements, and allocate an int* array.

C++ Multi-dimensional Arrays on the Heap

How would I go about dynamically allocating a multi-dimensional array?
If you know the size of nested dimensions already, you can also literally allocate a multi dimensional array using new:
typedef int dimensions[3][4];
dimensions * dim = new dimensions[10];
dim[/* from 0 to 9 */][/* from 0 to 2 */][/* from 0 to 3 */] = 42;
delete [] dim;
instead of 10, a runtime determined value can be passed. Since it's not part of the type operator new returns, that's allowed. This is nice if you know the number of columns, but want to keep the number of rows variable, for example. The typedef makes it easier to read the code.
For the sake of completeness, here is a better way to do it in C++ when you know the array bounds ahead of time. The benefit of using the following class is that you don't have to care about calling delete[] on your data. This means that this class will be exception-safe, and all of the other great stuff about RAII.
template<typename T, int width, int height>
class MultiArray
{
private:
typedef T cols[height];
cols * data;
public:
T& operator() (int x, int y) { return data[x][y]; }
MultiArray() { data = new cols[width]; }
~MultiArray() { delete [] data; }
};
Usage:
MultiArray<int, 10, 10> myArray;
myArray(2, 3) = 4;
cout << myArray(2, 3);
edit: and, while I'm at it, here is the setup you can use if you don't know the array bounds until runtime:
template<typename T>
class Array2D
{
private:
const int width;
T * data;
public:
T& operator() (int x, int y) { return data[y*width + x]; }
Array2D(const int w, const int h) : width(w) { data = new T[w*h]; }
~Array2D() { delete [] data; }
};
Usage:
Array2D myArray(10, 10);
myArray(3, 4) = 42;
cout << myArray(3, 4);
How about using Boost.Multiarray ? I believe it answers your need quite well !
http://www.boost.org/doc/libs/1_37_0/libs/multi_array/doc/user.html#sec_introduction
Here is an excerpt from the documentation page :
#include < boost/multi_array.hpp >
#include < cassert >
int main ()
{
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array< double, 3 > array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
// Assign values to the elements
int values = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
A[i][j][k] = values++;
// Verify values
int verify = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
assert(A[i][j][k] == verify++);
return 0;
}
See this:
C++ FAQ by Marshall Cline
See "How do I allocate multidimensional arrays using new?" and "But the previous FAQ’s code is SOOOO tricky and error prone! Isn’t there a simpler way?" sections.
std::vector<std::vector<int> >should be mentioned, as it's often the simplest way. However, be aware that it is non-rectangular. Not every std::vector<int> needs to have the same length.
I'm surprised no one has mentioned boost::multi_array yet. I needed a 2D array in a program just last week, and found it to be a lot easier, and quicker to code, than the home-brewed solutions that I've come up with before (all of which are mentioned in other comments).
Here's the implementation I've got; I declare a single contiguous block of ints instead of creating new blocks inside my for loop, so I'm not causing page faults all over the place. Thanks to eJames for pointing out why this code was broken originally.
int width = 10, height = 10, totalSize = width*height;
int **myArray = new int*[width];
int *data = new int[totalSize];
for ( int i = 0; i < height; ++i )
{
myArray[i] = data + (i*width);
}
// do some things here
delete[] data;
delete[] myArray;
Your loop would not write the pointer values into myArray properly. I would suggest the following instead:
int width = 10;
int height = 10;
int ** myArray = new int*[width];
int * data = new int[width*height];
int * index = data;
for (int i = 0; i < width; i++)
{
myArray[i] = index;
index += height;
}
// ...
delete[] data;
delete[] myArray;
As another alternative, STLSoft includes a fixed_array_2d class (as well as 3D and 4D versions). Compared with the homebrewed solutions given here, it has a similar implementation but a more complete feature set (full support for iterators, etc.). Compared with boost::multi_array, it's lighter weight and easier on not-quite-compliant C++ compilers but (intentionally) lacks some of multi_array's features.
You can index a one dimensional as a 2, 3, or N dimensional one if you just space over the correct amount of elements. For example, if I've got 10 rows and 10 columns, I know that if I'm on row 3 I will have to go over at least 30 elements to get to it.
Somehow I prefer this notation for simple 2D arrays since I don't need to worry about nested levels of pointers. The downside is the messier index notation. Here's an example with a 2D array with n rows and m columns:
int *matrix = new int[n*m];
//set element (3,7) to 10
matrix[3*m+7] = 10;
//print the matrix
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cout << matrix[i*m+j] << ' ';
}
cout << '\n';
}
This a reproduction of a post on another thread. It does exactly what you want, without needing to know the array dimensions ahead of time, and without using boost or STL.
Heres a routine which allocates the 3D array of dimension N1 x N2 x N3 in contiguous memory space while allowing you the a[i][j][k] syntax for operator access. The array is dynamic but continuous so it's a huge plus over the vector<> approach and loops of new[] calls.
template <class T> T ***Create3D(int N1, int N2, int N3)
{
T *** array = new T ** [N1];
array[0] = new T * [N1*N2];
array[0][0] = new T [N1*N2*N3];
int i,j,k;
for( i = 0; i < N1; i++) {
if (i < N1 -1 ) {
array[0][(i+1)*N2] = &(array[0][0][(i+1)*N3*N2]);
array[i+1] = &(array[0][(i+1)*N2]);
}
for( j = 0; j < N2; j++) {
if (j > 0) array[i][j] = array[i][j-1] + N3;
}
}
cout << endl;
return array;
};
template <class T> void Delete3D(T ***array) {
delete[] array[0][0];
delete[] array[0];
delete[] array;
};
And later in your implementation routine...
int *** array3d;
int N1=4, N2=3, N3=2;
int elementNumber = 0;
array3d = Create3D<int>(N1,N2,N3);
//equivalently, a 'flat' array could be obtained with
//int * array = array3d[0][0];
cout << "{" << endl;
for (i=0; i<N1; i++) {
cout << "{";
for (j=0; j<N2; j++) {
cout << "{";
for (k=0; k<N3; k++) {
array3d[i][j][k] = elementNumber++;
cout << setw(4) << array3d[i][j][k] << " ";
//or if you're using the flat array:
//array[i*N2*N3 + j*N3 + k] = elementNumber++;
}
cout << "}";
}
cout << "}";
cout << endl ;
}
cout << "}" << endl;
Delete3D(array3d);
Gives the output:
{
{{ 0 1 }{ 2 3 }{ 4 5 }}
{{ 6 7 }{ 8 9 }{ 10 11 }}
{{ 12 13 }{ 14 15 }{ 16 17 }}
{{ 18 19 }{ 20 21 }{ 22 23 }}
}