I want to swap two lines in a matrix. My matrix is an allocated solid block of memory.
I have an array of pointers that point to the rows of the matrix. The first pointer points to this big allocated block. And other pointers point to different parts or this block.
If I swap any two rows, except the first, it's OK. But I have problems with the first row.
I guess that's because the pointer to the first row is different from other. But what is the main difference?
#include <iostream>
int** allocateMatrix(int rows, int cols) {
// allocating array of pointers (rows)
int** matrix = new int*[rows];
// allocating one solid block for the whole matrix
matrix[0] = new int[rows*cols];
// setting the pointers for rows
for ( int i = 1; i < rows; ++i ) {
matrix[i] = matrix[i-1] + cols;
}
// fill the matrix with consecutive numbers
int k = 1;
for ( int i = 0; i < rows; ++i ) {
for ( int j = 0; j < cols; ++j ) {
matrix[i][j] = k;
k += 1;
}
}
return matrix;
}
void freeMatrix(int** matrix) {
delete[] matrix[0];
delete[] matrix;
}
int main() {
int n = 3;
int m = 3;
int** matrix = allocateMatrix(n, m);
// swap the first and the second line
int* tmp = matrix[0];
matrix[0] = matrix[1];
matrix[1] = tmp;
// print matrix (it is printing ok)
for ( int i = 0; i < n; ++i ) {
for ( int j = 0; j < m; ++j ) {
std::cout << matrix[i][j] << ' ';
}
std::cout << std::endl;
}
// problem is here
freeMatrix(matrix);
return 0;
}
The main difference is that the first pointer was returned by new[]. Deleting that pointer will deallocate the entire memory block, but deleting any other pointer in the array will have undefined behaviour.
You could store the pointer which you get from new[] separately, and have a duplicate "weak" pointer to the first row that you keep in the array of row pointers.
Your code won't work if you swap first (0) and second (1) rows because you are using matrix[0] to delete the memory allocation.
You need to somehow "keep" the original allocation, e.g.
int *origalloc;
...
origalloc = matrix[0] = new int[rows*cols];
...
delete[] origalloc; // Instead of malloc[0];
What you pass to delete or delete [] must the the same pointer-value as what you get back from the new or new []. Anything else is undefined behaviour.
Related
I'm trying to delete my 2D array, but I consistently get errors when I try to delete it, we have to work backwards so I delete the elements first, then the column array, then the row array. here is my code for the constructor in my class, MyMatrix:
private:
int m; //rows
int **ptr; //ptr to first dimension
int n; // columns
public:
MyMatrix() //constructor
{
m = 0;
n = 0;
ptr = new int*[m];
int *length_arr = new int[m];
for (int i = 0; i <= m-1; i++)
{
*(ptr+i) = new int[n];
*(length_arr+i) = n;
}
}
and my destructor looks like this:
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
the error I'm getting is:
assg7(2677,0x100de3d40) malloc: *** error for object 0x12d606804: pointer being freed was not allocated
I've wracked my brain for where I can fix this, for context, I'm doing an assignment with operator overloading. I specifically need a delete function to work properly for my = assignment overloading since I want to delete and again reallocate memory to equate two matrices, but the terminal is showing malloc errors and is thus not equating the matrices.
for additional info here is my = overloading code:
void operator = (const MyMatrix &obj)
{
if(n == obj.n && m == obj.m)
{
//for loop to equate elements in this-> to the elements of the passed object
}
else
{
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
// the code for assigning new memory according to the passed objects rows and colums goes here
//then for loop to equate elements in this-> to the elements of the passed object
}
}
thanks.
You have two "levels" of new, so three "levels" of delete can't be right.
Spell out your deletion loop, using indexing instead of pointer arithmetic:
First iteration:
delete ptr[0]+0;
delete ptr[0]+1;
...
delete ptr[0]+n-1;
delete [] ptr[0];
Second iteration:
delete ptr[1]+0;
delete ptr[1]+1;
...
delete ptr[1]+n-1;
delete [] ptr[1];
You're passing to delete a pointer to the first element of ptr[0], a pointer to the second element of ptr[0], a pointer to the third element of ptr[0], ...
But the things you allocated were ptr[0], ptr[1], ... ptr[m-1], not their individual elements.
Remove the innermost deletion loop.
(And don't mess around with pointer arithmetic when you can use indexing.)
I don't know how you would want to allocate memory space by m length if it is set to 0 by default.
To me it looks like you set m = 0 and then try to allocate by 0 length or how do you control the length of your dimensions?
Maybe edit your constructor to:
MyMatrix(int m, int n)
{
this->m = m;
this->n = n;
...
This question already has answers here:
How do I declare a 2d array in C++ using new?
(29 answers)
Closed 4 years ago.
Dont know how to do this. Tried something like below.Want more optimisation in code.
Everyting should be in one function only,
guide me how to open close a file,
how to find character in each line,
increase the counter.
void simpleFileIn(void) {
string line;
ifstream myfile("example.txt");
if (myfile.is_open()) {
while (getline(myfile, line)) {
//found(line);
size_t size = strlen(line);
cout << line << '\n';
}
myfile.close();
}
else
cout << "Unable to open file";
}
the function simpleFileIn() should work, to open a file then close after work is done.
find out character a and count the integers.
want to close/ delete this question as i am in ban asking more help me. situation getting worse day after day
You need to allocate rows in a loop as you go:
int** pptr = new int* [rows]; // <<== rows, not cols
for(int i=0;i<rows;i++){
pptr[i] = new int[cols]; // <<== Add this line
for(int j=0;j<cols;j++){
cout<<"Enter value at "<<i<<j<<endl;
cin>>pptr[i][j];
cout<<"Value is "<<pptr[i][j]<<endl;
}
}
You also need to delete individual rows before deleting the array of pointers to them. Use delete[] operator with square brackets:
for(int i=0;i<rows;i++){
delete[] pptr[i];
}
delete[] pptr;
You do not need to assign NULLs to deleted pointers, unless you plan to reuse the pointer for something else later on.
You are allocing array of pointers wrong.
First you have to allocate enough space for row pointers
int** pptr = new int* [rows];
For every pointer enough space for col integers
for (int i = 0; i < cols; i++)
{
pptr[i] = new int [cols];
}
To delete arrays use delete[] instead of delete.
Delete every individual row
for (int i = 0; i < rows; i++)
{
delete [] pptr[i];
}
Then delte array of pointers
delete [] pptr;
There is no need to assigning NULL to deleted pointer since you wont use them again. Also in c++ you should use nullptr instead of NULL.
Here is the correct using of array of pointers.
Your mistakes
int* ptr = new int [rows];
int** pptr = new int* [cols];
*pptr=ptr;
Swapped rows & cols
Allocated memory only for first pointer/row, others were uninitialized -> UB
Used delete instead of delete[]
So there seems to be some confusion with allocation. From your code
int* ptr = new int [rows];
int** pptr = new int* [cols];
*pptr=ptr;
you have now created to 1-dimensional arrays. You then dereference the pptr and assign to it ptr this is the same as
pptr[0] = ptr;
So you are only initializing the very first column. You want to change this code to be
int** pptr = new int* [cols];
for (int i = 0; i < cols; ++i) {
pptr[i] = new int [rows];
}
This will allocate the memory properly
You can create a constructor of sorts for your 2D array so that you have one-line bookkeeping:
#include <iostream>
template <typename T>
T** new_( std::size_t rows, std::size_t columns )
{
auto dsize = rows * sizeof(T*);
auto rsize = columns * sizeof(T);
auto tsize = rows * rsize;
unsigned char* data = new unsigned char[ dsize + tsize ];
T** result = (T**)data;
T* table = (T*)(data + dsize);
while (rows--)
result[ rows ] = table + rows * columns;
return result;
}
int main()
{
int m; std::cout << "m? "; std::cin >> m;
int n; std::cout << "n? "; std::cin >> n;
// Create the new matrix
int** a = new_<int>( m, n );
// Do stuff with a[ r ][ c ] here.
// It looks and behaves JUST LIKE a normal 2D C array
// in all respects EXCEPT one: &a != &(a[0][0]).
// Use the latter when passing to a flat function!
// Delete it
delete [] a;
}
Enjoy the weirdness.
So for a project I have i need to create a function to 'Resize' the first dimension of a dynamically allocated 3d array of shorts, the function cant alter the original data and must only alter the first dimension of the array.
3darray[alter this][stays the same][stays the same]
The variables passed into the function are the pointer that points to the 3d array, the old size, and the new size.
Ive tried this:
void reallocShort3d(short ***&ptr, size_t oldSize, size_t newSize)
{
short *** temp;
temp = (short***) realloc(ptr,(newSize - oldSize) * sizeof(ptr));
ptr = temp;
}
but it does not seem to be working, any idea on where i went wrong and possible solutions?
Thanks
EDIT: I realise that I can't use realloc now as th 3d array was created with new, we are only given the old and new sizes of the first dimension and the array itself, we are not allowed to use vectors:
/**
* #brief reallocates/resizes a 3D array of shorts to fit into a new size.
* Size here refers to the first dimension. i.e. ptr[size][row][col].
*
* #note after the function executed, the original data in the array must
* not be altered in any way. That is to say, only the first dimension of
* ptr may be altered.
*
* #NOTE! this function must work in general
*
* #param ptr is the pointer that refers to the 3D array to be resized.
* #param oldSize is the current total number of elements in the first
* dimension of ptr. e.g. ptr[this amount here][row][col]
* #param newSize is the new size that ptr will have after the function
* has been executed. ptr[the new amount here][row][col]
*/
SECOND EDIT:
Heres the code used to allocate the 3d array:
ptr = new short**[2];
for (int i = 0; i < 2; i++)
{
ptr[i] = new short*[12];
for (int j = 0; j < 12; ++j)
{
ptr[i][j] = new short[numDaysinMonth(j)];
}
}
Given the way OP's code allocates the memory, a simple way to resize it is:
short ***tmp;
// in OP's code rows = 12 while the inner dimension is the number of days in a month
// so we can use cols = 31
tmp = new short**[newSize];
// copy the old data
for ( size_t i = 0; i < oldSize; ++i ) {
tmp[i] = ptr[i];
}
// allocate memory for the new data
for ( size_t i = oldSize; i < newSize; ++i ) {
tmp[i] = new short*[rows];
for ( size_t j = 0; j < rows; ++j ) {
tmp[i][j] = new short[cols];
}
}
delete[] ptr;
ptr = tmp;
EDIT
The comment of #PaulMcKenzie points out a major flaw in this code. In C++, operator new throws an exception when it's unable to allocate the requested memory. If this happens, our options are limited and in most cases the only thing we can do is some clean up and exit the program.
In the following snippet I'll try to rewrite the function with OP's signature (which I personally, don't like) and to avoid the possible memory leaks. This function eventually rethrows a std::bad_alloc exception and it is up to the caller to deal with it (which, I'm pretty much sure, OP's code doesn't).
I'd like to remark that a far better practice would be to stick to the Standard Library containers and/or encapsulate all the memory managment in a class, to ensure RAII.
void reallocShort3d(short ***&ptr, size_t oldSize, size_t newSize, size_t rows, size_t cols ) {
short ***tmp = nullptr;
std::bad_alloc ee;
try {
tmp = new short**[newSize];
size_t i = 0, j = 0, ii, jj, kk;
for ( ; i < oldSize; ++i ) {
tmp[i] = ptr[i];
}
for ( ; i < newSize; ++i ) {
try {
tmp[i] = new short*[rows];
for ( j = 0; j < rows; ++j ) {
try {
tmp[i][j] = new short[cols];
}
catch ( const std::bad_alloc &e ) {
for ( jj = 0; jj < j; ++jj ) {
delete[] tmp[i][jj];
}
delete[] tmp[i];
throw e;
}
}
}
catch ( const std::bad_alloc &e ) {
for (ii = oldSize; ii < i; ++ii) {
for ( jj = 0; jj < rows; ++jj ) {
delete[] tmp[ii][jj];
}
delete[] tmp[ii];
}
delete[] tmp;
throw e;
}
}
delete[] ptr;
ptr = tmp;
}
catch ( const std::bad_alloc &e ) {
std::cout << "Error: unable to reallocate.\n";
throw e;
}
}
As alluded to in the comments, the signature of the reallocate function is not sufficient for the general case as one requires knowledge of the rows, cols and slices of the original 3D array to be able to perform reallocation.
So, assuming you can fix the method signature for the general case the following is a possible solution:
void reallocate_short_3d_arr(short***& ptr, std::size_t new_rows, std::size_t old_rows,
std::size_t cols, std::size_t slices) {
// allocate memory for tmp 3d arr
short*** tmp = new short**[new_rows];
for (std::size_t i = 0; i < new_rows; ++i) {
tmp[i] = new short*[cols];
for (std::size_t j = 0; j < cols; ++j)
tmp[i][j] = new short[slices];
}
// select correct rows for contraction or expansion of ptr
std::size_t tmp_rows = (new_rows > old_rows) ? old_rows : new_rows;
// copy all entries from ptr to tmp
for (std::size_t i = 0; i < tmp_rows; ++i) {
for (std::size_t j = 0; j < cols; ++j) {
for (std::size_t k = 0; k < slices; ++k)
tmp[i][j][k] = ptr[i][j][k];
}
}
// delete original ptr memory
for (std::size_t i = 0; i < old_rows; ++i) {
for (std::size_t j = 0; j < cols; ++j) {
delete[] ptr[i][j];
}
delete[] ptr[i];
}
delete[] ptr;
// assign ptr to tmp such that ptr points to reallocated memory
ptr = tmp;
}
One could probably optimise this via using std::move to assign the contents of ptr to tmp instead fairly trivially as the original ptr contents is deleted afterwards anyway so it is safe to move it.
Of course, this is all very silly C++ though and could be easily achieved via std::vector as follows:
std::vector<std::vector<std::vector<short>>> vec_3d(rows,
std::vector<std::vector<short>>(cols,
std::vector<short>(slices))); // initialise "3D vector" of dims rows*cols*slices
vec_3d.resize(new_rows); // resize just the rows, leaving slices and columns the same
Ok, so I'm quite new to C++ and I'm sure this question is already answered somewhere, and also is quite simple, but I can't seem to find the answer....
I have a custom array class, which I am using just as an exercise to try and get the hang of how things work which is defined as follows:
Header:
class Array {
private:
// Private variables
unsigned int mCapacity;
unsigned int mLength;
void **mData;
public:
// Public constructor/destructor
Array(unsigned int initialCapacity = 10);
// Public methods
void addObject(void *obj);
void removeObject(void *obj);
void *objectAtIndex(unsigned int index);
void *operator[](unsigned int index);
int indexOfObject(void *obj);
unsigned int getSize();
};
}
Implementation:
GG::Array::Array(unsigned int initialCapacity) : mCapacity(initialCapacity) {
// Allocate a buffer that is the required size
mData = new void*[initialCapacity];
// Set the length to 0
mLength = 0;
}
void GG::Array::addObject(void *obj) {
// Check if there is space for the new object on the end of the array
if (mLength == mCapacity) {
// There is not enough space so create a large array
unsigned int newCapacity = mCapacity + 10;
void **newArray = new void*[newCapacity];
mCapacity = newCapacity;
// Copy over the data from the old array
for (unsigned int i = 0; i < mLength; i++) {
newArray[i] = mData[i];
}
// Delete the old array
delete[] mData;
// Set the new array as mData
mData = newArray;
}
// Now insert the object at the end of the array
mData[mLength] = obj;
mLength++;
}
void GG::Array::removeObject(void *obj) {
// Attempt to find the object in the array
int index = this->indexOfObject(obj);
if (index >= 0) {
// Remove the object
mData[index] = nullptr;
// Move any object after it down in the array
for (unsigned int i = index + 1; i < mLength; i++) {
mData[i - 1] = mData[i];
}
// Decrement the length of the array
mLength--;
}
}
void *GG::Array::objectAtIndex(unsigned int index) {
if (index < mLength) return mData[index];
return nullptr;
}
void *GG::Array::operator[](unsigned int index) {
return this->objectAtIndex(index);
}
int GG::Array::indexOfObject(void *obj) {
// Iterate through the array and try to find the object
for (int i = 0; i < mLength; i++) {
if (mData[i] == obj) return i;
}
return -1;
}
unsigned int GG::Array::getSize() {
return mLength;
}
I'm trying to create an array of pointers to integers, a simplified version of this is as follows:
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
Now the problem is that the same pointer is used for j in every iteration. So after the loop:
array[0] == array[1] == array[2];
I'm sure that this is expected behaviour, but it isn't quite what I want to happen, I want an array of different pointers to different ints. If anyone could point me in the right direction here it would be greatly appreciated! :) (I'm clearly misunderstanding how to use pointers!)
P.s. Thanks everyone for your responses. I have accepted the one that solved the problem that I was having!
I'm guessing you mean:
array[i] = &j;
In which case you're storing a pointer to a temporary. On each loop repitition j is allocated in the stack address on the stack, so &j yeilds the same value. Even if you were getting back different addresses your code would cause problems down the line as you're storing a pointer to a temporary.
Also, why use a void* array. If you actually just want 3 unique integers then just do:
std::vector<int> array(3);
It's much more C++'esque and removes all manner of bugs.
First of all this does not allocate an array of pointers to int
void *array = new void*[2];
It allocates an array of pointers to void.
You may not dereference a pointer to void as type void is incomplete type, It has an empty set of values. So this code is invalid
array[i] = *j;
And moreover instead of *j shall be &j Though in this case pointers have invalid values because would point memory that was destroyed because j is a local variable.
The loop is also wrong. Instead of
for (int i = 0; i < 3; i++) {
there should be
for (int i = 0; i < 2; i++) {
What you want is the following
int **array = new int *[2];
for ( int i = 0; i < 2; i++ )
{
int j = i + 1;
array[i] = new int( j );
}
And you can output objects it points to
for ( int i = 0; i < 2; i++ )
{
std::cout << *array[i] << std::endl;
}
To delete the pointers you can use the following code snippet
for ( int i = 0; i < 2; i++ )
{
delete array[i];
}
delete []array;
EDIT: As you changed your original post then I also will append in turn my post.
Instead of
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
there should be
Array array;
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject( new int( j ) );
}
Take into account that either you should define copy/move constructors and assignment operators or define them as deleted.
There are lots of problems with this code.
The declaration void* array = new void*[2] creates an array of 2 pointers-to-pointer-to-void, indexed 0 and 1. You then try to write into elements 0, 1 and 2. This is undefined behaviour
You almost certainly don't want a void pointer to an array of pointer-to-pointer-to-void. If you really want an array of pointer-to-integer, then you want int** array = new int*[2];. Or probably just int *array[2]; unless you really need the array on the heap.
j is the probably in the same place each time through the loop - it will likely be allocated in the same place on the stack - so &j is the same address each time. In any case, j will go out of scope when the loop's finished, and the address(es) will be invalid.
What are you actually trying to do? There may well be a better way.
if you simply do
int *array[10];
your array variable can decay to a pointer to the first element of the list, you can reference the i-th integer pointer just by doing:
int *myPtr = *(array + i);
which is in fact just another way to write the more common form:
int *myPtr = array[i];
void* is not the same as int*. void* represent a void pointer which is a pointer to a specific memory area without any additional interpretation or assuption about the data you are referencing to
There are some problems:
1) void *array = new void*[2]; is wrong because you want an array of pointers: void *array[2];
2)for (int i = 0; i < 3; i++) { : is wrong because your array is from 0 to 1;
3)int j = i + 1; array[i] = *j; j is an automatic variable, and the content is destroyed at each iteration. This is why you got always the same address. And also, to take the address of a variable you need to use &
CASE1:
int nrows=5;
int ncols=10;
int **rowptr;
rowptr=new int*;
for(int rows=0;rows<nrows;rows++) {
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
CASE2:
int nrows=5;
int ncols=10;
int **rowptr;
for(int rows=0;rows<nrows;rows++) {
rowptr=new int*;
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
I am able to insert and print values using both ways. What is the difference in initializations?
What is the difference?
#1 just allocates memory enough to hold a integer pointer and not an array of integer pointers.
#2 Causes a memory leak by just overwritting the memory allocation of the previous iteration.
I am able to insert and print values using both the ways
Memory leaks and Undefined behaviors may not produce immediate observale erroneous results in your program but they sure are good cases of the Murphy's Law.
The correct way to do this is:
int nrows = 5;
int ncols = 10;
//Allocate enough memory for an array of integer pointers
int **rowptr = new int*[nrows];
//loop through the array and create the second dimension
for (int i = 0;i < nrows;i++)
rowptr[i] = new int[ncols];
You have a memory leak in both cases.
The proper way to initialize such a "2d" array is
int** arr = new int*[nrows];
for (int i = 0; i < nrows; i++)
arr[i] = new int[ncols];
Note however, that it isn't a 2d array as defined by C/C++. It may not, and probably will not, be consecutive in memory. Also, the assembly code for accessing members is different.
In your case, the accessing by indexing is equivalent to *(*(arr+i)+j)
And in the case of a 2d array it's *(arr + N_COLS*i + j) when N_COLS is a compile time constant.
If you want a true 2d array you should do something like this:
int (*arr)[N_COLS] = (int(*)[N_COLS])(new int[N_ROWS * N_COLS])
You'd better use 1d array to manage 2d array
int **x = new int*[nrows];
x[0] = new int[nrows*ncols];
for (int i = 1; i < nrows; i++)
x[i] = x[i-1] + ncols;
for (int i = 0; i < nrows; i++)
for (int j = 0; j < ncols; j++)
x[i][j] = 0;
delete [] x[0];
delete [] x;