Don't know if it matter but for the problem I use rand() to fill a 2d array with elements and CodeBloks for IDE.
I've been learning C++ and have gotten to pointers and 2d arrays and I've encountered something I don't understand why it works like this.
I had a tasks to swap two rows of a 2d array using pointers and this is how I swap the rows:
int *temp=arr[0];
arr[0]=arr[1];
arr[1]=temp;
And when my array is defined like this the code can compile without problem:
int a=5;
int b=3;
int **arr=new int*[a];
for(int i=0;i<a;i++){
*(arr+i)=new int[b];
for(int j=0;j<b;j++){
*(*(arr+i)+j)=rand()%(125-15+1)+15;
cout<<*(*(arr+i)+j)<<" ";
}
cout<<endl;
}
But when its defined like this the code doesn't compile doesn't and I don't understand what is the difrence:
int a=5;
int b=3;
int arr[a][b];
And I get this as an error message:
invalid array assignment|
incompatible types in assignment of 'int*' to 'int [b]'|
Aren't the two definitions equvelent trought the compiler or does something else happen?
Arrays are not pointers, and pointers are not arrays.
With
int **arr=new int*[a];
arr is not a two-dimensional array but a pointer to the first element in an array of pointers, and your code is only swapping pointers.
But you can't assign between arrays;
int a[3] {1,2,3};
int b[3] {4,5,6};
a = b; // Error
or from a pointer to an array;
int x = 0;
int a[3] {1,2,3};
a = &x; // Error
However, an array can be implicitly converted into a pointer to its first element, and when you use arrays your "swapping code" is equivalent to
int *temp = &arr[0][0]; // Pointer to the first element of the array arr[0]
arr[0] = &arr[1][0]; // Try to assign a pointer to the first element of arr[1] to the array arr[0]
arr[1] = temp; // Try to assign a pointer to the array arr[1]
In summary, you can't swap arrays, you need to do the swapping element-wise.
Or use std::array instead of "native" arrays, or std::vector if you need to determine the dimensions at runtime.
Related
do_something(int array[][])
{
}
int main()
{
int array_length;
cin>> array_length;
int array[array_length][array_length];
for()
{
"putting elements of array"
}
}
I have seen people putting some const int so they can pass array to the function. Question is how do I pass a multidimensional array to the function if I don't know its size until it is entered.
int array[array_length][array_length];
This line will not compile. Unlike some other languages (Java, possibly), allocating an array of dynamic size is different than one of constant size. The [] notation will create a constant-size array, which will not work your attempt to pass it array_length. To allocate this array dynamically, use
int **array = new int*[array_length];
The you'll need to iterate through array and allocate each sub-array to the correct size with
array[i] = new int[array_length];
After this, you'll need to reference array_length when iterating through array, as it is your only indication as to the size of the array.
Consider the following case:
int **my_array = new int*[10];
What do we assign to my_array here?
my_array is a pointer that points to what?
Is there any way to iterate through my_array (the pointer) and set up a two-dimensional array of integers (and not int*)?
We assign to my_array the address of an array. The array contains pointers which can point to other arrays, but don't yet.
Yes, we can do this:
int **my_array = new int*[10];
for(int i=0; i<10; ++i)
my_array[i] = new int[13];
my_array[2][11] = 500;
What do we assign to my_array here?
You can assign an int* to the elements of my_array. E.g.
my_array[0] = new int[20];
or
int i;
my_array[0] = &i;
my_array is a pointer that points to what?
It points to an an array of 10 int* objects.
Is there any way to iterate through my_array (the pointer) and set up a two-dimensional array of integers (and not int*)?
Not sure what you are expecting to see here. An element of my_array can only be an int*.
If you want my_array to be a pointer to a 2D array, you may use:
int (*my_array)[20] = new int[10][20];
Now you can use my_array[0][0] through my_array[9][19].
PS If this is your attempt to understand pointers and arrays, it's all good. If you are trying to deploy this code in a working program, don't use raw arrays any more. Use std::vector or std::array.
For a 1D array, use:
// A 1D array with 10 elements.
std::vector<int> arr1(10);
For a 2D array, use:
// A 2D array with 10x20 elements.
std::vector<std::vector<int>> arr2(10, std::vector<int>(20));
I saw that an array of pointers can be created using vector, however, I don't want that. Is the example below a way to create a pointer to int array?
#include <iostream>
using namespace std;
int main() {
int* arr[4];
for (int i=0; i<4; ++i) {
cout<<endl<<arr[i];
}
}
This makes a pointer to int array and it displays the memory address of each index in the array. Now I have few questions. Is it a proper way to create a pointer to int array without a vector? Also, if I want to initialize a value inside each memory address in the given example, how is it done? And lastly why is &arr equal to arr?
While &arr and just plain arr may both give you the same address, they are both very different.
With &arr you get a pointer to the array, and the type of it is (in your case) int* (*)[4].
When you use arr it decays to a pointer to the first element and the type is (again, in your case) int**.
Same address, but different types.
As for the array itself, it's defined fine, you have an array of four pointers to int. However, you do not initialize the contents of the array, which means that the contents is indeterminate, and using those pointers in any way (even just printing them) leads to undefined behavior.
Your proposed way doesn't make pointer to int array. Instead of that it makes a pointer to pointer to an int array. Usually the name of any array represent a pointer to it self. Or &arr[0] also represent it.
So I hope that you got the answer for why &arr equal arr.
Creating a pointer to int array
int arr[4];
int* p = arr; //pointer to int array
Initializing each element in array
(1) Using pointer arithmetic
int size = 4;
int* p = arr;
for (int i = 0; i < size; i++)
{
*p = i; // assigning each element i
p++; //pointing to next element
}
(2) Using operator []
int size = 4;
for (int i = 0; i < size; i++)
{
arr[i] = i; // assigning each element i
}
&arr gives you the address of array which starts with base address ie address of first element.
arr gives the address of first element.
hence u get same result for both
I ve got a function that takes 3 parameteres, first one is **double.
normalizeDataZeroMeanUnitSD(double ** trainingActions, int numberOfTrainingActions, int descriptorDimension)
When I call it from main, I am trying to use normalizeDataZeroMeanUnitSD(data, 681, 24); however, I am receiving
cannot convert parameter 1 from 'double [681][24]' to 'double **'
This is how I construct the data array:
fstream infile;
infile.open("gabor\\Data.txt");
double data[681][24];
while (!infile.eof())
{
for(int j=0;j<681;j++)
{
for(int k=0; k<24;k++)
{
infile >> data[j][k];
}
}
}
infile.close();
Is there a way to do the same using **data?
The error is pretty clear: Datatype double [681][24] is not the same as double **. While it's true that double[681] can decay to a pointer to its first element (thus, double*), that does not imply that double[681][24] can decay to double**.
Think about it this way: double** implies a pointer to many pointers. But double[][] does not have ANY pointers in it. At best, an array of ANY dimensions still only has, at very most, one pointer: to the beginning of its contiguous storage.
You could use a template:
template<std::size_t M, std::size_t N>
void normalizeDataZeroMeanUnitSD(double (&trainingActions)[M][N], int descriptorDimension)
{
for( std::size_t m = 0; m < M; ++m )
{
for( std::size_t n = 0; n < N; ++n )
{
trainingActions[m][n] = ...;
}
}
}
But beware of code bloat if you call this with many differently sized arrays.
Use any of the following declarations. Both are equivalent.
NormalizeDataZeroMeanUnitSD(double trainingActions[][24], int numberOfTrainingActions, int descriptorDimension)
NormalizeDataZeroMeanUnitSD(double trainingActions[681][24], int numberOfTrainingActions, int descriptorDimension)
When you declare a 2D array it takes up contiguous memory locations. So you need to specify at least the number of columns (in case of row major architecture).
For row major and column major definitions, have a look at this.
For your edited question, yes you can declare using **data. Dynamically allocate the data array. But remember to free it when you're done with it.
double **data=new double*[681];
for (int i=0;i<681;i++)
{
data[i]=new double[24];
}
//do what you want to do
for (int i=0;i<681;i++)
{
delete [] data[i];
}
delete [] data;
Now your function prototype can be like void func(double **pp) because data is a pointer not a 2D array.
A 2d array is a continuous area of storage. The function expects a pointer to pointers. These are incompatible.
The function expects an array of pointers to arrays; you have an array of arrays. Some options are:
change the function to take a more friendly type, perhaps double* pointing to the first element of a contiguous 2-dimensional array; or
build a separate array of pointers pointing to each row of your 2-dimensional array; or
restructure your data into an array of pointers to arrays.
Here is a constructive answer for how to make it work.
Basically, you need to generate an array that has pointers to each 1D slice of your 2D array.
double data[N][M] = {...};
double *dataPtrs[N];
for(size_t n=0; n<N; ++n) {
dataPtrs[n] = data[n];
}
normalizeDataZeroMeanUnitSD(dataPtrs, N, M); // order of N and M might be wrong
Yay, I get to rant about this again.
In C++, despite having similar syntax, 2D arrays are NOT jagged arrays. 2D arrays (double foo[681][24]) are allocated contiguously in memory. When you deference a 2D array (foo[j][i]) it actually does *(foo+24*i+j). This is all done under the hood. The sizeof(foo)==sizeof(double)*681*24.
Jagged arrays are (double** bar;). This is a bunch of different arrays: first, you allocate an array of pointer, 268 members long. Each pointer will point to an array of doubles, 24 elements long. Bar is just a pointer, so sizeof(bar)==sizeof(void*).
More annoyingly, 2D arrays (or a static array of any dimension) behave the opposite of all other types in C++ in the following reguard: they are passed implicitly by reference, causing the weird phenomenon below.
void foo(double bar[24][24]) { std::cout << sizeof(bar) << std::endl;}
int main() {
double test[24][24];
std::cout << sizeof(test) << std::endl;//returns sizeof(double)*24*24
foo(test);//returns sizeof(void*), implicitly passed by reference, opossite of the rest of c++!
double[][] is not the same thing as double**.
double** is a pointer to pointers.
double[][] is a 2-dimensional array allocated as continuous storage.
In order to pass a "2-dimensional array" to the function, you need to create an array of pointers to arrays. For example:
double* array_2d[681];
for(unsigned int i=0; i<681; ++i) {
array_2d[i] = new double[24];
}
normalizeDataZeroMeanUnitSD(array_2d, 681, 24);
Remember to later delete[] each element of array_2d!
Better yet, change normalizeDataZeroMeanUnitSD to take a reference to std::vector<std::vector<double>>, and you no longer have to worry about memory management, nor passing the correct dimensions to the function.
I'm new to C++ and still really confused about how 2d arrays work with pointers. If I have this (in example format):
int* anarray = anarrayfiller();
for (int a=0;a<10;a++) {
for (int b=0;b<10;b++) {
cout<<(char)anarray[a][b]; //Here's the error mentioned below
}
cout<<"\n";
}
//Later, outside main
int* anarrayfiller() {
int anarray[10][10];
//Populated here
return &anarray;
}
This produces an error under b in the cout<< line:
"Expression must have pointer-to-object type"
I would just check how to search through 2d arrays, and I found this:
A pointer to 2d array
Which suggests that actually this pointer points to the array of ints inside anarray[0], and if that's the case, I must be missing something in terms of returning pointers - wouldn't I then have to return a pointer to a 2d array of pointers that each points to a specific int from anarray? I'm pretty confused here. How do pointers work with 2d arrays?
You have a few errors here:
You return a pointer to a local variable. After the function returns the stack area previously occupied by that variable no longer exist, or is used by the next function.
You return a pointer to an integer, while you have a two-dimensional array. The closest would be a pointer-to-pointer.
You access thing single-pointer as though it was a double-pointer (pointer-to-pointer or pointer-to-array or array-or-arrays), but it's not. That's the reason you get errors at the pointed to line.
But you can't use pointer to pointer, as the memory layout of an array-of-arrays (a two-dimensional array) is different from a pointer-to-pointer. See e.g. this old answer of mine for an explanation of why.
This can be solved most easily by creating the array dynamically on the heap, as a pointer-to-pointer:
int **anarrayfiller()
{
int **anarray = malloc(sizeof(int *) * 10);
for (int i = 0; i < 10; ++i)
{
anarray[i] = malloc(sizeof(int) * 10);
/* Populate here */
}
return anarray;
}
As you tagged your question as C++, you should actually avoid plain arrays or pointers in favor of either std::vector (if you need to add dynamically) or std::array (if you have a fixed compile-time size):
std::array<std::array<int, 10>, 10> anarrayfiller()
{
std::array<std::array<int, 10>, 10> anarray;
// Populate arrays
return anarray;
}