Вопрос о новичках, на эффективности цикла. Я начал программировать в C++ (мой первый язык) и использовал 'Принципы и Практику Используя C++' Bjarne Stroustrup. Я пробивался через более ранние главы и был просто представлен понятию циклов.
Первое осуществление относительно циклов спрашивает меня следующее: символ 'b' является символом (+1), 'c' является символом (+2) и т.д. Используйте цикл для выписывания таблицы символов с их соответствующими целочисленными значениями:
97, b 98..., z 122
Хотя, я использовал верхний регистр, я создал следующее:
int number = 64; //integer value for @ sign, character before A
char letter = number;//converts integer to char value
int i = 0;
while (i<=25){
cout << ++letter << "\t" << ++number << endl;
++i;
}
Я должен стремиться только к наличию 'я' присутствовать в цикле, или разве это просто не возможно при преобразовании между типами? Я не могу действительно думать ни о каком другом способе, в который вышеупомянутое может быть сделано кроме наличия символьного значения, преобразовываемого, он - целочисленный дубликат (т.е. противоположность существующего метода) или просто не наличие преобразования вообще, и имейте хранилище буквы.
Вы должны сначала стремиться к ясности, и вы стараетесь вместо этого Micro оптимизировать. Вы можете лучше переписать, что как для цикла:
const int offsetToA = 65;
const int numberOfCharacters = 26;
for( int i = 0; i < numberOfCharacters; ++i ) {
const int characterValue = i + offsetToA;
cout << static_cast<char>( characterValue ) << characterValue << endl;
}
, и вы можете конвертировать между различными типами - это называется отливками ( Static_Cast
, конструируйте в код выше).
Следует от JK, вы можете даже использовать саму букву в петле (буква <= 'z'). Я также использовал петлю для цикла, но это только я.
for( char letter = 'a'; letter <= 'z'; ++letter )
std::cout << letter << "\t" << static_cast<int>( letter ) << std::endl;
Так как никто больше не упоминал об этом: Имея фиксированное количество итераций, это также кандидат на постусловную итерацию с do...while
.
char letter = 'a';
do {
std::cout << letter << "\t" << static_cast<int>( letter ) << std::endl;
} while ( ++letter <= 'z' );
Однако, как показано в ответе Патрика идиома для
часто бывает короче (в данном случае в количестве строк).
Нет ничего особо неэффективного о том, как вы это делаете, но это, безусловно, возможно просто преобразовать между Chars и IntS (CHAR - это целочисленный тип). Это будет означать, что вам нужно только хранить 1 счетчик, а не 3 (я, буква + номер), у вас в курсе
также, для зацикливания с фиксированного начала, чтобы закончить петлю «для», возможно, более идиоматична (хотя это возможно Ты еще не встретил этого!)
Увеличение трех отдельных переменных, вероятно, немного запутано. Вот возможность:
for (int i = 0; i != 26; ++i)
{
int chr = 'a' + i;
std::cout << static_cast<char>(chr) << ":\t" << chr << std::endl;
}
Обратите внимание, что использование для цикла
удерживает все логику настройки, тестирования и увеличения переменной петли в одном месте.
Это не плохой способ сделать это, но вы можете сделать это только с одной переменной петли, как это:
char letter = 65;
while(letter <= 65+25){
printf("%c\t%d\n", letter, letter);
++letter;
}
Если вы обеспокоены эффективностью вашего цикла, я бы побудил вас попробовать:
Получите этот код скомпилированным и запущенным под IDE, такие как Visual Studio, и установить Выровняйте точку в начале. Когда вы попадаете туда, перейдите на просмотр по разборке (представление инструкции) и начните ударить клавишу F11 (STOW STEP) и сохраняйте ментальный счетчик того, сколько раз вы его попадаете.
Вы увидите, что он входит в цикл, сравнивает I
против 25, а затем начинает выполнять код для Cout Cout
. Это включает в себя увеличение буква
, а затем входит в <<
<< [126047] для Cout. Там делает ряд вещей, возможно, идет глубже в подпрограммы и т. Д., И, наконец, возвращается, возвращая объект. Затем он толкает «\ T»
как аргумент и передает его к этому объекту и восходит назад и делает все это делали раньше. Тогда это занимает номер
, увеличивает его и передает его в Coutine :: <<
COUT :: << Рутина, которая принимает целое число, вызывает функцию для преобразования его в строку (которая включает в себя петлю ), то все это делало, прежде чем расти, чтобы цитать эту строку в выходной буфер и возврат.
Устали? Вы еще не закончены. EndL
должен быть выведен, а когда это произойдет, он не только ставится «\ N»
в буфере, но он вызывает системную рутину для промывания этого буфера в файл или консоль, где вы отправляете ввод / вывод. Вы, вероятно, не можете в этом, но отдых уверены, что требуется много циклов и не возвращается до тех пор, пока ввод / вывод.
К настоящему времени ваш счет F11 должен быть в непосредственной близости от нескольких тысяч, более или менее.
Наконец, вы выходите и добираетесь до оператора ++ I
, который занимает 1 или 2 инструкции и переходит назад к верхней части цикла, чтобы начать следующую итерацию.
Теперь вы все еще беспокоитесь о эффективности цикла?
Есть более простой способ сделать этот момент, и это так же, как поучительный. Оберните бесконечную петлю вокруг всего кода, чтобы он работает навсегда. Хотя он работает, нажмите кнопку «Пауза» в IDE и посмотрите на стек вызовов. (это называется «StackShot».) Если вы делаете это несколько раз, вы получаете хорошее представление о том, как это проводит время. Вот пример:
NTDLL! 7c90e514()
KERNEL32! 7c81cbfe()
KERNEL32! 7c81cc75()
KERNEL32! 7c81cc89()
MSVCRTD! 1021bed3()
MSVCRTD! 1021bd59()
MSVCRTD! 10218833()
MSVCRTD! 1023a500()
std::_Fputc() line 42 + 18 bytes
std::basic_filebuf<char,std::char_traits<char> >::overflow() line 108 + 25 bytes
std::basic_streambuf<char,std::char_traits<char> >::sputc() line 85 + 94 bytes
std::ostreambuf_iterator<char,std::char_traits<char> >::operator=() line 304 + 24 bytes
std::num_put<char,std::ostreambuf_iterator<char,std::char_traits<char> > >::_Putc() line 633 + 32 bytes
std::num_put<char,std::ostreambuf_iterator<char,std::char_traits<char> > >::_Iput() line 615 + 25 bytes
std::num_put<char,std::ostreambuf_iterator<char,std::char_traits<char> > >::do_put() line 481 + 71 bytes
std::num_put<char,std::ostreambuf_iterator<char,std::char_traits<char> > >::put() line 444 + 44 bytes
std::basic_ostream<char,std::char_traits<char> >::operator<<() line 115 + 114 bytes
main() line 43 + 96 bytes
mainCRTStartup() line 338 + 17 bytes
Я сделал это куча раз, и не развернул его в коде для внешнего i <= 25
цикла. Таким образом, оптимизация того, что цикл похож на чью-то отличную метафору: «Получение стрижки, чтобы похудеть».
На данный момент я бы не стал беспокоиться о микро-оптимизациях, таких как эффективный способ написания небольшого цикла, как этот. То, что у вас есть, позволяет циклу для
делать эту работу хорошо, но если вам удобнее использовать в то время как
, вы должны использовать это. Но я не уверен, что это ваш вопрос.
Я не думаю, что вы правильно поняли вопрос. Вы пишете код, зная, что 'A'
- это 65. Весь смысл этого упражнения заключается в том, чтобы распечатать значение от 'A'
до 'Z'
в вашей системе, не зная, какое значение они имеют.
Теперь, чтобы получить целое значение для символа c
, можно сделать: static_cast
. Думаю, это то, о чем вы просите.
Я не писал никакого кода, потому что это должно быть веселее для вас.
Вопрос для экспертов: В Си я знаю, что 'а'
... 'z'
не обязательно должны иметь непрерывные значения (то же самое для 'A'
... 'Z'
). То же самое верно и для C++? Я бы так и думал, но тогда кажется крайне маловероятным, что книга Струстрапа предполагает это.