This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 4 years ago.
I am trying to write a small C++ library to do simple matrix calculations. It consists of a Matrix class with static member functions altering given matrices.
I have one function which adds a scalar to each element, however the loop isn't working:
// Member function to add a scalar to the matrix
void Matrix::add_scal(double** arr, double s) {
for (size_t x = 0; x < sizeof(arr) / sizeof(*arr); ++x) {
Serial.println("test");
for (size_t y = 0; y < sizeof(*arr) / sizeof(**arr); ++y) {
arr[x][y] += s;
}
}
}
"Test" is only printed once and the inner loop isn't run at all. Here is the function I use to create a matrix:
double** Matrix::init(int rows, int cols) {
double** temp = new double*[rows];
for (int i = 0; i < rows; i++) {
temp[i] = new double[cols];
for (int j = 0; j < cols; j++) {
temp[i][j] = 0.0;
}
}
return temp;
}
The following two lines create a matrix and are supposed to add a scalar to it:
double** test = Matrix::init(3, 3);
Matrix::add_scal(test, 2.5);
The loop is not working, because sizeof() is not working as you think it does.
You are asking for the size of pointer, which is always a constant on a given machine (e.g. it is 4 in a 32bit). So, when you ask for the size of *arr, or **arr, that would be a number, irrelevant from the dimensions of the matrix!
In order to verify this yourself, print them, like this:
std::cout <<sizeof(*arr) << " " << sizeof(**arr) << std::endl;
Read more in Is the sizeof(some pointer) always equal to four?
In order to loop over a matrix, you need to use its dimensions, rows and cols in your case, like this:
void Matrix::add_scal(double** arr, double s) {
for (size_t x = 0; x < rows; ++x) {
Serial.println("test");
for (size_t y = 0; y < cols; ++y) {
arr[x][y] += s;
}
}
}
PS: You dynamically allocate the matrix correctly, but do not forget to free the memory when you don't need it any more-it's a must! If you don't know how, check my dynamic 2D array in C++
.
Tip: In C++, I strongly suggest you to use std::vector, which grows and shrinks in size automatically. Moreover, it has a method called size(), which returns the size of it, so you don't need to track its size manually!
In order to create a matrix using vectors, read Vector of Vectors to create matrix.
Related
I'm taking a c++ programming course (we are still mostly using C) and we just got to dynamic allocation of memory. For one of my homeworks, I'm asked to create a function that transposes any given matrix. This function is given the following arguments as inputs: a pointer, in which are saved the matrix elements, the number of rows and of colunms. I would like this to be a void type function that changes the order of the stored elements without returning any new pointer.
I tried creating a new pointer, in which I save the elemtens in the correct order (using 2 for loops). Then what I would like to do is deallocating the original pointer (using the delete command), assinging it to the new pointer and finally deleting the new pointer.
This unfortunately does not work (some elements turn out to be random numbers), but I don't understand why.
I hope my code is more precise and clear than my explanation:
void Traspose(float *matrix, const int rows, const int cols ){
auto *tras = new float [rows * cols];
int k = 0;
for(int i = 0; i < cols; i++){
for(int j = 0; j < rows * cols; j += cols){
tras[k] = matrix[j + i];
k++;
}
}
delete[] matrix;
matrix = tras;
delete[] tras;
}
All those lines are wrong:
delete[] matrix;
matrix = tras;
delete[] tras;
You didn't allocate matrix so you don't want do delete it.
You assign tras to matrix and then you delete tras, after that, tras points nowhere, nor does matrix.
matrix = tras is pointless anyway, because matrix is a local variable, and any changes to local variables are lost after the function ends.
You're inventing a problem where none should exist.
A matrix AxB in dimension will transpose to a matrix BxA in size. While the dimensional difference is obvious the storage requirements might not be so. Your storage is identical.
Per the function signature, the change must be done in the same memory allocated to matrix. E.g., the results should be stored back into matrix memory. So, don't delete that memory; leave it alone. It is both large enough to hold the transposition, and owned by the caller regardless.
Rather, do this:
void Traspose(float *matrix, const int rows, const int cols)
{
float *tras = new float[ rows * cols ];
int k = 0;
for (int i = 0; i < cols; i++)
{
for (int j = 0; j < rows * cols; j += cols)
tras[k++] = matrix[j + i];
}
for (int i=0; i<k; ++i)
matrix[i] = tras[i];
delete [] tras;
}
Note this gets quite a bit simpler (and safer) if the option to use the standard library algorithms and containers is on the table:
void Traspose(float *matrix, const int rows, const int cols)
{
std::vector<float> tras;
tras.reserve(rows*cols);
for (int i = 0; i < cols; i++)
{
for (int j = 0; j < rows * cols; j += cols)
tras.emplace_back(matrix[j + i]);
}
std::copy(tras.begin(), tras.end(), matrix);
}
Finally, probably worth investigating in your spare time, there are algorithms to do this, even for non-square matrices, in place without temporary storage using permutation chains. I'll leave researching those as an exercise to the OP.
I would like to determine if there is a way to determine whether a dynamically allocated matrix is square (nxn).
The first thing that came to mind was to see if there is a way to find out whether a pointer is about to point to an invalid memory location. But according to these posts:
C++ Is it possible to determine whether a pointer points to a valid object?
Testing pointers for validity (C/C++)
This cannot be done.
The next idea I came up with was to somehow use the sizeof() function to find a pattern with square matrices, but using sizeof() on a pointer will always yield the same value.
I start off by creating a dynamically allocated array to be of size nxn:
int **array = new int*[n]
for(int i = 0; i < n; i++)
array[i] = new int[n];
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
array[i][j] = 0;
}
}
Now I have a populated square matrix of size nxn. Let's say I'm implementing a function to print a square 2D array, but a user has inadvertently created and passed a 2D array of size mxn into my function (accomplished by the code above, except there are more row pointers than elements that comprise the columns, or vice versa), and we're also not sure whether the user has passed a value of n corresponding to n rows or n columns:
bool(int **arr, int n){
for(int rows = 0; rows < n; rows++)
for(int cols = 0; cols < n; cols++)
cout << *(*(arr + rows) + cols) << " ";
// Is our next column value encroaching on unallocated memory?
}
cout << endl;
// Is our next row value out of bounds?
}
}
Is there any way to inform this user (before exiting with a segmentation fault), that this function is for printing square 2D arrays only?
Edit: corrected 3rd line from
array[i] = new int[i]
to
array[i] = new int[n]
There is NO way to find out information about an allocation. The ONLY way you can do that, is to store the information about the matrix dimensions somewhere. Pointers are just pointers. Nothing more, nothing less. If you need something more than a pointer, you'll need to define a type that encapsulates all of that information.
class Matrix2D
{
public:
Matrix2D(int N, int M)
: m_N(N), m_M(M), m_data(new int[N*M]) {}
int N() const { return this->m_N; }
int M() const { return this->m_M; }
int* operator[] (int index) const
{ return m_data + m_M * index; }
private:
int m_N;
int m_M;
int* m_data;
};
I am new to C++ and programming in general so i apologize if this is a trivial question.I am trying to initialize 2 arrays of size [600][600] and type str but my program keeps crashing.I think this is because these 2 arrays exceed the memory limits of the stack.Also,N is given by user so i am not quite sure if i can use new here because it is not a constant expression.
My code:
#include<iostream>
using namespace std;
struct str {
int x;
int y;
int z;
};
int main(){
cin>>N;
str Array1[N][N]; //N can be up to 200
str Array2[N][N];
};
How could i initialize them in heap?I know that for a 1-D array i can use a vector but i don't know if this can somehow be applied to a 2-D array.
How 2-or-more-dimensional arrays work in C++
A 1D array is simple to implement and dereference. Assuming the array name is arr, it only requires one dereference to get access to an element.
Arrays with 2 or more dimensions, whether dynamic or stack-based, require more steps to create and access. To draw an analogy between a matrix and this, if arr is a 2D array and you want access to a specific element, let's say arr[row][col], there are actually 2 dereferences in this step. The first one, arr[row], gives you access to the row-th row of col elements. The second and final one, arr[row][col] reaches the exact element that you need.
Because arr[row][col] requires 2 dereferences for one to gain access, arr is no longer a pointer, but a pointer to pointer. With regards to the above, the first dereference gives you a pointer to a specific row (a 1D array), while the second dereference gives the actual element.
Thus, dynamic 2D arrays require you to have a pointer to pointer.
To allocate a dynamic 2D array with size given at runtime
First, you need to create an array of pointers to pointers to your data type of choice. Since yours is string, one way of doing it is:
std::cin >> N;
std::string **matrix = new string*[N];
You have allocated an array of row pointers. The final step is to loop through all the elements and allocate the columns themselves:
for (int index = 0; index < N; ++index) {
matrix[index] = new string[N];
}
Now you can dereference it just like you would a normal 2D grid:
// assuming you have stored data in the grid
for (int row = 0; row < N; ++row) {
for (int col = 0; col < N; ++col) {
std::cout << matrix[row][col] << std::endl;
}
}
One thing to note: dynamic arrays are more computationally-expensive than their regular, stack-based counterparts. If possible, opt to use STL containers instead, like std::vector.
Edit: To free the matrix, you go "backwards":
// free all the columns
for (int col = 0; col < N; ++col) {
delete [] matrix[col];
}
// free the list of rows
delete [] matrix;
When wanting to allocate a 2D array in C++ using the new operator, you must declare a (*pointer-to-array)[N] and then allocate with new type [N][N];
For example, you can declare and allocate for your Array1 as follows:
#define N 200
struct str {
int x, y, z;
};
int main (void) {
str (*Array1)[N] = new str[N][N]; /* allocate */
/* use Array1 as 2D array */
delete [] Array1; /* free memory */
}
However, ideally, you would want to let the C++ containers library type vector handle the memory management for your. For instance you can:
#include<vector>
..
std::vector <std::vector <str>> Array1;
Then to fill Array1, fill a temporary std::vector<str> tmp; for each row (1D array) of str and then Array1.push_back(tmp); to add the filled tmp vector to your Array1. Your access can still be 2D indexing (e.g. Array1[a][b].x, Array1[a][b].y, ..., but you benefit from auto-memory management provided by the container. Much more robust and less error prone than handling the memory yourself.
Normally, you can initialize memory in heap by using 'new' operator.
Hope this can help you:
// Example program
#include <iostream>
struct str {
int x;
int y;
int z;
};
int main()
{
int N;
std::cin>>N;
str **Array1 = new str*[N]; //N can be up to 200
for (int i = 0; i < N; ++i) {
Array1[i] = new str[N];
}
// set value
for (int row = 0; row < N; ++row) {
for (int col = 0; col < N; ++col) {
Array1[row][col].x=10;
Array1[row][col].y=10;
Array1[row][col].z=10;
}
}
// get value
for (int row = 0; row < N; ++row) {
for (int col = 0; col < N; ++col) {
std::cout << Array1[row][col].x << std::endl;
std::cout << Array1[row][col].y << std::endl;
std::cout << Array1[row][col].z << std::endl;
}
}
}
I want to use a pointer to a 2D vector (matrix) in some function that traverses all the rows and columns like this:
int do_stuff_to_matrix(vector< vector<int> > *matrix) {
for (int i = 0; i < matrix->size(); i++) {
for (int j = 0; j < (*matrix)[0].size(); j++) {
// do something for each element of matrix
}
}
return 0;
}
Using -> notation, I can get the size of one dimension of the matrix that my pointer points to. But I wasn't sure if I could use the same notation for the 2nd dimension, which is why I wrote it out using the normal * operator.
Is a way I can rewrite "(*matrix)[0].size()" using -> notation?
matrix->operator[](0).size()
I wouldn't advise it.
This question already has answers here:
how to use memset for double dimentional array?
(2 answers)
Closed 9 years ago.
What is the fastest way to set a 2-dim array of double,such as double x[N][N] all to -1?
I tried to use memset, but failed. Any good idea?
Use: std::fill_n from algorithm
std::fill_n(*array, sizeof(array) / sizeof (**array), -1 );
Example:
double array[10][10];
std::fill_n( *array, sizeof(array) / sizeof (**array), -1.0 );
//Display Matrix
for(auto i=0;i<10;i++)
{
for(auto j=0;j<10;j++)
cout<<array[i][j]<< " ";
cout<<endl;
}
A simple loop:
#include <stdio.h>
int main(void)
{
#define N 5
double x[N][N];
size_t i, n = sizeof(x) / sizeof(double);
for (i = 0; i < n; i++)
x[0][i] = -1.0;
for (i = 0; i < n; i++)
printf("%zu) %f\n", i, x[0][i]);
}
// create constants
const int rows = 10;
const int columns = 10;
// declare a 2D array
double myArray [rows][columns];
// run a double loop to fill up the array
for (int i = 0; i < rows; i++)
for (int k = 0; k < columns; k++)
myArray[rows][columns] = -1.0;
// print out the results
for (int i = 0; i < rows; i++) {
for (int k = 0; k < columns; k++)
cout << myArray[rows][columns];
cout << endl;
}
Also you can set directly
double x[4][4] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}
if the array index is small.
Using std::array and its fill method:
#include <array>
#include <iostream>
int main()
{
const std::size_t N=4
std::array<double, N*N> arr; // better to keep the memory 1D and access 2D!
arr.fill(-1.);
for(auto element : arr)
std::cout << element << '\n';
}
Using C++ containers you can use the fill method
array<array<double, 1024>, 1024> matrix;
matrix.fill(-1.0);
if, for some reason, you have to stick with C-style arrays you can initialize the first row manually and then memcpy to the other rows. This works regardless if you have defined it as static array or allocated row by row.
const int rows = 1024;
const int cols = 1024;
double matrix[rows][cols]
for ( int i=0; i<cols; ++i)
{
matrix[0][cols] = -1.0;
}
for ( int r=1; r<rows; ++r)
{
// use the previous row as source to have it cache friendly for large matrices
memcpy(&(void*)(matrix[row][0]), &(void*)(matrix[row-1][0]), cols*sizeof(double));
}
But I rather would try to move from C style arrays to the C++ containers than doing that kind of stunt.
memset shouldn't be used here because it is based on void *. So all bytes in are the same. (float) -1 is 0xbf800000 (double 0xbff0000000000000) so not all bytes are the same...
I would use manual filling:
const int m = 1024;
const int n = 1024;
double arr[m][n];
for (size_t i = 0; i < m*n; i++)
arr[i] = -1;
Matrix is like array in memory, so better to have 1 loop, it slightly faster.
Or you can use this:
std::fill_n(arr, m*n, -1);
Not sure which one is faster, but both looks similar. So probably you'll need to make small test to find it out, but as far as I know people usually use one or another. And another thing first one is more C on some compiler it won't work and second is real C++ it and never works on C. So you should choose by the programming language I think :)