El tamaño de la matriz de C ++ que depende del parámetro de la función provoca errores de compilación

StackOverflow https://stackoverflow.com/questions/312116

Pregunta

Tengo una función simple en la que una matriz se declara con tamaño dependiendo del parámetro que es int.

    void f(int n){
        char a[n];
    };

    int main() {
        return 0;
    }

Este código se compila bien en GNU C ++ , pero no en MSVC 2005.

Recibo los siguientes errores de compilación:

    .\main.cpp(4) : error C2057: expected constant expression
    .\main.cpp(4) : error C2466: cannot allocate an array of constant size 0
    .\main.cpp(4) : error C2133: 'a' : unknown size

¿Qué puedo hacer para corregir esto?

(Estoy interesado en hacer que esto funcione con MSVC, sin usar new / delete)

¿Fue útil?

Solución

Lo que has encontrado es una de las extensiones del compilador Gnu al lenguaje C ++. En este caso, Visual C ++ es completamente correcto. Las matrices en C ++ deben definirse con un tamaño que sea una expresión constante en tiempo de compilación.

Se agregó una característica a C en la actualización de 1999 de ese lenguaje llamada matrices de longitud variable, donde esto es legal. Si puede encontrar un compilador de C que admita C99, que no es fácil. Pero esta característica no es parte del estándar C ++, no se agregará en la próxima actualización del estándar C ++.

Hay dos soluciones en C ++. El primero es usar un std :: vector, el segundo es usar el operador new []:

char *a = new char [n];

Mientras escribía mi respuesta, otra publicó una sugerencia para usar _alloca. Lo recomendaría encarecidamente contra eso. Simplemente estaría intercambiando un método no estándar y no portátil por otro igual como específico del compilador.

Otros consejos

Su método de asignación desde la pila es una extensión g ++. Para hacer el equivalente en MSVC, debe usar _alloca:

char *a = (char *)_alloca(n);

Estás utilizando algo que no es un estándar. En realidad, es C estándar pero no C ++. ¡Qué peculiar es eso!

Explicando un poco más, los arreglos de pila de tamaño de tiempo de ejecución no son parte de C ++, pero son parte de C99, el último estándar para C. Por eso & # 180; es por eso que algunos compiladores lo obtendrán, mientras que otros no lo harán. . Recomendaría abstenerse de usarlo, para evitar problemas de compatibilidad del compilador.

La implementación alternativa de la funcionalidad sería usar new y delete, según lo publicado por strager.

Puede usar new / delete para asignar / liberar memoria en el montón. Esto es más lento y posiblemente más propenso a errores que usar char [n], pero lamentablemente aún no forma parte del estándar C ++.

Puede usar la clase de matriz con alcance de boost para un método seguro de excepción para usar new []. eliminar [] se llama automáticamente en a cuando sale del alcance.

void f(int n) {
    boost::scoped_array<char> a(new char[n]);

    /* Code here. */
}

También puede usar std :: vector, y reserve () algunos bytes:

void f(int n) {
    std::vector<char> a;
    a.resize(n);

    /* Code here. */
}

Si lo hace quiere usar char [n], compile como código C99 en lugar de código C ++.

Si por alguna razón debe asignar datos en la pila, use _alloca o _malloca / _freea, que son extensiones proporcionadas por las bibliotecas MSVC y demás.

La matriz de longitud variable

se introdujo en C99. Es compatible con gcc pero no con msvc. Según una persona del equipo de MSVC, Microsoft no tiene planes de admitir esta característica en su compilador c / C ++. Sugirió usar std :: vector en esos casos.

Tenga en cuenta que C99 no requiere que la matriz asignada en la pila. El compilador puede asignarlo en el montón. Sin embargo, gcc asigna la matriz en la pila.

Típicamente en C (excepto en los compiladores C99 como otros han señalado) y C ++, si desea asignar memoria en la pila, el tamaño de lo que desea asignar debe conocerse en el momento de la compilación. Las variables locales se asignan en la pila, por lo que una matriz cuya longitud depende de un parámetro de función en tiempo de ejecución infringe esta regla. Klein tiene razón al señalar que usar el operador 'nuevo' es una forma de resolver este problema:


char *a = new char [n];

'a' sigue siendo una variable local asignada en la pila, pero en lugar de ser la matriz completa (que tiene una longitud variable), es solo un puntero a una matriz (que siempre tiene el mismo tamaño y, por lo tanto, se conoce en la compilación hora). La matriz se asigna en el montón, que generalmente juega la contraparte de la pila: la pila es para cosas con un tamaño conocido en tiempo de compilación, y el montón es para cosas con un tamaño no conocido en un momento de compilación.

¿Sería razonable usar un vector<> en lugar de una matriz? O, ya que está reemplazando un char *, un std::string? Esos funcionan bien con el tamaño del tiempo de ejecución, aunque puede haber otras razones para no usarlos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top