Как создать массив без объявления размера в C? - PullRequest
0 голосов
/ 29 апреля 2018

Я довольно плохо знаком с новым C и не смог найти ничего, связанного с этим (возможно, потому что я не совсем уверен, что я ищу).

Я пытаюсь создать массив типа int и float без размера (это может быть 0 или оно может увеличиваться при использовании программы пользователем).

Я пытался сделать следующее:

int bills[];

float totalAmount[];

Я не могу назначить максимальный размер, потому что я печатаю каждый массив с циклом for (если я назначу размер 99, я напечатаю 99 строк, и я этого не хочу).

Я почти уверен, что это возможно, но я не знаю как.

Спасибо!

Ответы [ 3 ]

0 голосов
/ 29 апреля 2018

C не поддерживает массивы с динамическим числом элементов. Количество элементов массива должно быть определено либо во время компиляции, либо, поскольку C99 может быть оценен во время выполнения в точке создания. Как только массив создан, его размер является фиксированным и не может быть изменен. Есть несколько случаев, когда размер явно не указан между [], либо в определениях массива, либо в объявлениях массива.

Вы можете определить массив без явного размера для самого левого измерения, если вы предоставите инициализатор. Компилятор выведет размер из инициализатора:

int a[] = { 1, 2, 3 };              // equivalent to int a[3] = { 1, 2, 3 };
int m[][2] = {{ 1, 2 }, { 3, 4 }};  // equivalent to int m[2][2] = {{ 1, 2 }, { 3, 4 }};
char s[] = "Hello world\n";         // equivalent to char s[13] = "Hello world\n";

Обратите внимание, как компилятор добавляет неявный нулевой терминатор в строковом регистре.

Вы можете объявить массив без спецификатора размера для крайнего левого измерения в нескольких случаях:

  • как глобальная переменная с extern хранилищем классов (массив определен в другом месте),
  • как параметр функции: int main(int argc, char *argv[]). В этом случае размер, указанный для самого левого размера, все равно игнорируется.
  • как последний член struct. Это расширение C99, называемое гибким массивом .

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

В случае аргумента функции, массив передается как указатель, и даже если указано количество элементов, sizeof(argv) оценивается как размер указателя.

0 голосов
/ 29 апреля 2018

Для этого можно использовать комбинацию malloc() (или calloc()), realloc() и free().

Память может быть выделена как блоки фиксированного размера, а не перераспределять память для каждого сохраняемого числа.

Давайте определим макрос (или const, если хотите) BLOCK_SIZE.

#define BLOCK_SIZE 10

Сначала объявите указатель соответствующего типа и выделите первый блок.

Обратите внимание, что malloc(), а также realloc() возвращают NULL, если произошла какая-либо ошибка по причинам, таким как нехватка памяти.

int *ptr=malloc(sizeof(int)*BLOCK_SIZE);    
if(ptr==NULL)
{
    perror("some error");
    return 1;
}

Теперь объявите переменную для хранения максимально возможного индекса в соответствии с выделенной в данный момент памятью (чтобы избежать несанкционированного доступа к памяти).

int max_index = BLOCK_SIZE-1;

Теперь используйте цикл.

for(int i=0; ; ++i)
{
    if(i > max_index)
    {
        ptr=realloc(ptr, (max_index+1 + BLOCK_SIZE)*sizeof(int));
        if(ptr == NULL)
        {
            perror("insufficient memory!");
            break;
        }
        printf("\nRealloced!");
        max_index += BLOCK_SIZE;
    }
    scanf("%d", &ptr[i]);
    printf("\n%d: %d", i, ptr[i]);
}

На каждой итерации мы проверяем, больше ли i, чем max_index. Если это так, другой блок выделяется с помощью realloc() перед чтением значения.

Не забудьте освободить память, как только закончите с ней.

free(ptr);

Кроме того, как обсуждалось в этом посте, malloc() фактически совпадает с realloc() с первым аргументом последнего NULL.

И в опубликованном вами коде нет необходимости явно приводить возвращаемое значение calloc(), поскольку возвращаемым является указатель void, который неявно преобразуется в целевой тип указателя.

См. это и это .

0 голосов
/ 29 апреля 2018

Вы не объявляете массив без размера, вместо этого вы объявляете указатель на несколько записей.

так, если вы хотите сделать

int bills[];

Правильный способ сделать это в C -

int* bills;

И вам придется выделить размер в определенный момент времени и инициализировать массив.

bills = (int*)malloc(sizeof(int)*items);

То же самое касается массивов других типов данных. Если вы не знаете размер массива до времени выполнения, вам следует использовать указатели на память, которая выделена на правильный размер во время выполнения.

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