Можно ли использовать переменную для определения размера массива в стеке в c? - PullRequest
4 голосов
/ 02 ноября 2009

У меня есть ситуация, когда я хочу, чтобы моя программа считывала некоторые числа, которые будут определять размер двумерного массива (используется в качестве матрицы). Первоначально я утверждал, что единственный способ сделать это - использовать вызов malloc для помещения массива в кучу, что-то вроде этого:

matrixElement* matrix = malloc(sizeof(matrixElement) * numRows * numCols);

где numCols и numRows - целые числа, которые были прочитаны ранее, а matrixElement - некоторый произвольный тип. Я рассуждал так, что просто написал:

matrixElement matrix[numRows][numCols];

не будет работать, так как компилятор не сможет узнать, сколько стекового пространства выделить для вызова функции. Оказывается, я был не прав, так как следующий код компилируется и запускается:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int x, y;
    scanf("%d", &x);
    scanf("%d", &y);

    double arr[x][y];

    printf("Made an array of size %d by %d, total memory %fKb\n", 
            sizeof(arr) / sizeof(arr[0]), 
            sizeof(arr[0]) / sizeof(arr[0][0]),
            (float) sizeof(arr) / 1024.0f);

    return 0;
}

С достаточно большими числами, введенными для x и y, это в конечном итоге приведет к ошибке, но я был очень удивлен, увидев, что я могу создать массив 1000x1000 с этим кодом.

Может кто-нибудь объяснить, что здесь происходит?

Компилятор просто выделяет кучу места для массива, даже если он не знает, сколько будет использовано?

Указано ли это поведение в ANSI C или это просто то, что делает gcc самостоятельно?

Ответы [ 3 ]

8 голосов
/ 02 ноября 2009

Эта функция была добавлена ​​в C99. Массив размещается в стеке так же, как если бы вы вызвали alloca(). Там могут быть некоторые тонкие различия; проверьте информацию в документации вашего компилятора.

Документация GCC содержит описание их реализации.

3 голосов
/ 02 ноября 2009

Вы должны быть столь же удивлены тем фактом, что вы можете объявить свой массив arr в середине блока, так же как и его размер, указанный в переменной. Оба являются новыми функциями спецификации языка C99. Оба были поддержаны компилятором GCC как расширение C89 / 90 на некоторое время. Но ни один не является законным в "классическом" ANSI C, то есть C89 / 90.

Если вы компилируете свой код в режиме C89 / 90 (по умолчанию в GCC), то вы действительно имеете дело с тем, что GCC делает самостоятельно. Если вы компилируете свой код в режиме -std=c99, вы имеете дело с [относительно] новыми функциями стандартных языков.

3 голосов
/ 02 ноября 2009

C99 добавлена ​​поддержка массивов переменной длины (иногда называемых «VLA»). Многие компиляторы C также поддерживали это до C99. Многие также поддерживали функцию «alloca», которая делала то же самое, хотя и несколько менее удобным способом.

Типичные реализации выделяют «правильный» объем пространства. По сути, указатель стека просто корректируется в зависимости от размера вашего массива переменной длины. Нужно сделать некоторую дополнительную бухгалтерию, чтобы гарантировать, что указатель стека «вытолкнет» нужное количество при возврате, и что автоматические переменные, помещенные в стек, доступны с правильным смещением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...