Suppose a matrix such that:
int matriz[3][3];
and you fill in your positions with numbers from 1 to 9. In memory it would look like this:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
--------- --------- ---------
FILA 0 FILA 1 FILA 2
That is, the values of the matrix will occupy consecutive positions in the memory.
If now, instead, we have this:
int ** matriz = new int*[3];
for( int i=0; i<3; i++ )
matriz[i] = new int[3];
And fill in the matrix, the result in memory will be rather:
MEMORIA 0x0000 0x0001 0x0002 ... 0x1000 0x1001 0x1002 ... 0x1020 0x1021 0x1022 ...
VALOR 0x1000 0x1020 0x1250 ... 1 2 3 ... 4 5 6 ...
^^^^^^ ^^^^^^ ^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
Punteros Valores fila 0 Valores fila 1
That is, although some features can be used equally in the language:
std::cout << matriz[1][2];
At the level of memory and machine instructions, they do not resemble each other at all.
If you do not need to pull dynamic memory better still use the matrices of the first example ... otherwise the most advisable would almost create a class Matriz
that encapsulates the complexity associated with the management of dynamic memory. A possible silly example:
class Matriz
{
double* m_datos;
const int m_filas;
const int m_columnas;
public:
class MatrizRef
{
friend class Matriz;
double* m_ptr;
MatrizRef(double* ptr)
: m_ptr(ptr)
{ }
public:
double& operator[](int index)
{ return m_ptr[index]; }
};
Matriz(int filas, int columnas)
: m_filas(filas), m_columnas(columnas), m_datos(new double[filas*columnas])
{ }
~Matriz()
{ delete[] m_datos; }
MatrizRef operator[](int index)
{ return MatrizRef(m_datos+(index*m_columnas)); }
int Filas() const
{ return m_filas; }
int Columnas() const
{ return m_columnas; }
};
And an example of use:
int main()
{
Matriz m(3,3);
for( int i=0; i<m.Filas(); i++ )
for( int j=0; j<m.Columnas(); j++ )
m[i][j] = i*3+j+1;
for( int i=0; i<m.Filas(); i++ )
{
for( int j=0; j<m.Columnas(); j++ )
std::cout << m[i][j] << ' ';
std::cout << '\n';
}
}
That applied to your code would result in a function with the following signature:
void kapeso(Matriz& k, double *pesos63, Matriz& Q60, Matriz& Q120, Matriz& Q180, Matriz& Q240, Matriz& Q300)
Just in case someone thinks that the use of the nested class is totally inefficient, I invite you to verify that this is not the case. The following example:
// Función externa (para evitar optimizaciones en este punto)
extern void Func(int&);
int main()
{
Matriz m(3,3);
for( int i=0; i<m.Filas(); i++ )
for( int j=0; j<m.Columnas(); j++ )
m[i][j] = i*3+j+1;
int total = 0;
for( int i=0; i<m.Filas(); i++ )
{
for( int j=0; j<m.Columnas(); j++ )
Func(m[i][j]);
}
}
Generates the following assembly:
main: # @main
push r14
push rbx
push rax
mov edi, 36
call operator new[](unsigned long)
mov rbx, rax
movaps xmm0, xmmword ptr [rip + .LCPI0_0] # xmm0 = [1,2,3,4]
movups xmmword ptr [rbx], xmm0
movaps xmm0, xmmword ptr [rip + .LCPI0_1] # xmm0 = [5,6,7,8]
movups xmmword ptr [rbx + 16], xmm0
mov dword ptr [rbx + 32], 9
mov rdi, rbx
call Func(int&)
lea rdi, [rbx + 4]
call Func(int&)
lea rdi, [rbx + 8]
call Func(int&)
lea rdi, [rbx + 12]
call Func(int&)
lea rdi, [rbx + 16]
call Func(int&)
lea rdi, [rbx + 20]
call Func(int&)
lea rdi, [rbx + 24]
call Func(int&)
lea rdi, [rbx + 28]
call Func(int&)
mov rdi, rbx
add rdi, 32
call Func(int&)
mov rdi, rbx
call operator delete[](void*)
xor eax, eax
add rsp, 8
pop rbx
pop r14
ret
mov r14, rax
mov rdi, rbx
call operator delete[](void*)
mov rdi, r14
call _Unwind_Resume
As you can see, the compiler is able to eliminate the nested class and offer direct access to memory:
mov rdi, rbx # Se carga en rdi el valor m_datos[0]
call Func(int&) # Llamada a Func()
lea rdi, [rbx + 4] # Se carga en rdi m_datos[1] ( 4=sizeof(int) )
call Func(int&)
lea rdi, [rbx + 8] # Se carga en rdi m_datos[2]
call Func(int&)
lea rdi, [rbx + 12] # Se carga en rdi m_datos[3]
call Func(int&)
# ...
The example can be verified here