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).
Related
I'm trying to copy an array from one class to to another class by passing it to a function but I'm running into issues. The array that I'm trying to copy seems to lose all its data.
// A.h
class A
public:
virtual void Test();
private:
A* array2D[30][32];
// A.cpp
void A::Test()
{
B* f = new B();
f->pass(array2D);
}
// B.h
class A;
class B
{
public:
void pass(A *a[][32]);
private:
A *a[30][32];
}
// B.cpp
void B::pass(A *array2D[][32])
{
for (int i = 0; i <= 30; i++)
{
for (int j = 0; j <= 32; j++)
{
a[i][j] = array2D[i][j];
}
}
}
My guess is that it's happening when I'm passing it but I'm not sure what I'm doing wrong.
My guess is that it's happening when I'm passing it but I'm not sure what I'm doing wrong.
First, your for loops to populate the array go out-of-bounds on the last iteration of the nested for loop:
void B::pass(A *array2D[][32])
{
for (int i = 0; i <= 30; i++) // This goes out-of-bounds on the last iteration
{
for (int j = 0; j <= 32; j++) // This also goes out-of-bounds.
{
a[i][j] = array2D[i][j];
}
}
}
Using <= in a for loop is an indication that things can go wrong, and they do go wrong with your code. The fix would simply be:
void B::pass(A *array2D[][32])
{
for (int i = 0; i < 30; i++)
{
for (int j = 0; j < 32; j++)
{
a[i][j] = array2D[i][j];
}
}
}
This will work, however it is inefficient (unless a great optimizing compiler sees that this is inefficient and changes the code).
The better way to do this is a simple call to std::copy:
#include <algorithm>
void B::pass(A *array2D[][32])
{
std::copy(&array2D[0][0], &array2D[29][32], &a[0][0]);
}
The reason why this works is that two-dimensional arrays in C++ have their data layout in contiguous memory, thus it is essentially a one-dimensional array. So giving the starting and ending address of the array elements is all that's required.
A compiler will more than likely see that you are copying a trivially-copyable type (a pointer), thus the call to std::copy results in a call to memcpy.
I am trying to create a merge function for two array structures in c++ but am coming up with a bad access error that I don't know how to solve. The error comes up when I am trying to swap the element in the smaller array into the larger, merged array. The code doesn't even go through a single iteration. All three of i, j, and k remain at 0. Any help would be greatly appreciated! Here is the code:
struct Array
{
int *A;
int size;
int length;
};
void display(Array arr){
for (int i = 0; i < arr.length; i++)
std::cout << arr.A[i] << std::endl;
}
Array merge(Array arr1, Array arr2){
Array arr3;
arr3.length = arr1.length + arr2.length;
arr3.size = arr1.length + arr2.length;
int i = 0, j =0, k =0;
while(i <arr1.length && j < arr2.length){
if (arr1.A[i] < arr2.A[j])
{
arr3.A[k] = arr1.A[i]; //(The error is displayed here: Thread 1: EXC_BAD_ACCESS (code=1, address=0x28))
k++;
i++;
}
else if (arr2.A[j] < arr1.A[i])
{
arr3.A[k] = arr2.A[j];
k++;
j++;
}
}
for (; i< arr1.length; i++)
{
arr3.A[k]=arr1.A[i];
k++;
}
for (; i< arr2.length; j++)
{
arr3.A[k]=arr2.A[j];
k++;
}
return arr3;
}
int main() {
Array arr1;
arr1.size = 10;
arr1.length = 5;
arr1.A = new int[arr1.size];
arr1.A[0]= 2;
arr1.A[1]= 6;
arr1.A[2]= 10;
arr1.A[3]= 15;
arr1.A[4]= 25;
Array arr2;
arr2.size = 10;
arr2.length = 5;
arr2.A = new int[arr2.size];
arr2.A[0]= 3;
arr2.A[1]= 4;
arr2.A[2]= 7;
arr2.A[3]= 18;
arr2.A[4]= 20;
Array arr3 = merge(arr1, arr2);
display(arr3);
return 0;
}
Your Array arr3 does not allocate any memory for its int *A field. It's natural that it would not work.
Anyway, your implementation of Array is very poor. Don't reimplement arrays unless you have a good reason; use std::vector instead.
If you really need to implement an Array on your own, then learn about encapsulation, make a class with a constructor, and allocate/delete your data (*A) field properly. Remember, using pointers and heap memory without understanding them is a recipe for disaster.
Easy: arr3.A is not initialized. It's a pointer. What does it point to?
Suggestion: learn about dynamic memory allocation.
I'm writing a simple program within which a dynamic array is to be created. The function that is being used to create said array is in a second .cpp file, attached as a user-made library. Unfortunatelly Visual Studio pops an error saying that the program can't use uninitialized variable. I feel like it's a really easy problem to solve, but I don't know how to get through it. Here is the code:
int main()
{
int i = 5, j = 6;
string** Array;
createDefStruct(Array, i, j);
/*for (int k = 0; k < i; k++)
{
for (int m = 0; m < j; m++)
{
Array[i][j] = "YIKES";
cout << Array[i][j] << '\t';
}
cout << endl;
}*/
deleteDefStruct(Array, i);
return 0;
}
The createDefStruct function:
void createDefStruct(string** Arr, int varAttribCount, int varCount)
{
Arr = new string * [varAttribCount+1];
for (int i = 0; i < varAttribCount+1; i++)
Arr[i] = new string[varCount];
}
How do I go about initilizing a variable?
Thank you in advance!
So the problem is that instead of returning your array from the function you passed the array into the function as parameter. This mean that the variable is uninitialised in main (even though it is initiialised in createDefStruct). Rewrite like this
string** createDefStruct(int varAttribCount, int varCount)
{
string** Arr = new string * [varAttribCount+1];
for (int i = 0; i < varAttribCount+1; i++)
Arr[i] = new string[varCount];
return Arr;
}
int main()
{
int i = 5, j = 6;
string** Array = createDefStruct(i, j);
...
In general when you want a function to return a value you use return from inside the function to return that value. When you want to pass a value into a function you use a parameter. In your createDefStruct function varAttribCount and varCount are the parameters but the array should be a return value.
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.
I have made a class that's supposed to make a symmetric toeplitz matrix (see here). The implementation of the class is shown here
class toeplitz{
private:
int size;
double* matrix;
public:
toeplitz(const double* array, const int dim){
size = dim;
matrix = new double(size*size);
for(int i = 0; i < size; i++){
for (int j = 0; j < size; j++){
int index = std::abs(i - j);
matrix[i*size + j] = array[index];
}
}
}
~toeplitz(){
delete[] matrix;
}
void print() const{
//loop over rows
for (int i = 0; i < size; i++){
//loop over colums
for (int j = 0; j < size; j++){
double out = matrix[i*size + j];
std::cout << std::setw(4) << out;
}
//start new line for each row
std::cout << "\n";
}
}
};
I can't see what's wrong with this, but when I try and use this in a simple test function, I get malloc errors. The main function I have is
int main(){
double array[] = {0,1,1,2};
int len = sizeof(array)/sizeof(array[0]);
std::cout<<"length of array " << len << std::endl;
toeplitz tp = toeplitz(array, len);
tp.print();
}
It compiles and runs when I leave out the tp.print() line, but when I add this line I get error
test_toeplitz(8747,0x7fffdbee63c0) malloc: *** error for object 0x7fb119402788:
incorrect checksum for
freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
I cannot figure out why this is. I've looked at the other questions about this on here but I can't tell how they relate to what I've done. As I understand it has to do with either double freeing memory or trying to modify memory after it's been freed, but I can't see where my code is doing that. Any insight into what's going on would be appreciated.
You stumbled on the classical:
matrix = new double(size*size);
which allocates a double worth size*size when you wanted to do:
matrix = new double[size*size];
to allocate an array of the proper size. So you get undefined behaviour. Sometimes it works sometimes not depending on the memory configuration.
Since you're using C++, I suggest you use std::vector<double> or Eigen matrix template, and drop C arrays forever (no more memory leaks, no more failed allocations, possible boundary checking, only advantages)