una - matriz dinamica c++
La matriz 2D grande da una falla de segmentación (7)
¡Me parece que tienes un desbordamiento de pila honesto-a-Spolsky!
Intenta compilar tu programa con la opción gcc -fstack-check. Si sus arreglos son demasiado grandes para asignar en la pila, obtendrá una excepción StorageError.
Sin embargo, creo que es una buena apuesta, ya que 5000 * 500 * 3 dobles (8 bytes cada uno) llegan a unos 60 megas, ninguna plataforma tiene suficiente pila para eso. Tendrás que asignar tus matrices grandes en el montón.
Estoy escribiendo un código C ++ en Linux, donde he declarado algunas matrices 2D como esta:
double x[5000][500], y[5000][500], z[5000][500];
Durante la compilación no hay error. Cuando lo ejecuto dice "falla de segmentación".
Cuando reduzco el tamaño de la matriz de 5000 a 50, el programa funciona bien. ¿Cómo puedo protegerme contra este problema?
Es posible que desee probar y utilizar Boost.Multi_array
typedef boost::multi_array<double, 2> Double2d;
Double2d x(boost::extents[5000][500]);
Double2d y(boost::extents[5000][500]);
Double2d z(boost::extents[5000][500]);
La porción de memoria grande real se asignará en el montón y se desasignará automáticamente cuando sea necesario.
Estas matrices están en la pila. Las pilas son bastante limitadas en tamaño. Probablemente te encuentras con un ... desbordamiento de pila :)
Si quieres evitar esto, debes ponerlos en la tienda gratuita:
double* x =new double[5000*5000];
Pero es mejor que empieces con el buen hábito de usar los contenedores estándar, que envuelven todo esto para ti:
std::vector< std::vector<int> > x( std::vector<int>(500), 5000 );
Además: incluso si la pila se ajusta a las matrices, aún necesita espacio para que las funciones coloquen sus marcos.
Otra solución a las anteriores sería ejecutar un
ulimit -s stack_area
para ampliar la pila máxima.
Si su programa se ve así ...
int main(int, char **) {
double x[5000][500],y[5000][500],z[5000][500];
// ...
return 0;
}
... entonces estás desbordando la pila. La forma más rápida de solucionar esto es agregar la palabra estática .
int main(int, char **) {
static double x[5000][500],y[5000][500],z[5000][500];
// ...
return 0;
}
La segunda forma más rápida de solucionar esto es mover la declaración fuera de la función:
double x[5000][500],y[5000][500],z[5000][500];
int main(int, char **) {
// ...
return 0;
}
La tercera forma más rápida de solucionar este problema es asignar la memoria en el montón:
int main(int, char **) {
double **x = new double*[5000];
double **y = new double*[5000];
double **z = new double*[5000];
for (size_t i = 0; i < 5000; i++) {
x[i] = new double[500];
y[i] = new double[500];
z[i] = new double[500];
}
// ...
for (size_t i = 5000; i > 0; ) {
delete[] z[--i];
delete[] y[i];
delete[] x[i];
}
delete[] z;
delete[] y;
delete[] x;
return 0;
}
La cuarta forma más rápida es asignarlos en el montón usando std :: vector. Hay menos líneas en su archivo pero más líneas en la unidad de compilación, y debe pensar en un nombre significativo para sus tipos de vectores derivados o meterlos en un espacio de nombres anónimo para que no contaminen el espacio de nombres global:
#include <vector>
using std::vector
namespace {
struct Y : public vector<double> { Y() : vector<double>(500) {} };
struct XY : public vector<Y> { XY() : vector<Y>(5000) {} } ;
}
int main(int, char **) {
XY x, y, z;
// ...
return 0;
}
La quinta forma más rápida es asignarlos en el montón, pero use plantillas para que las dimensiones no estén tan alejadas de los objetos:
include <vector>
using namespace std;
namespace {
template <size_t N>
struct Y : public vector<double> { Y() : vector<double>(N) {} };
template <size_t N1, size_t N2>
struct XY : public vector< Y<N2> > { XY() : vector< Y<N2> > (N1) {} } ;
}
int main(int, char **) {
XY<5000,500> x, y, z;
XY<500,50> mini_x, mini_y, mini_z;
// ...
return 0;
}
La forma más eficaz es asignar las matrices bidimensionales como matrices unidimensionales y luego utilizar la aritmética de índice.
Todo lo anterior supone que tiene alguna razón, buena o mala, por querer crear su propio mecanismo de matriz multidimensional. Si no tiene ninguna razón y espera volver a utilizar matrices multidimensionales, considere la posibilidad de instalar una biblioteca:
Una forma de jugar muy bien con STL es usar la matriz multidimensional Boost .
Una forma de velocidad es usar Blitz++ .
Su declaración debe aparecer en el nivel superior, fuera de cualquier procedimiento o método.
Con mucho, la forma más fácil de diagnosticar un error de seguridad en código C o C ++ es usar valgrind . Si uno de sus arreglos tiene la culpa, valgrind señalará exactamente dónde y cómo. Si la culpa está en otra parte, también te lo dirá.
valgrind se puede usar en cualquier binario x86, pero le dará más información si compila con gcc -g
.
Una reserva acerca de usar siempre vector: por lo que yo entiendo, si abandonas el final de la matriz, simplemente asigna una matriz más grande y copia todo lo que podría crear errores sutiles y difíciles de encontrar cuando realmente estás tratando de trabajar con ellos. una matriz de tamaño fijo. Al menos con una matriz real, segregarás si te alejas del final haciendo que el error sea más fácil de detectar.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
typedef double (*array5k_t)[5000];
array5k_t array5k = calloc(5000, sizeof(double)*5000);
// should generate segfault error
array5k[5000][5001] = 10;
return 0;
}