Как я могу объявить и определить несколько переменных в одной строке, используя 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.