Я не могу заполнить массив в C all значением 0. Я пытаюсь memset и array[]={0};

#arrays #c #initialization

#массивы #c #инициализация

Вопрос:

Я использую memset для заполнения массива всеми нулями, но я думаю memset , что он работает неправильно (когда я отлаживаю его в компиляторе, он не заполняет его всеми нулями (IDK ПОЧЕМУ?)).

Когда я использую, например B[n] = { 0 } , я получаю сообщение об ошибке:

 variable-sized object may not be initialized
 

Код:

 #include <stdio.h>

int main()
{
    int m, n;
    scanf("%d%d", amp;m, amp;n);
    int A[m][n];
    int B[n];
    int redici = 0, koloni = 0, vkupno = 0;
    //memset(B, 0, n);
    B[n] = { 0 };
    int popolnetaR[m], popolnetaK[n];
    memset(popolnetaR, 0, m - 1);
    memset(popolnetaK, 0, n - 1);
    return 0;
}
 

Ответ №1:

Прежде всего, не используйте объявление таблицы с переменным размером int A[m][n] , потому что его поведение не указано в каждой ситуации — я настоятельно рекомендую вам прочитать это сообщение в блоге. В C99 это было разрешено, но поскольку C11 это не является частью стандарта, это необязательная функция.

Чтобы решить вашу проблему, memset принимает Number of bytes to be set to the value. в качестве третьего num аргумента. Итак, вы не хотите использовать

 memset(B, 0, n);
 

но

 memset(B, 0, n * sizeof(int));
 

Ошибка, которую вы получаете, в основном говорит о том, что этот «трюк» с ={0}
работает только с массивами постоянного размера.

Комментарии:

1. Re » потому что это не в языковом стандарте «, вы уверены в этом? В документе, на который вы ссылались, очень четко указано, что они являются частью стандарта C99. /// Говоря, все, что это говорит о том, что у вас может закончиться место в стеке, если вы его используете. Ну, то же самое можно сказать и о вызове функции, особенно рекурсивных. Вы не видите, чтобы мы избегали их, не так ли? Небольшие VLA неплохие. Но да, большие могут вызвать у вас проблемы.

2. Прежде всего, не используйте объявление таблицы с переменным размером, используя int A[m][n] , потому что в стандарте языка это не совсем неправильно . Я буду откровенен: если вы не можете правильно использовать VLAS, вам все равно не следует писать код на C. И как вы планируете динамически выделять 2-мерный массив переменного размера без VLAS? (Нет, массив указателей на несколько одномерных массивов не является 2-мерным массивом)

3. AFAIK нет, «alloca() зависит от компьютера и компилятора; его использование не рекомендуется». <- от man alloca . Блог посвящен возможным ловушкам при использовании VLA в C99.

4. Я добавил небольшое редактирование, чтобы уточнить, что я имел в виду 🙂

5. Это то, что написал этот блоггер: «ВЛАс путается в моей мысленной картине происходящего, потому что объявление переменной зависит от выполняемого кода». Этому блоггеру лучше никогда не использовать что-то подобное realloc() . И это: «Я склонен помещать все объявления переменных в начало функций. Это может быть пережитком времен C89, но для меня это также облегчает понимание того, что происходит в стеке;» Серьезно? Это какой-то авторитет на C? for ( int i = 0; i < count; i ) ... ему трудно «понять, что происходит в стеке»?

Ответ №2:

Вот несколько объяснений:

  • B[n] = { 0 }; это синтаксическая ошибка
  • int B[n] = { 0 }; это нарушение ограничений, как B и массив переменной длины, а стандарт C указывает, что VLAS не может иметь инициализатора.
  • memset(B, 0, n); устанавливает только n байты 0 , которые не охватывают весь диапазон массива B . Вместо этого вы должны написать:
     memset(B, 0, sizeof(*B) * n);
     

    Или просто:

     memset(B, 0, sizeof B);
     
  • то же замечание относится и к popolnetaR and popolnetaK .

Вот модифицированная версия:

 #include <stdio.h>

int main() {
    int m, n;

    if (scanf("%d%d", amp;m, amp;n) != 0 || m <= 0 || n <= 0)
        return 1;

    int A[m][n];
    int B[n];
    int popolnetaR[m], popolnetaK[n];
    int redici = 0, koloni = 0, vkupno = 0;
    memset(A, 0, size A);
    memset(B, 0, size B);
    memset(popolnetaR, 0, sizeof popolnetaR);
    memset(popolnetaK, 0, sizeof popolnetaK);
    // ...
    return 0;
}
 

Однако обратите внимание, что выделение слишком большого пространства при автоматическом хранении может привести к переполнению стека, что произойдет при умеренно больших значениях m и / или n .

Комментарии:

1. Большое вам спасибо за объяснение. Я очень ценю!