Создать массив целых чисел, используя цифры в качестве размера

Я пытаюсь создать массив символов в C, чтобы заполнить его цифрами int, но int может иметь любое количество цифр.

Я использую созданную функцию под названием getDigits(int num), который возвращает количество цифр, которое имеет int.

char buffer[getDigits(number)] = "";
snprintf(buffer, sizeof(buffer),"%d",number);

но когда я компилирую с использованием gcc, он возвращает:

error: variable-sized object may not be initialized

Я перепробовал все. Когда я объявляю это как char fileSizeStr[5] = "";, оно работает. Я вижу, что проблема возрастает, когда я пытаюсь динамически объявить размер буфера, но мне бы очень хотелось узнать, есть ли способ добиться этого.

5 ответов

Решение

Проблема именно в том, что говорит вам ваш компилятор; Вы не можете инициализировать VLA. Зак дал очевидное решение в комментариях: уберите инициализацию. В этом ответе вы найдете рабочие примеры, некоторые из которых разрешают инициализацию, а другие - нет. Вы найдете больше информации об этом в комментариях. Следующие примеры упорядочены от наиболее разумных (IMHO) к наименее разумным (которые включают использование malloc) для выделения памяти для последовательностей десятичных цифр, представляющих числа.


Я предлагаю использовать тот же трюк, чтобы определить, сколько байтов необходимо для хранения int значение в виде десятичных цифр, которое вы использовали бы для восьмеричного числа: разделите общее число бит в int на 3 и добавить для любого знака и NUL прекращения. digit_count можно написать как макрос препроцессора, например так:

#include <limits.h>
#include <stddef.h>
#include <stdio.h>

#define digit_count(num) (1                                /* sign            */ \
                        + sizeof (num) * CHAR_BIT / 3      /* digits          */ \
                        + (sizeof (num) * CHAR_BIT % 3 > 0)/* remaining digit */ \
                        + 1)                               /* NUL terminator  */

int main(void) {
    short short_number = -32767;
    int int_number = 32767;
    char short_buffer[digit_count(short_number)] = { 0 }; /* initialisation permitted here */
    char int_buffer[digit_count(int_number)];
    sprintf(short_buffer, "%d", short_number);
    sprintf(int_buffer, "%d", int_number);
}

Как видите, одно из важных преимуществ заключается в том, что digit_count может использоваться для любого типа целого числа без изменений: char, short, int, long, long longи соответствующий unsigned типы.

Одним небольшим недостатком сравнения является то, что вы тратите несколько байтов памяти, особенно для небольших значений, таких как 1, Во многих случаях простота этого решения более чем компенсирует это; Код, необходимый для подсчета десятичных цифр во время выполнения, будет занимать больше места в памяти, чем здесь теряется.


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

#include <stddef.h>
#include <stdio.h>

size_t digit_count(int num) {
    return snprintf(NULL, 0, "%d", num) + 1;
}

int main(void) {
    int number = 32767;
    char buffer[digit_count(number)]; /* Erroneous initialisation removed as per Zacks advice */
    sprintf(buffer, "%d", number);
}

В ответ на malloc рекомендации: наименее ужасный способ решить эту проблему - избежать ненужного кода (например, malloc и позже free). Если вам не нужно возвращать объект из функции, не используйте malloc! В противном случае рассмотрите возможность сохранения в буфере, предоставленном вызывающей стороной (посредством аргументов), чтобы вызывающая сторона могла выбрать, какой тип хранилища использовать. Это очень редко, что это не подходящая альтернатива использованию malloc,

Если вы решили использовать malloc а также free для этого, однако, сделать это наименее ужасным способом. Избегайте typecasts на возвращаемое значение malloc и умножения на sizeof (char) (который всегда 1). Следующий код является примером. Используйте любой из вышеперечисленных методов для расчета длины:

char *buffer = malloc(digit_count(number)); /* Initialisation of malloc bytes not possible */
sprintf(buffer, "%d", number);

... и не забудьте free(buffer); когда вы закончите с этим.

Попробуйте что-то вроде:

 char* buffer =(char *)malloc(getDigits(number)*sizeof(char));

malloc и calloc используются для динамического распределения.

За мои деньги есть одно решение, которое не упоминалось, но которое на самом деле проще, чем любое из вышеперечисленного. Существует комбинированная распределительная версия sprintf под названием "asprintf", доступная в Linux и большинстве вариантов BSD. Он определяет необходимый размер, выделяет память и возвращает заполненную строку в первый аргумент.

char * a;
asprintf(&a, "%d", 132);
// use a
free(a);

Использование выделенного массива стека, конечно, устраняет необходимость в свободном доступе, но это полностью устраняет необходимость когда-либо отдельно вычислять размер.

Ниже может помочь

char* buffer;
buffer = (char*)malloc(number * sizeof(char));

Вам нужно будет использовать malloc выделить динамический объем памяти.

Инициализация, которую вы сделали, разрешена, только если размер известен во время компиляции.

Другие вопросы по тегам