C ++ выполняет функцию перед ее вызовом? [Дубликат]

Когда вы пишете [x]*3, вы получаете, по существу, список [x, x, x]. То есть список с 3 ссылками на тот же x. Когда вы затем изменяете этот сингл x, он отображается через все три ссылки на него.

Чтобы исправить это, вам нужно убедиться, что вы создаете новый список в каждой позиции. Один из способов сделать это -

[[1]*4 for n in range(3)]

, который будет повторно оценивать [1]*4 каждый раз, а не оценивать его один раз и делать 3 ссылки на 1 список.


Вы можете удивиться почему * не может создавать независимые объекты так, как это делает понимание списка. Это потому, что оператор умножения * работает с объектами, не видя выражений. Когда вы используете * для умножения [[1] * 4] на 3, * видит только 1-элементный список [[1] * 4], а не текст выражения [[1] * 4. * не имеет понятия, как делать копии этого элемента, не знаю, как переоценить [[1] * 4], и не подозревайте, что вы даже хотите копировать, и вообще, возможно, даже не было способа скопировать элемент.

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

Напротив, понимание списка переоценивает выражение элемента на каждой итерации. [[1] * 4 for n in range(3)] пересчитывает [1] * 4 каждый раз по той же причине [x**2 for x in range(3)] каждый раз переоценивает x**2. Каждая оценка [1] * 4 генерирует новый список, поэтому понимание списка делает то, что вы хотели.

Кстати, [1] * 4 также не копирует элементы [1], но это не имеет значения , так как целые числа неизменны. Вы не можете сделать что-то вроде 1.value = 2 и превратить 1 в 2.

10
задан Denilson Sá Maia 6 August 2014 в 00:20
поделиться

2 ответа

Вот что происходит с входным буфером при запуске вашей программы:

std::cin >> name;

Вы ждете ввода. Когда вы вводите «Ryan Cleary» и нажимаете enter, входной буфер содержит:

Ryan Cleary\n

Теперь ваш cin читает ввод как обычно, останавливаясь в пробеле, оставляя ваш буфер следующим образом:

 Cleary\n

Обратите внимание на начальное пространство, так как оно останавливается после прочтения Ryan. Ваша первая переменная теперь содержит Ryan. Если, однако, вы хотите получить полное имя, используйте std::getline . Он будет читать до новой строки, а не только пробелов. В любом случае, продолжайте:

std::cin >> age;

Теперь вы получаете еще один вход. Тем не менее, там что-то есть. Он пропускает пробел, пока он не начнет чтение, оставив буфер только:

\n

Ваша вторая переменная получает текст Cleary. Обратите внимание на новую строку в буфере, которая возвращает меня ко второй части. Замена system ("pause"); таким образом, который всегда работает, является сложной задачей. Лучше всего жить с решением, отличным от совершенства, или, как мне нравится, тем, что не гарантируется, что он точно говорит:

std::cin.get(); //this consumes the left over newline and exits without waiting

Хорошо, поэтому cin.get() не работает. Как насчет этого:

std::cin.get(); //consume left over newline
std::cin.get(); //wait

Это работает отлично, но что, если вы скопируете-вставьте его где-нибудь, где новая строка не останется? Вам нужно нажать дважды!

Решение состоит в том, чтобы очистить новую строку (и все остальное), а затем подождать. Это цель cin.sync() . Однако, как видно из раздела примечаний, не гарантируется очистка буфера, как он говорит, поэтому, если ваш компилятор не захочет, его нельзя использовать. Для меня, тем не менее, он делает именно это, оставляя решение:

std::cin.sync(); //clear buffer
std::cin.get(); //wait

. Самое главное в system("pause"); заключается в том, что вы не знаете, какую программу он будет запускать на чужом компьютере. Они могли бы изменить pause.exe или перенести тот, который был найден первым, и вы не знаете. Это может потенциально разрушить их компьютер из-за того, что это возможно любая программа .

14
ответ дан chris 21 August 2018 в 06:20
поделиться
  • 1
    Спасибо, отличный ответ. Это многое объясняло мне. У меня гораздо больше понимания, чем раньше, с тем, как вводит CIN-анализ. – dead beef 13 July 2012 в 00:43
  • 2
    Я натолкнулся на это, в то время как Гуглинг. Отличное объяснение. Большое спасибо. – PingPing 4 September 2013 в 20:54

Вы должны попробовать cin.getline , таким образом, поток будет считан до первого символа новой строки.

Хорошо, плохие советы, как указывали некоторые люди. Вы можете использовать std :: getline для чтения целой строки. Опять же, разделитель является новой линией, если не сообщается. Для чтения из cin вы можете передать его как первый параметр (и строку как вторую).

std::string str;
std::getline(cin, str); // to read until the end of line

std::getline(cin, str, ' '); // to read until a space character, for instance

(конечно, вы можете опустить часть std:: из строк, поскольку вы уже сообщили компилятору, что используете пространство имен std)

7
ответ дан Bruno Brant 21 August 2018 в 06:20
поделиться
  • 1
    -1 плохой совет. std::getline является безопасным и легким, cin.getline - нет. – Cheers and hth. - Alf 13 July 2012 в 00:12
  • 2
    Я пропустил ту часть, где ОП сказал, что он использует класс струн. – Bruno Brant 13 July 2012 в 00:14
  • 3
    Исправленный. Но, в любом случае, я не заслуживаю внимания, поскольку я просто заимствовал ответ из комментариев ... – Bruno Brant 13 July 2012 в 00:20
  • 4
    @BrunoBrant, он содержит правильную информацию сейчас. Тот факт, что вы предприняли попытку изменить его, - это то, что имеет значение. – chris 13 July 2012 в 00:27
  • 5
    хорошо, удалил downvote – Cheers and hth. - Alf 14 July 2012 в 02:02
Другие вопросы по тегам:

Похожие вопросы: