Need help with pointer and bidimensional arrays

Hi, im fairly new to c++ programming and programming in general. That being said, i recently got into pointers and arrays as arguments in functions and i ran into the following problem:

I wanted to code functions that replicate elemental algebraic operations on bidimiensional number arrays, but when coding the following function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 #include <iostream>
using namespace std;

void row_Scale(double *,int,int,double);//this function receives the array adress as a pointer,
								    	//an int equal to the number of columns, the row i want to multiply 
								    	//and the number i want to multiply by
int main(){
	double array[5][5];
	row_Scale(&array[0][0],5,3,5);//this call sends the array's adress, the number of columns, an arbitrary row and an arbitrary number to multiply by
	return 0;
}

void row_Scale(double *array,int columns,int row,double number){
	for(int x=0;x<columns;x++)     //this for loop multiplies every element    in the "row" row by the desired number
		*(array[row]+x) *= number; //HERE'S THE PROBLEM
	return;
}


So the problem is, even if i dont call the function from main(), i get an error message:
C:\Users\Manuel\Desktop\Manuel\DevC++\Matrices\Untitled2.cpp In function 'void row_Scale(double*, int, int, double)':
C:\Users\Manuel\Desktop\Manuel\DevC++\Matrices\Untitled2.cpp [Error] invalid type argument of unary '*' (have 'double')

I dont understand exactly why, because i've tried that same array syntax from main() in other codes and i never got that issue.

Again, im fairly new to c++ ;)
A double* is the same as a double[N], but never the same as a double[N][M].

It is worth your time to write a class to manage a 2D array:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template <typename T>
struct array2d
{
  private:
    unsigned _rows;
    unsigned _columns;
    T* _data;

  public:
    array2d( unsigned rows, unsigned columns ): 
      _rows(rows), _columns(columns), _data(new T[rows*columns])
      { }

    unsigned rows() const { return _rows; }
    unsigned columns() const { return _columns; }

    void resize( unsigned rows, unsigned columns ) { ... }

    T& operator () ( unsigned row, unsigned column ) { return _data[ row * _columns + column ]; }
    const T& operator () ( unsigned row, unsigned column ) const { return _data[ row * _columns + column ]; }

    ...
};

With that, your code becomes much simpler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void row_Scale( array2d& m, double k )
{
  for (unsigned row = 0; row < m.rows(); row++)
    for (unsigned col = 0; col < m.columns(); col++)
      m(row,col) *= k;
}

int main()
{
  array2d <double> m(5,5);
  
  /* initialize m here ... */

  row_Scale( m, -7.2 );

If you don't want to do that, though, you must still treat the array as a 1D array and index it properly. For that you need to know the size of the inner dimension as well as the address of the 2D array itself. A small function is useful to convert a 2D index into a 1D index:

1
2
3
4
unsigned index( unsigned columns, unsigned row, unsigned column )
{
  return row * columns + column;
}

And use:
1
2
3
4
5
6
void row_Scale(double *m,int columns,int rows,double k)
{
  for (int row = 0; row < rows; row++)
    for (int col = 0; col < columns; col++)
      m[ index(columns,row,col) ] *= k;
}

This second method has the peculiarity that you must beware of when you are using the actual array or a pointer to it.

Notice the lack of out-of-bounds checking in all this.
You could add it in if you wish.

I do not recommend the second method because it requires you to do all the stuff the compiler could do for you otherwise. Nevertheless, if you wish to continue with it, here is some further reading:
http://www.cplusplus.com/forum/beginner/118058/#msg643956
http://www.cplusplus.com/forum/general/49079/#msg266703

Hope this helps.

Thanks man! Really helps me learn about dynamic array sizes, which is something i still struggle with.
Thanks again!
The only real trick is that there are two ways to declare an array:

statically
1
2
3
4
int main()
{
  int a[12];  // here is an array that has 12 elements

dynamically
1
2
3
4
int main()
{
  int* a = new int[12];  // here is a dynamically-allocated array with 12 elements

The first significant difference is that the first has its size built in to the program. That array of twelve elements exists when main() starts, and remains that way so long as main() exists (and possibly longer).

Whereas the second is only created at the time that new is used, which can be any time:

1
2
3
4
5
6
7
int main()
{
  int* a = nullptr;

  // do other stuff

  a = new int[12];

What is also nice about the dynamic array is that it's size is not fixed by the compiler. You can, for example, get a size from the user:

1
2
3
4
5
6
7
8
9
10
11
int main()
{
  int* a = nullptr;
  int n;

  cout << "How many elements? ";
  cin >> n;
  /* in real code, please make sure that n has a valid value before continuing! */

  a = new int[n];  // create an array with some user-defined number of elements


Another significant difference is where the array is created. A static array appears in one of two places: in the global data segment (for global variables) or on the stack (for function-local variables). A "dynamic" array (one created "dynamically" with new) is located on the heap.

If you don't know what any of that means, don't worry about it. You'll get into those kinds of details later.


The final significant difference is scope. A static array is bound to the enclosing scope. So a global array exists during the entire program. An array declared in a function exists only so long as that function has not returned.

A dynamic array is not bound to the lifetime of any function. It exists from the time you create it with new[] to the time you destroy it with delete[], which can be any time you like.


With all that, the compiler only knows extra stuff about your array when it is a static array declared in a using scope -- which means that the compiler can only tell you how many elements your array has:
- (1) anywhere, if it is a static global array, or
- (2) in the function it is declared, if it is a static local array

Anywhere else, you are dealing with no more information than if you had a pointer -- the same as if you created an array dynamically.

What this boils down to is that you must keep track of the size of your array yourself. But wait, there's more! Not only does your array have a size, but often, you also want to keep track of how many elements are actually used in your array!

So at this point we want the following pieces of information:
1
2
3
int* address_of_the_array;
int  size_of_the_array;  // also called the 'capacity'
int  elements_used_in_the_array;

One might think it useful just to have a struct (or class) to keep all this information together. And so it was with the STL: the std::vector, which does this for us.


Hope this helps. :O)
Wow, your help is really appreciated.

But now i came across another problem :S

Im just getting the hang on dynamic memory allocation for arrays and i just wrote the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <iomanip>
using namespace std;


void createArray(int **,int,int);//allocates memory to the array based on the second and third parameter
void loadArray(int **,int,int);  //manual input of every element

int main(){
	int **array,rows,columns;
	
	cout<<"What size do you want? ";
	cin>>rows>>columns;

	createArray(array,rows,columns);
	loadArray(array,rows,columns);

	return 0;
}

void createArray(int **array,int rows,int columns){
	int x,y;
	array=new int*[rows];
	
	for(x=0;x<rows;x++)
		array[x]=new int[columns]();
	return;
}

void loadArray(int **array,int rows,int columns){
	cout<<"Please write each element in your array"<<endl;
	for(int x=0;x<rows;x++)
		for(int y=0;y<columns;y++)
		{
			cout<<"Write element NÂș "<<x<<","<<y<<": ";
			cin>>array[x][y];
		}
	return;
}


Now, the program runs fine until it hits the loadArray() function, where it crashes.

At first i thought it may had something to do with the scope that you were referring to, but if the array is not bound to any function, and i declared it on main(), then i suppose this specific problem has nothing to do with scope, or does it?

Again, thanks for the swift and thourough response

Edit: I ditched functions and put everything in main() and it worked but i don't think that's a proper solution xD
Last edited on
Topic archived. No new replies allowed.