Эффективность цикла - C ++ - PullRequest
8 голосов
/ 22 января 2010

Вопрос для начинающих, об эффективности цикла. Я начал программировать на C ++ (мой первый язык) и использовал «Принципы и практика использования C ++» Бьярна Страуструпа. Я пробирался через предыдущие главы и только что познакомился с концепцией циклов.

Первое упражнение, касающееся циклов, требует от меня следующего: Символ 'b' является символом ('a' + 1), 'c' является символом ('a' + 2) и т. Д. Используйте цикл для записи таблица символов с соответствующими им целочисленными значениями:

a 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;
    }

Должен ли я стремиться к тому, чтобы в цикле присутствовало только 'i', или это просто невозможно при преобразовании между типами? Я не могу думать о каком-либо другом способе, описанном выше, за исключением того, что значение символа преобразуется в его целочисленный аналог (т. Е. Противоположен текущему методу) или просто не имеет преобразования вообще и имеет хранилище букв '@'.

Ответы [ 11 ]

22 голосов
/ 22 января 2010

Исходя из jk, вы можете даже использовать саму букву в цикле (буква <= 'z'). Я бы также использовал цикл for, но это только я. </p>

for( char letter = 'a'; letter <= 'z'; ++letter )
    std::cout << letter << "\t" << static_cast<int>( letter ) << std::endl;
8 голосов
/ 22 января 2010

Сначала вы должны стремиться к ясности и вместо этого попытаться оптимизировать микро. Вы могли бы лучше переписать это как цикл for:

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 в приведенном выше коде).

2 голосов
/ 23 января 2010

Если вы обеспокоены эффективностью вашего цикла, я призываю вас попробовать это:

Получите этот код, скомпилированный и запущенный в среде IDE, такой как Visual Studio, и установите точку останова в начале. Когда вы туда доберетесь, переключитесь на вид разборки (вид инструкций) и начните нажимать клавишу F11 (одношаговый) и сохраняйте подсчет того, сколько раз вы нажимаете на нее.

Вы увидите, что он входит в цикл, сравнивает i с 25, а затем начинает делать код для строки cout. Это включает в себя увеличение letter, а затем переход к процедуре << для cout. Он делает там много вещей, возможно, углубляясь в подпрограммы и т. Д., И, наконец, возвращается, возвращая объект. Затем он выдвигает "\t" в качестве аргумента и передает его этому объекту, возвращается и выполняет все то, что делал раньше. Затем он принимает number, увеличивает его и передает его в подпрограмму cout::<<, которая принимает целое число, вызывает функцию для преобразования ее в строку (которая включает цикл), а затем выполняет всю работу, которую он делал до цикла эту строку в выходной буфер и вернуть.

Устали? Вы еще не закончили. endl должен быть выведен, и когда это происходит, он не только помещает "\n" в буфер, но и вызывает системную подпрограмму для сброса этого буфера в файл или консоль, куда вы отправляете ввод / вывод. Вы, вероятно, не можете использовать F11, но будьте уверены, это займет много циклов и не вернется, пока не будет выполнен ввод / вывод.

К настоящему времени ваш F11-счет должен составлять около нескольких тысяч, более или менее.

Наконец, вы выходите и получаете оператор ++i, который принимает 1 или 2 инструкции и возвращается к началу цикла, чтобы начать следующую итерацию.

СЕЙЧАС, вы все еще беспокоитесь об эффективности цикла?


Есть более простой способ сделать это, и он так же поучителен. Оберните бесконечный цикл вокруг всего вашего кода, чтобы он работал вечно. Пока он работает, нажмите кнопку «пауза» в IDE и посмотрите на стек вызовов. (Это называется «стопкой».) Если вы сделаете это несколько раз, вы получите хорошее представление о том, как он проводит время. Вот пример:

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. Поэтому оптимизация этой петли - это как чья-то метафора: «стричься, чтобы похудеть».

2 голосов
/ 22 января 2010

Это не плохой способ сделать это, но вы можете сделать это только с одной переменной цикла, как это:

char letter = 65;

while(letter <= 65+25){
  printf("%c\t%d\n", letter, letter);
  ++letter;
}
2 голосов
/ 22 января 2010

нет ничего особенно неэффективного в том, как вы это делаете, но, безусловно, можно просто конвертировать между символами и целыми числами (тип символа целочисленный). это будет означать, что вам нужно хранить только 1 счетчик, а не 3 (i, буква + число), которые у вас есть

также, поскольку цикл от фиксированного начала до конца цикла for, возможно, более идиоматичен (хотя возможно, что вы еще этого не встречали!)

1 голос
/ 28 июля 2014

Вы можете продвигать char к int ...

//characters and their corresponding integer values
#include"../../std_lib_facilities.h"

int main()
{
    char a = 'a';
    while(a<='z'){
        cout<<a<<'\t'<<a*1<<'\n'; //a*1 => char operand promoted to integer!
        ++a;
    }

    cout<<endl;
}
1 голос
/ 23 января 2010

Поскольку никто больше не упоминал об этом: имея фиксированное количество итераций, это также кандидат на итерацию после условия с do..while.

char letter = 'a';
do {
    std::cout << letter << "\t" << static_cast<int>( letter ) << std::endl;
} while ( ++letter <= 'z' );

Однако, как показано в ответ Патрика , идиома for часто короче (в данном случае количество строк).

0 голосов
/ 23 июня 2015

Я попробовал это и работал нормально:

char a = 'a';
int i = a; //represent char a as an int
while (a <= 'z') {
cout << a << '\t' << i << '\n';
++a;
++i;
}
0 голосов
/ 26 декабря 2010

спасибо за помощь ... все, что я записал, было

int main() 
{
char letter = 96;
int number = letter;
int i = 0;

while(i <26)
{
cout <<++letter <<":" <<++numbers <<"  ";
++i;
}

прекрасно работает ... и теперь довольно просто понять.

0 голосов
/ 22 января 2010

На данный момент я бы не стал беспокоиться о микрооптимизации, такой как эффективный способ написать небольшой цикл, подобный этому. То, что у вас есть, позволяет циклу for хорошо выполнять свою работу, но если вам удобнее использовать while, вам следует это использовать. Но я не уверен, что это ваш вопрос.

Не думаю, что вы правильно поняли вопрос. Вы пишете код, зная, что 'A' равно 65. Весь смысл упражнения состоит в том, чтобы напечатать значение от 'A' до 'Z' в вашей системе, не зная, какое значение они имеют.

Теперь, чтобы получить целочисленное значение для символа c, вы можете сделать: static_cast<int>(c). Я полагаю, это то, что вы спрашиваете.

Я не написал никакого кода, потому что вам должно быть веселее.

Вопрос к экспертам: В Си я знаю, что 'a' ... 'z' не обязательно должен иметь непрерывные значения (то же самое для 'A' ... 'Z'). То же самое верно для C ++? Я бы так подумал, но тогда кажется маловероятным, что книга Страуструпа предполагает это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...