Как я могу объявить и определить несколько переменных в одной строке, используя C ++?


173

Я всегда думал, что если я объявлю эти три переменные, то все они будут иметь значение 0

int column, row, index = 0;

Но я считаю, что только индекс равен нулю, а остальные такие же, как 844553 и 2423445.

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


36
Осторожнее с этими однострочными объявлениями с несколькими переменными. Это проще, чем вы думаете, объявить указатель типа int, за которым следует список обычных целых чисел ( int* a, b, c;не выполняется так, как это выглядит).
— Крис Эберле

4
Есть только три переменные, чувак, напиши =0для каждой в своих определениях. И, если вам действительно нужно много переменных, попробуйте массив: int a[10]={0}инициализирует каждую a[i]для вас 0.
— Стэн

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

1
@ cph2117 Разумный программист подумал бы: «Хм, этот синтаксис может означать несколько разных вещей в зависимости от того, как грамматика связывает вещи» , посмотрите Стандарт, чтобы узнать, что является правдой, и продолжайте в том же духе .
— underscore_d

Хватит это делать. Это только затрудняет чтение кода. Смысл написания кода на языке высокого уровня состоит в том, чтобы облегчить чтение для сопровождающего.
— Мартин Йорк

Ответы:



162

Когда вы заявляете:

int column, row, index = 0;

Только индекс установлен на ноль.

Однако вы можете сделать следующее:

int column, row, index;
column = index = row = 0;

Но лично я предпочитаю следующее, на которое было указано.
Это более читаемая форма, на мой взгляд.

int column = 0, row = 0, index = 0;

или

int column = 0;
int row = 0;
int index = 0;

3
Между двумя последними я решаю, основываясь на том, должны ли два значения действительно быть одного и того же типа ( bool previousInputValue, presentInputValue;) или же они просто имеют один и тот же тип сейчас, но не обязательно должны быть ( uint8_t height, width;могут превратиться в uint8_t height; uint16_t width;будущее и должны были быть uint8_t height; uint8_t width;начать с).
— altendky

Потому что запись uint8_t height; uint16_t width;вместо того, чтобы uint8_t height, width;сохранить 10 символов в будущем. :-) Конечно, вы можете делать это как хотите. Просто убедитесь, что вы делаете это легко читать. Таким образом, последняя форма является наиболее явной.
— Мэтт

Последняя форма, безусловно, является наиболее явной при указании типа каждой переменной и прояснении того, что каждая инициализирована. Тем не менее, неясно, должны ли столбцы и строки быть одного типа или нет. Возможно, мы оба предпочли бы явность int presentValue = 0; typeof(presentValue) previousValue = presentValue;, но я считаю, что typeof()это нестандартное расширение GCC.
— altendky

49

Как сказал @Josh, правильный ответ:

int column = 0,
    row = 0,
    index = 0;

Вам нужно следить за тем же с помощью указателей. Это:

int* a, b, c;

Эквивалентно:

int *a;
int b;
int c;

34
Я ненавижу эту вещь указателя, это не имеет никакого смысла. Звездочка является частью типа, поэтому она должна применяться ко всем из них. Вообразите, если unsigned long x, y;объявлено xкак, unsigned longно yкак раз unsigned, иначе unsigned int! Это точно так же! </ rant>
— Кэм Джексон

6
Это имеет смысл. "int * a, b, c;"
— Йерун

7
@JeroenBollen Ну да, имеет смысл, если вы пишете звездочки рядом с именем переменной вместо типа, но это само по себе не имеет никакого смысла. Как я уже говорил выше, звездочка является частью типа, а не частью имени, поэтому она должна быть сгруппирована с типом!
— Кэм Джексон

11
С другой стороны, на самом деле имеет смысл, что * не обязательно является частью типа, как int *aсредство, *aпредставляющее intзначение.
— mdenton8

2
Идея уже была высказана, но просто добавить к ней void - это, по сути, отсутствие типа, но вы все равно можете делать на него указатели. Таким образом, почему void* aбудет компилировать и void *a, b, cне будет. Эта рационализация работает для меня.
— Джош К

25

Если вы объявляете одну переменную / объект на строку, это не только решает эту проблему, но и делает код более понятным и предотвращает глупые ошибки при объявлении указателей.

Чтобы напрямую ответить на ваш вопрос, вы должны явно инициализировать каждую переменную равной 0. int a = 0, b = 0, c = 0;,


16
int column(0), row(0), index(0);

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


2
и в настоящее время с равномерной инициализацией (в ожидании исправления C ++ 17 для auto...): int column { 0 } , строка { 0 } , индекс { 0 } ;
— underscore_d


4

Возможные подходы:

  • Инициализируйте все локальные переменные с нуля.
  • Есть массив memsetили {0}массив.
  • Сделайте это глобальным или статическим.
  • Поместите их struct, и / memsetили есть конструктор, который будет инициализировать их в ноль.

#define COLUMN 0 #define ROW 1 #define INDEX 2 #define AR_SIZE 3 int Data [ AR_SIZE ]; // Просто идея.
— Ajay

Извините, я имел в виду, почему вы включили в свой ответ строку " Есть массив, memset или {0} массив. "
— Матин Улхак,

memset (Данные, 0, sizeof (Данные)); // Если это можно упаковать логически.
— Ajay

2

Я бы не рекомендовал это, но если вы действительно хотите, чтобы это была одна строка и только один раз написать 0, вы также можете сделать это:

int row, column, index = row = column = 0;

0

Как уже упоминалось, начиная с C ++ 17 вы можете использовать структурированные привязки для множественных присвоений переменных.

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

#include <iostream>
#include <array>

template <int N, typename T> auto assign(T value)
{
    std::array<T, N> out;
    out.fill(value);
    return out;
}

int main()
{
    auto [a, b, c] = assign<3>(1);

    for (const auto& v : {a, b, c})
    {
        std::cout << v << std::endl;
    }

    return 0;
}

Demo


-13

Когда вы объявляете переменную без ее инициализации, выбирается случайное число из памяти, и переменная инициализируется этим значением.


7
на самом деле, нет. Компилятор решает, что «эта переменная будет по адресу xxx», а то, что окажется по адресу xxx, будет исходным значением, если только оно не установлено явно (путем инициализации или присваивания)
— pm100

3
@ pm100 хотя и лучше , и верно для любой тривиальной реализации, которая не мешает преследовать пользователей ... это все еще упрощает ;-), поскольку использование неинициализированной переменной - это UB, так что в теории может произойти все, включая любой код использование этой переменной просто исключается из программы - что особенно вероятно, когда оптимизация находится в игре.
— underscore_d

1
значение этой переменной будет равно тому, что было по адресу, который она получила, т.е.
— Педро Вернетти

@PedroVernetti Неважно, что произошло по указанному адресу до того, как была объявлена ​​новая переменная и получен тот же адрес. Если пользователь объявляет новую переменную без инициализации ее значением, а затем читает переменную перед тем, как присвоить ей значение, программа имеет неопределенное поведение. Это бесконечно хуже, чем «случайный» и «мусорный», и его просто нужно избегать.
— underscore_d
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.