C - динамические массивы

Я не совсем понимаю, как указатели работают с массивами C. Вот некоторый код, который я получил:

int arrayOne[] = {1, 2, 3};
int arrayTwo[] = {4, 5, 6, 7};

int **arrayThree = (int **)malloc(2 * sizeof(int));
arrayThree[0] = arrayOne;
arrayThree[1] = arrayTwo;

for (int i = 0; i < 2; i++) {
    int *array = arrayThree[i];
    int length = sizeof(array) / sizeof(int);
    for (int j = 0; j < length; j++)
        printf("arrayThree[%d][%d] = %d\n", i, j, array[j]);
}

Я ожидал, что это выведет следующее:

arrayThree[0][0] = 1
arrayThree[0][1] = 2
arrayThree[0][2] = 3
arrayThree[1][0] = 4
arrayThree[1][1] = 5
arrayThree[1][2] = 6
arrayThree[1][3] = 7

То, что он на самом деле печатает, это:

arrayThree[0][0] = 1
arrayThree[0][1] = 2
arrayThree[1][0] = 4
arrayThree[1][1] = 5

Почему?!


person ryyst    schedule 07.03.2011    source источник
comment
Вам не нужно приводить к типу результат указателя void из malloc(), если только вы не компилируете код C на компиляторе C++, что делать нехорошо.   -  person Lundin    schedule 07.03.2011


Ответы (4)


sizeof(array) — это размер указателя, который вдвое превышает размер int на вашей платформе.

В C нет способа получить длину массива. Вам просто нужно запомнить ее самостоятельно.

person David Heffernan    schedule 07.03.2011
comment
@Erik Мое редактирование, чтобы исправить то, что появилось за несколько секунд до вашего комментария !! - person David Heffernan; 07.03.2011
comment
В C нет способа получить длину массива. Вам просто нужно запомнить ее самостоятельно. Или используйте специальное значение маркера, например, разделитель строки \0. - person user; 07.03.2011
comment
@David: Здесь должен быть значок за скорость набора текста: P - person Erik; 07.03.2011
comment
Тогда почему int array[] = {1, 2, 3, 4, 5, 6, 7}; printf("sizeof(array) = %lu\n", sizeof(array) / sizeof(int)); работает? - person ryyst; 07.03.2011
comment
Потому что это массив постоянного размера. Это то же самое, что объявить его как int array[7] - person David Heffernan; 07.03.2011
comment
Потому что вы используете sizeof для массива, а не для указателя. Массивы могут распадаться на указатели, но это не одно и то же. - person Erik; 07.03.2011
comment
Предложение @user @Michael о завершении массивов часовыми является обычным способом решения этой проблемы. Вы выполняете итерацию по массиву, пока не достигнете конечного часового. Это действительно работает, только если вы можете зарезервировать одно специальное значение. - person David Heffernan; 07.03.2011
comment
Значит, константный массив каким-то образом сохраняет свою длину, а указатель (или массив, превратившийся в указатель) — нет? - person ryyst; 07.03.2011
comment
@ user282635: потому что оператор sizeof ведет себя по-разному для массивов и указателей. В исходном коде array имеет тип int *, тогда как в вашем комментарии это тип int [7]. - person John Bode; 07.03.2011
comment
@ user282635: он даже не сохраняется, он вычисляется во время компиляции. - person SirDarius; 07.03.2011
comment
@ user282635: нет, размер массива является частью его типа, поэтому компилятор знает это без его сохранения. Эта информация теряется (для компилятора), когда массив распадается на указатель. Итак, когда вы делаете int array[] = {1, 2, 3}, тип array будет int[3], поэтому sizeof array будет 3 * sizeof(int). Когда вы делаете int *array = whatever, тип array — это просто int*, без информации о размере, а sizeof array — это просто sizeof(int*). - person Steve Jessop; 07.03.2011
comment
Комментарий Стива прибивает. Вы можете получить размер массива, если у вас есть переменная, тип которой является массивом. Если все, что у вас есть, это указатель на начало массива, то все, что вы получите, это размер указателя. - person Nemanja Trifunovic; 07.03.2011

Во-первых, int **arrayThree = (int **)malloc(2 * sizeof(int)) неправильно, должно быть sizeof(int *)

Затем sizeof(array) / sizeof(int) соответствует sizeof(int *) / sizeof(int), а это не то, что вам нужно.

В указателе, который вы рассматриваете как массив, нет «встроенной» информации о размере, вам нужно будет вручную управлять размером.

person Erik    schedule 07.03.2011

В C нет встроенного механизма для отслеживания размера массива, вам нужно поддерживать его самостоятельно и передавать его любой функции, которая принимает ваш массив в качестве параметра.

Однако если вам действительно нужно широко и динамически использовать массивы в C, вы можете без особых усилий создать собственную библиотеку динамических массивов в C. Для получения дополнительной информации обратитесь к следующему руководству: goo.gl/vYhkF.

person Greg    schedule 07.03.2011

Прежде всего, выделение arrayThree должно быть

int **arrayThree = malloc(2 * sizeof *arrayThree);

Поскольку тип arrayThree — это int **, то тип *arrayThree — это int *.

Причина, по которой sizeof (array) / sizeof (int) не возвращает того, что вы ожидаете, заключается в том, что array является указателем (тип int *), а не типом массива, поэтому sizeof возвращает количество байтов, содержащихся в указателе object< /em> сам, а не количество элементов, на которые указывает.

Невозможно узнать только по значению указателя, на сколько элементов указывает указатель; вы должны отслеживать эту информацию отдельно.

person John Bode    schedule 07.03.2011