I'm currently using a particular API such that I must use raw pointers, however given the particular arrangement of the pointers I'm not sure how to best go about clearing the memory and avoiding any undefined behaviour in doing so.
double *data1 = new double[rows*columns];
double **data2 = new double*[rows];
data2[0] = data1; // Point to first row
for (int i = 1; i < columns; i++) {
data2[i] = data2[i - 1] + rows;
}
I've attempted something like below, but I don't think it's right.
for(int i = 0; i < rows; i++) {
delete [] data2[i];
}
delete [] data2;
delete [] data1;
Who owns What?
Is the question which will dictate how you delete objects.
What I think you're doing is creating one large array to hold a two-dimensional array of data, and then creating another array to hold pointers to the beginning of each row.
So that's two news and therefore two deletes.
It might be easier to visualise like this:
struct matrix_view
{
int rows, columns;
// this pointer owns a block of doubles
double* entire_buffer = nullptr;
// this pointer owns a block of pointers, but not the memory
// they point to
double** row_pointers = nullptr;
};
matrix_view create_matrix(int rows, int columns)
{
auto result = matrix_view{ rows, columns, nullptr, nullptr };
auto size = rows * columns;
result.entire_buffer = new double [size];
result.row_pointers = new double* [rows];
auto first = result.entire_buffer;
auto last = first + size;
auto dest = result.row_pointers;
while (first != last) {
*dest++ = first;
first += columns;
}
return result;
}
void destroy_matrix(matrix_view m)
{
// always destroy in reverse order
delete [] m.row_pointers;
delete [] m.entire_buffer;
}
Related
I try to build a function which deletes the last element of an array. So I need an input array and its dimension, then delete the last term and obtain a new output array. I don't want that. My goal is to somehow make the output array the new input array. In other words, I want to overwrite the input array with the output array.
So if dimension is 4, I don't want to have a 4-dim array in the memory but only 3-dim table after the deletion.
void del (int* ptr_array, int dim) {
int* temp = ptr_array; //Hold the very first address of the input array.
ptr_array = new int[dim - 1]; // Let the address of the input array be
// the address of new output array. Overwritting.
for (int i = 0; i < dim - 1; i++) {
ptr_array = (temp+i); // Will it remember what is temp+1 if I have
// already overwritten the arrays?
ptr_array++;
}
//delete[] ptr_array; - this one is out of the questions - deletes now the input table.
}
Can you tell me what is wrong with this code? - in fact it doesn't change anything
in you function
for (int i = 0; i < dim - 1; i++) {
ptr_array = (temp+i); // Will it remember what is temp+1 if I have
// already overwritten the arrays?
ptr_array++;
}
does nothing, you wanted
for (int i = 0; i < dim - 1; i++) {
ptr_array[i] = temp[i];
}
Note the delete in your comment is invalid because you do not delete the result of a new[] but a pointer inside the allocated array
If the call is like
int * v = ...;
del(v);
// here v is unchanged
probably you wanted to modify v, in that case you can return the new array or to use an input-output variable using a reference
First possibility :
int* del (int* ptr_array, int dim) {
int* new_array = new int[dim - 1];
for (int i = 0; i < dim - 1; i++) {
new_array[i] = ptr_array[i];
}
delete[] ptr_array;
return new_array;
}
with
int * v = ...;
v = del(v);
Second possibility
void del (int*& ptr_array, int dim) {
int* new_array = new int[dim - 1];
for (int i = 0; i < dim - 1; i++) {
new_array[i] = ptr_array[i];
}
delete[] ptr_array;
ptr_array = new_array;
}
with
int * v = ...;
del(v);
// here v is the new array
Warning these codes suppose the input array has at least one element
However the use of an std::vector<int> does all of that for you and is more practical to use
std::vector<int> v;
...
v.resize(v.size() - 1);
or
std::vector<int> v;
...
v.pop_back();
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.
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.
Constructor
This is how I'm allocating it:
char **board = new char*[width];
for(i = 0; i < width; i++){
board[i] = new char[height];
for(j = 0; j < height; j++)
board[i][j] = 0;
}
this->board = &board;
Inside the class, it's:
char ***board;
Destructor:
Now I want to delete it, so I wrote this (the board it the class field):
for(i = 0; i < width; i++)
delete (*board)[i];
delete (*board);
When running this:
Board* b = new Board(16, 30, 99);
delete b;
I get an Unhandled exception. Why?
You are storing a pointer to a variable on the stack, which becomes invalid as soon as the constructor returns. You should declare your class's data member as char **board and assign this->board = board.
EDIT: See also #Kerrek SB's comment. The local variable is redundant. Just use the data member directly (without the this->).
EDIT 2: Rectangular arrays are best created as a single array, using pointer arithmetic to index (which is what the compiler does with declared 2D arrays anyway):
char *board;
...
board = new char[width*height];
for(i = 0; i < width*height; ++i){
board[i] = 0;
}
...
char& operator()(int i, int j) { return board[width*i + j]; }
This has the advantage of requiring just one memory allocation (and therefore one delete[]). It also improves cache locality because the cells are contiguous.
Even better, if you know the dimensions at compile-time, use templates:
template <int W, int H>
class Board {
char board[W][H];
...
};
...
Board<8, 8>* b = new Board<8, 8>(...);
This requires no memory allocation at all (other than the new Board, of course).
Anything that you new you need to delete, in the exact same way:
board = new char*[width];
...
board[i] = new char[height];
...
...
delete[] board[i];
delete[] board;
No dereferencing is needed in this case.
You should use the powers of C++.
class Board
{
std::vector<std::vector<char>> board;
public:
Board(std::vector<std::vector<char>> const& board) : board(board) {}
Board(size_t x, size_t y, char val = 0)
{
std::vector<char> x2(x, val);
this->board(y, x2);
}
};
All you've got to do now is board[y].push_back(char_x_val) in order to append a new element to the end. You can treat board[y][x] just like any other 2D array (well, almost), but not worry about the deallocation.
Read up more on vectors here. (Anyone know a good tutorial?)
How do you dynamically allocate a 2D matrix in C++?
I have tried based on what I already know:
#include <iostream>
int main(){
int rows;
int cols;
int * arr;
arr = new int[rows][cols];
}
It works for one parameter, but now for two. What should I do?
A matrix is actually can be represented as an array of arrays.
int rows = ..., cols = ...;
int** matrix = new int*[rows];
for (int i = 0; i < rows; ++i)
matrix[i] = new int[cols];
Of course, to delete the matrix, you should do the following:
for (int i = 0; i < rows; ++i)
delete [] matrix[i];
delete [] matrix;
I have just figured out another possibility:
int rows = ..., cols = ...;
int** matrix = new int*[rows];
if (rows)
{
matrix[0] = new int[rows * cols];
for (int i = 1; i < rows; ++i)
matrix[i] = matrix[0] + i * cols;
}
Freeing this array is easier:
if (rows) delete [] matrix[0];
delete [] matrix;
This solution has the advantage of allocating a single big block of memory for all the elements, instead of several little chunks. The first solution I posted is a better example of the arrays of arrays concept, though.
You can also use std::vectors for achieving this:
using: 'std::vector< std::vector >'
Example:
#include <vector>
std::vector< std::vector<int> > a;
//m * n is the size of the matrix
int m = 2, n = 4;
//Grow rows by m
a.resize(m);
for(int i = 0 ; i < m ; ++i)
{
//Grow Columns by n
a[i].resize(n);
}
//Now you have matrix m*n with default values
//you can use the Matrix, now
a[1][0]=1;
a[1][1]=2;
a[1][2]=3;
a[1][3]=4;
//OR
for(i = 0 ; i < m ; ++i)
{
for(int j = 0 ; j < n ; ++j)
{ //modify matrix
int x = a[i][j];
}
}
Try boost::multi_array
#include <boost/multi_array.hpp>
int main(){
int rows;
int cols;
boost::multi_array<int, 2> arr(boost::extents[rows][cols] ;
}
arr = new int[cols*rows];
If you either don't mind syntax
arr[row * cols + col] = Aij;
or use operator[] overaloading somewhere. This may be more cache-friendly than array of arrays, or may be not, more probably you shouldn't care about it. I just want to point out that a) array of arrays is not only solution, b) some operations are more easier to implement if matrix located in one block of memory. E.g.
for(int i=0;i < rows*cols;++i)
matrix[i]=someOtherMatrix[i];
one line shorter than
for(int r=0;i < rows;++r)
for(int c=0;i < cols;++s)
matrix[r][c]=someOtherMatrix[r][c];
though adding rows to such matrix is more painful
const int nRows = 20;
const int nCols = 10;
int (*name)[nCols] = new int[nRows][nCols];
std::memset(name, 0, sizeof(int) * nRows * nCols); //row major contiguous memory
name[0][0] = 1; //first element
name[nRows-1][nCols-1] = 1; //last element
delete[] name;
#include <iostream>
int main(){
int rows=4;
int cols=4;
int **arr;
arr = new int*[rows];
for(int i=0;i<rows;i++){
arr[i]=new int[cols];
}
// statements
for(int i=0;i<rows;i++){
delete []arr[i];
}
delete []arr;
return 0;
}
or you can just allocate a 1D array but reference elements in a 2D fashion:
to address row 2, column 3 (top left corner is row 0, column 0):
arr[2 * MATRIX_WIDTH + 3]
where MATRIX_WIDTH is the number of elements in a row.
Here is the most clear & intuitive way i know to allocate a dynamic 2d array in C++. Templated in this example covers all cases.
template<typename T> T** matrixAllocate(int rows, int cols, T **M)
{
M = new T*[rows];
for (int i = 0; i < rows; i++){
M[i] = new T[cols];
}
return M;
}
...
int main()
{
...
int** M1 = matrixAllocate<int>(rows, cols, M1);
double** M2 = matrixAllocate(rows, cols, M2);
...
}
The other answer describing arrays of arrays are correct.
BUT if you are planning of doing a anything mathematical with the arrays - or need something special like sparse matrices you should look at one of the many maths libs like TNT before re-inventing too many wheels
I have this grid class that can be used as a simple matrix if you don't need any mathematical operators.
/**
* Represents a grid of values.
* Indices are zero-based.
*/
template<class T>
class GenericGrid
{
public:
GenericGrid(size_t numRows, size_t numColumns);
GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue);
const T & get(size_t row, size_t col) const;
T & get(size_t row, size_t col);
void set(size_t row, size_t col, const T & inT);
size_t numRows() const;
size_t numColumns() const;
private:
size_t mNumRows;
size_t mNumColumns;
std::vector<T> mData;
};
template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns):
mNumRows(numRows),
mNumColumns(numColumns)
{
mData.resize(numRows*numColumns);
}
template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue):
mNumRows(numRows),
mNumColumns(numColumns)
{
mData.resize(numRows*numColumns, inInitialValue);
}
template<class T>
const T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx) const
{
return mData[rowIdx*mNumColumns + colIdx];
}
template<class T>
T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx)
{
return mData[rowIdx*mNumColumns + colIdx];
}
template<class T>
void GenericGrid<T>::set(size_t rowIdx, size_t colIdx, const T & inT)
{
mData[rowIdx*mNumColumns + colIdx] = inT;
}
template<class T>
size_t GenericGrid<T>::numRows() const
{
return mNumRows;
}
template<class T>
size_t GenericGrid<T>::numColumns() const
{
return mNumColumns;
}
Using the double-pointer is by far the best compromise between execution speed/optimisation and legibility. Using a single array to store matrix' contents is actually what a double-pointer does.
I have successfully used the following templated creator function (yes, I know I use old C-style pointer referencing, but it does make code more clear on the calling side with regards to changing parameters - something I like about pointers which is not possible with references. You will see what I mean):
///
/// Matrix Allocator Utility
/// #param pppArray Pointer to the double-pointer where the matrix should be allocated.
/// #param iRows Number of rows.
/// #param iColumns Number of columns.
/// #return Successful allocation returns true, else false.
template <typename T>
bool NewMatrix(T*** pppArray,
size_t iRows,
size_t iColumns)
{
bool l_bResult = false;
if (pppArray != 0) // Test if pointer holds a valid address.
{ // I prefer using the shorter 0 in stead of NULL.
if (!((*pppArray) != 0)) // Test if the first element is currently unassigned.
{ // The "double-not" evaluates a little quicker in general.
// Allocate and assign pointer array.
(*pppArray) = new T* [iRows];
if ((*pppArray) != 0) // Test if pointer-array allocation was successful.
{
// Allocate and assign common data storage array.
(*pppArray)[0] = new T [iRows * iColumns];
if ((*pppArray)[0] != 0) // Test if data array allocation was successful.
{
// Using pointer arithmetic requires the least overhead. There is no
// expensive repeated multiplication involved and very little additional
// memory is used for temporary variables.
T** l_ppRow = (*pppArray);
T* l_pRowFirstElement = l_ppRow[0];
for (size_t l_iRow = 1; l_iRow < iRows; l_iRow++)
{
l_ppRow++;
l_pRowFirstElement += iColumns;
l_ppRow[0] = l_pRowFirstElement;
}
l_bResult = true;
}
}
}
}
}
To de-allocate the memory created using the abovementioned utility, one simply has to de-allocate in reverse.
///
/// Matrix De-Allocator Utility
/// #param pppArray Pointer to the double-pointer where the matrix should be de-allocated.
/// #return Successful de-allocation returns true, else false.
template <typename T>
bool DeleteMatrix(T*** pppArray)
{
bool l_bResult = false;
if (pppArray != 0) // Test if pointer holds a valid address.
{
if ((*pppArray) != 0) // Test if pointer array was assigned.
{
if ((*pppArray)[0] != 0) // Test if data array was assigned.
{
// De-allocate common storage array.
delete [] (*pppArray)[0];
}
}
// De-allocate pointer array.
delete [] (*pppArray);
(*pppArray) = 0;
l_bResult = true;
}
}
}
To use these abovementioned template functions is then very easy (e.g.):
.
.
.
double l_ppMatrix = 0;
NewMatrix(&l_ppMatrix, 3, 3); // Create a 3 x 3 Matrix and store it in l_ppMatrix.
.
.
.
DeleteMatrix(&l_ppMatrix);