¿Cómo crear una matriz cuando el tamaño es una variable, no una constante?

Tengo un método que recibe una variable int. Esa variable constituye un tamaño de matriz (por favor, no me ofrezcas un vector). Por lo tanto, necesito iniciar un const int dentro de mi método para inicializar una matriz de tamaño específico. Pregunta: ¿cómo hago eso?

void foo(int variable_int){ int a[variable_int] = {0}; //error } 

 int *a = new int[variable_int]; 

¡Recuerde eliminar [] el espacio asignado cuando haya terminado con él!

C ++ no admite matrices de longitud variable. En su lugar, deberá asignar la matriz dinámicamente:

 std::vector a(variable_int); 

o como dices que no quieres usar un vector por alguna razón:

 class not_a_vector { public: explicit not_a_vector(size_t size) : a(new int[size]()) {} ~not_a_vector() {delete [] a;} int & operator[](size_t i) {return a[i];} int operator[](size_t i) const {return a[i];} not_a_vector(not_a_vector const &) = delete; void operator=(not_a_vector const &) = delete; private: int * a; }; not_a_vector a(variable_int); 

ACTUALIZACIÓN: la pregunta acaba de actualizarse con la etiqueta “C” y con “C ++”. C (desde 1999) admite matrices de longitud variable, por lo que su código debería estar bien en ese idioma.

Puede crear fácilmente una variable const a partir de una variable no const escribiendo const int bar = variable_int; – sin embargo eso no te ayudará. En C ++, el tamaño de una matriz con almacenamiento automático debe ser una constante en tiempo de comstackción . No puede convertir una variable en una constante en tiempo de comstackción, por lo que lo que quiere simplemente no es posible.

Dependiendo de sus necesidades, podría hacer a puntero y asignar memoria usando new (y luego delete ) o, si el parámetro foo siempre se conocerá en tiempo de comstackción, podría convertir foo en una función de plantilla como esta:

 template void foo() { int a[n] = {0}; } 

Usted solicitó una solución que no sea del vector, pero repasemos la información porque es posible que la haya rechazado por los motivos equivocados. No debe preocuparse por el rendimiento porque, de manos de cualquier comstackdor competente, tendrá la misma sobrecarga que cualquier otra solución estándar. Por otro lado, hay algunas cuestiones de legibilidad y seguridad que analizaré a continuación. Veamos las formas en que puede hacerlo desde la más recomendada hasta la menos.

std :: vector

Contenedor favorito de la comunidad y por buenas razones. No solo se puede declarar con un tamaño de tiempo de ejecución, sino que el tamaño se puede cambiar en cualquier momento. Esto facilita el uso cuando el tamaño no puede ser predeterminado, por ejemplo, al sondear repetidamente para la entrada del usuario. Ejemplos:

 // Known size size_t n; std::cin >> n; std::vector vec(n); // Unknown size std::vector vec; int input; while (std::cin >> input) { // Note: not always the best way to read input vec.push_back(in); } 

No hay muchas desventajas de usar std::vector . El caso de tamaño conocido requiere exactamente una asignación dinámica. El tamaño desconocido requiere más en el caso general, pero de todos modos no podrías hacerlo mejor. Entonces el rendimiento es más o menos óptimo.

Semánticamente, puede no ser ideal para tamaños que son constantes durante la ejecución. Puede no ser evidente para el lector que este contenedor no está destinado a cambiar. Tampoco es conocido por el comstackdor, por lo que le permitirá hacer algo incorrecto, como push_back en un vector que es lógicamente de tamaño constante.

std :: unique_ptr (o std :: shared_ptr)

La solución más segura para imponer el tamaño estático es importante para usted.

 size_t n; std::cin >> n; auto arr = std::make_unique(n); 

El tamaño de arr no puede cambiar, aunque puede hacerse para liberar la matriz actual y apuntar a otra de diferente tamaño. Por lo tanto, si lógicamente el tamaño de su contenedor es constante, esto transmite la intención de una manera más clara. Desafortunadamente, también es mucho más débil que std::vector incluso en el caso de tamaño constante. No es consciente del tamaño, por lo que debe almacenar explícitamente el tamaño. Por la misma razón, no ofrece iteradores y no se puede usar en el rango para bucles. Depende de usted (y del proyecto en cuestión) si desea sacrificar estas características para imponer el tamaño estático.

Inicialmente, había recomendado boost::scoped_array pero después de pensarlo mejor, no creo que tenga mucho que ofrecer sobre esta solución, así que me limitaré a la biblioteca estándar.

nuevo [] – eliminar []

Técnicamente es una solución, pero a menos que te obliguen a usar un viejo estándar de C ++ o que estés escribiendo una biblioteca de bajo nivel que administre la memoria internamente, es estrictamente peor que la std::unique_ptr o std::shared_ptr . No ofrecen más funciones, pero son significativamente menos seguras porque tienes que liberar explícitamente la memoria cuando hayas terminado con ella. De lo contrario, tendrá fugas y esto podría causar problemas importantes. Para empeorar las cosas, usar delete[] correctamente puede no ser trivial para progtwigs con flujos de ejecución complicados y manejo de excepciones. ¡No use esto cuando las soluciones anteriores estén disponibles para usted!

 size_t n; std::cin >> n; int* arr = new int[n]; ... // Control flow must reach exactly one corresponding delete[] !!! delete[] arr; 

Bonificación: extensión del comstackdor

Algunos comstackdores podrían estar bien con el siguiente código

 size_t n; std::cin >> n; int arr[n]; 

Confiar en esto tiene graves inconvenientes. Su código no puede ser comstackdo en todos los comstackdores conformes a C ++. Probablemente ni siquiera se comstack en todas las versiones del comstackdor dado. Además, dudo que el ejecutable producido compruebe el valor de n y lo asigne en el montón cuando sea necesario, lo que significa que puede explotar su stack. Esta solución solo tiene sentido cuando sabes que el límite superior de n es pequeño y cuando el rendimiento es tan importante para ti que estás dispuesto a confiar en el comportamiento específico del comstackdor para obtenerlo. Estos son casos realmente excepcionales.

Para hacer lo que quiera, necesitará usar la asignación dinámica. En ese caso, sugeriría seriamente usar el vector en su lugar; es lo “correcto” que se debe hacer en C ++.

Pero si todavía no quieres usar el vector [por qué no lo harías después de mí], el código correcto es:

  void foo(int variable_int){ int *a = new int[variable_int](); // Parenthesis to initialize to zero. ... do stuff with a ... delete [] a; } 

Como otros han sugerido, también puede usar calloc, que tiene el mismo efecto de inicializar a cero, pero en realidad no es la solución “c ++”.

Si está utilizando matrices, es una buena idea encapsularlas:

 template class Vector { //... }; 

La biblioteca estándar viene con una implementación: std :: vector