Главная страница
Навигация по странице:

  • Проект 7.1 Создание функций поразрядного циклического сдвига 336

  • Проект 7.1 Создание функций поразрядного циклического сдвига 338

  • Использование -оператора // для предотвращения // деления на нуль.

  • ВАЖНО! 7.10. Оператор “запятая”

  • ВАЖНО! 7.11. Составные операторы присваивания

  • ВАЖНО! 7.12. Использование ключевого слова sizeof

  • Тест для самоконтроля по модулю 7

  • Справочник по C, Полный справочник по C


    Скачать 393.9 Kb.
    НазваниеСправочник по C, Полный справочник по C
    Анкорaboba
    Дата09.07.2021
    Размер393.9 Kb.
    Формат файлаpdf
    Имя файлаcrukovodstvodlyanachinayushchih.pdf
    ТипСправочник
    #223848
    страница5 из 5
    1   2   3   4   5

    3.
    Определите функцию rrotate(), предназначенную для выполнения ци- клического сдвига вправо.
    // Функция циклического сдвига вправо байта на n разря- дов. unsigned char rrotate(unsigned char val, int n)
    { unsigned int t; t = val;
    // Сначала сдвигаем значение на 8 бит влево. t = t << 8;


    С++: руководство для начинающих
    335
    Еще о типах данных и операторах
    7
    for(int i=0; i < n; i++) { t = t >> 1; // Сдвиг вправо на 1 разряд.
    /* После сдвига бита вправо на 1 разряд он становит- ся седьмым битом целочисленного значения t. Если 7-й бит равен единице, то нужно установить крайний слева бит. */ if(t & 128) t = t | 32768; // Устанавливаем “1” с левого кон- ца.
    }
    /* Наконец, помещаем результат назад в младшие 8 бит значения t. */ t = t >> 8; return t;
    }
    Циклический сдвиг вправо немного сложнее циклического сдвига влево, поскольку значение, переданное в параметре val, должно быть первона- чально сдвинуто во второй байт значения t, чтобы “не упустить” биты, сдвигаемые вправо. После завершения циклического сдвига значение не- обходимо сдвинуть назад в младший байт значения t, подготовив его тем самым для возврата из функции. Поскольку сдвигаемый вправо бит стано- вится седьмым битом, то для проверки его значения используется следую- щая инструкция.
    if(t & 128)
    В десятичном значении 128 установлен только седьмой бит. Если анализи- руемый бит оказывается равным единице, то в значении t устанавливается
    15-й бит путем применения к значению t операции “ИЛИ” с числом 32768.
    В результате выполнения этой операции 15-й бит значения t устанавлива- ется равным 1, а все остальные не меняются.
    4.
    Приведем полный текст программы, которая демонстрирует использование функций rrotate() и lrotate(). Для отображения результатов выполне- ния каждого циклического сдвига используется функция show_binary().
    Проект
    7.1
    Создание функций поразрядного циклического сдвига

    336
    Модуль 7. Еще о типах данных и операторах
    /*
    Проект 7.1.
    Функции циклического сдвига вправо и влево для байтовых значений.
    */
    #include using namespace std; unsigned char rrotate(unsigned char val, int n); unsigned char lrotate(unsigned char val, int n); void show_binary(unsigned int u); int main()
    { char ch = 'T'; cout << "Исходное значение в двоичном коде:\n"; show_binary(ch); cout << "Результат 8-кратного циклического сдвига впра- во:\n"; for(int i=0; i < 8; i++) { ch = rrotate(ch, 1); show_binary(ch);
    } cout << "Результат 8-кратного циклического сдвига вле- во:\n"; for(int i=0; i < 8; i++) { ch = lrotate(ch, 1); show_binary(ch);
    } return 0;
    }
    // Функция циклического сдвига влево байта на n разрядов.

    С++: руководство для начинающих
    337
    Еще о типах данных и операторах
    7
    unsigned char lrotate(unsigned char val, int n)
    { unsigned int t; t = val; for(int i=0; i < n; i++) { t = t << 1;
    /* Если выдвигаемый бит (8-й разряд значения t) содержит единицу, то устанавливаем младший бит. */ if(t & 256) t = t | 1; // Устанавливаем 1 на правом конце.
    } return t; // Возвращаем младшие 8 бит.
    }
    // Функция циклического сдвига вправо байта на n разрядов. unsigned char rrotate(unsigned char val, int n)
    { unsigned int t; t = val;
    // Сначала сдвигаем значение на 8 бит влево. t = t << 8; for(int i=0; i < n; i++) { t = t >> 1; // Сдвиг вправо на 1 разряд.
    /* После сдвига бита вправо на 1 разряд он становится седьмым битом целочисленного значения t.
    Если 7-й бит равен единице, то нужно установить крайний слева бит. */ if(t & 128) t = t | 32768; // Устанавливаем “1” с левого конца.
    }
    Проект
    7.1
    Создание функций поразрядного циклического сдвига

    338
    Модуль 7. Еще о типах данных и операторах
    /* Наконец, помещаем результат назад в младшие 8 бит значения t. */ t = t >> 8; return t;
    }
    // Отображаем биты, которые составляют байт. void show_binary(unsigned int u)
    { int t; for(t=128; t>0; t = t/2) if(u & t) cout << "1 "; else cout << "0 "; cout << "\n";
    }
    5.
    Вот как выглядят результаты выполнения этой программы.
    Исходное значение в двоичном коде:
    0 1 0 1 0 1 0 0
    Результат 8-кратного циклического сдвига вправо:
    0 0 1 0 1 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 0 0 0 1 0 1 1 0 1 0 0 0 1 0 0 1 0 1 0 0 0 1 1 0 1 0 1 0 0 0 0 1 0 1 0 1 0 0
    Результат 8-кратного циклического сдвига влево:
    1 0 1 0 1 0 0 0 0 1 0 1 0 0 0 1 1 0 1 0 0 0 1 0 0 1 0 0 0 1 0 1 1 0 0 0 1 0 1 0 0 0 0 1 0 1 0 1 0 0 1 0 1 0 1 0 0 1 0 1 0 1 0 0

    С++: руководство для начинающих
    339
    Еще о типах данных и операторах
    7
    ВАЖНО!
    7.9.
    Оператор “знак вопроса”
    Одним из самых замечательных операторов C++ является оператор “?”. Опе- ратор “?” можно использовать в качестве замены if-else-инструкций, употре- бляемых в следующем общем формате.
    if (
    условие)
    переменная = выражение1;
    else
    переменная = выражение2;
    Здесь значение, присваиваемое переменной, зависит от результата вычисления элемента условие, управляющего инструкцией if.
    Оператор “?” называется тернарным, поскольку он работает с тремя операн- дами. Вот его общий формат записи:
    Выражение1 ? Выражение2 : Выражение3;
    Все элементы здесь являются выражениями. Обратите внимание на использова- ние и расположение двоеточия.
    Значение ?-выражения определяется следующим образом. Вычисляется Вы-
    ражение1. Если оно оказывается истинным, вычисляется Выражение2, и ре- зультат его вычисления становится значением всего ?-выражения. Если резуль- тат вычисления элемента Выражение1 оказывается ложным, значением всего
    ?
    -выражения становится результат вычисления элемента Выражение3. Рассмо- трим следующий пример.
    absval = val < 0 ? –val : val; // Получение абсолютного
    // значения переменной val.
    Здесь переменной absval будет присвоено значение val, если значение пере- менной val больше или равно нулю. Если значение val отрицательно, пере- менной absval будет присвоен результат отрицания этого значения, т.е. будет получено положительное значение. Аналогичный код, но с использованием if- else
    -инструкции, выглядел бы так.
    if(val < 0) absval = –val;
    else absval = val;
    А вот еще один пример практического применения оператора ?. Следующая программа делит два числа, но не допускает деления на нуль.
    /* Эта программа использует оператор “?” для предотвращения деления на нуль. */

    340
    Модуль 7. Еще о типах данных и операторах
    #include
    using namespace std;
    int div_zero();
    int main()
    {
    int i, j, result;
    cout << "Введите делимое и делитель: ";
    cin >> i >> j;
    // Эта инструкция не допустит возникновения ошибки
    // деления на нуль.
    result = j ? i/j : div_zero(); //
    Использование ?-оператора
    //
    для предотвращения
    //
    деления на нуль. cout << "Результат: " << result;
    return 0;
    }
    int div_zero()
    {
    cout << "Нельзя делить на нуль.\n";
    return 0;
    }
    Здесь, если значение переменной j не равно нулю, выполняется деление значе- ния переменной i на значение переменной j, а результат присваивается пере- менной result. В противном случае вызывается обработчик ошибки деления на нуль div_zero(), и переменной result присваивается нулевое значение.
    ВАЖНО!
    7.10.
    Оператор “запятая”
    Не менее интересным, чем описанные выше операторы, является такой оператор
    C++, как “запятая”. Вы уже видели несколько примеров его использования в цикле for
    , где с его помощью была организована инициализация сразу нескольких пере- менных. Но оператор “запятая” также может составлять часть любого выражения.

    С++: руководство для начинающих
    341
    Еще о типах данных и операторах
    7
    Его назначение в этом случае — связать определенным образом несколько выра- жений. Значение списка выражений, разделенных запятыми, определяется в этом случае значением крайнего справа выражения. Значения других выражений отбра- сываются. Следовательно, значение выражения справа становится значением всего выражения-списка. Например, при выполнении этой инструкции var = (count=19, incr=10, count+1);
    переменной count сначала присваивается число 19, переменной incr — чис- ло 10, а затем к значению переменной count прибавляется единица, после чего переменной var присваивается значение крайнего справа выражения, т.е. count+1
    , которое равно 20. Круглые скобки здесь обязательны, поскольку опе- ратор “запятая” имеет более низкий приоритет, чем оператор присваивания.
    Чтобы понять назначение оператора “запятая”, попробуем выполнить следу- ющую программу.
    #include
    using namespace std;
    int main()
    {
    int i, j;
    j = 10;
    i = (j++, j+100, 999+j); // Оператор “запятая” означает
    // “сделать это, и то, и дру- гое”.
    cout << i;
    return 0;
    }
    Эта программа выводит на экран число 1010. И вот почему: сначала перемен- ной j присваивается число 10, затем переменная j инкрементируется до 11. По- сле этого вычисляется выражение j+100, которое нигде не применяется. Нако- нец, выполняется сложение значения переменной j (оно по-прежнему равно 11) с числом 999, что в результате дает число 1010.
    По сути, назначение оператора “запятая” — обеспечить выполнение задан- ной последовательности операций. Если эта последовательность используется в правой части инструкции присваивания, то переменной, указанной в ее левой

    342
    Модуль 7. Еще о типах данных и операторах части, присваивается значение последнего выражения из списка выражений, раз- деленных запятыми. Оператор “запятая” по его функциональной нагрузке можно сравнить со словом “и”, используемым в фразе: “сделай это, и то, и другое...”.
    Вопросы для текущего контроля
    1.
    Какое значение будет иметь переменная x после вычисления этого выра- жения?
    x = 10 > 11 ? 1 : 0;
    2.
    Оператор “?” называется тернарным, поскольку он работает с ______ операндами.
    3.
    Каково назначение оператора “запятая”?*
    Несколько присваиваний “в одном”
    Язык C++ позволяет применить очень удобный метод одновременного присва- ивания многим переменным одного и того же значения. Речь идет об объединении сразу нескольких присваиваний в одной инструкции. Например, при выполнении этой инструкции переменным count, incr и index будет присвоено число 10.
    count = incr = index = 10;
    Этот формат присвоения нескольким переменным общего значения можно часто встретить в профессионально написанных программах.
    ВАЖНО!_7.11.__Составные_операторы_присваивания'>ВАЖНО!
    7.11.
    Составные операторы
    присваивания
    В C++ предусмотрены специальные составные операторы присваивания, в которых объединено присваивание с еще одной операцией. Начнем с примера и рассмотрим следующую инструкцию.
    x = x + 10;
    1. Переменная x
    после вычисления этого выражения получит значение 0.
    2. Оператор “?” называется тернарным, поскольку он работает с тремя операндами.
    3. Оператор “запятая” обеспечивает выполнение заданной последовательности операций.

    С++: руководство для начинающих
    343
    Еще о типах данных и операторах
    7
    Используя составной оператор присваивания, ее можно переписать в таком виде.
    x += 10;
    Пара операторов += служит указанием компилятору присвоить переменной x
    сумму текущего значения переменной x и числа 10. Составные версии опера- торов присваивания существуют для всех бинарных операторов (т.е. для всех операторов, которые работают с двумя операндами). Таким образом, при таком общем формате бинарных операторов присваивания
    переменная = переменная op выражение;
    общая форма записи их составных версий выглядит так:
    переменная op = выражение;
    Здесь элемент op означает конкретный арифметический или логический опера- тор, объединяемый с оператором присваивания.
    А вот еще один пример. Инструкция x = x - 100;
    аналогична такой:
    x -= 100;
    Обе эти инструкции присваивают переменной x ее прежнее значение, уменьшен- ное на 100.
    Эти примеры служат иллюстрацией того, что составные операторы присва- ивания упрощают программирование определенных инструкций присваивания.
    Кроме того, они позволяют компилятору сгенерировать более эффективный код.
    Составные операторы присваивания можно очень часто встретить в професси- онально написанных C++-программах, поэтому каждый C++-программист дол- жен быть с ними на “ты” .
    ВАЖНО!
    7.12.
    Использование ключевого
    слова sizeof
    Иногда полезно знать размер (в байтах) одного из типов данных. Поскольку размеры встроенных C++-типов данных в разных вычислительных средах могут быть различными, знать заранее размер переменной во всех ситуациях не пред- ставляется возможным. Для решения этой проблемы в C++ включен оператор sizeof
    (действующий во время компиляции программы), который использует- ся в двух следующих форматах.
    sizeof (
    type)
    sizeof
    имя_переменной

    344
    Модуль 7. Еще о типах данных и операторах
    Первая версия возвращает размер заданного типа данных, а вторая — размер заданной переменной. Если вам нужно узнать размер некоторого типа данных
    (например, int), заключите название этого типа в круглые скобки. Если же вас интересует размер области памяти, занимаемой конкретной переменной, можно обойтись без круглых скобок, хотя при желании их можно использовать.
    Чтобы понять, как работает оператор sizeof, испытайте следующую корот- кую программу. Для многих 32-разрядных сред она должна отобразить значения
    1, 4, 4 и 8.
    // Демонстрация использования оператора sizeof.
    #include
    using namespace std;
    int main()
    {
    char ch;
    int i;
    cout << sizeof ch << ' '; // размер типа char cout << sizeof i << ' '; // размер типа int cout << sizeof (float) << ' '; // размер типа float cout << sizeof (double) << ' '; // размер типа double return 0;
    }
    Оператор sizeof можно применить к любому типу данных. Например, в слу- чае применения к массиву он возвращает количество байтов, занимаемых масси- вом. Рассмотрим следующий фрагмент кода.
    int nums[4];
    cout << sizeof nums; // Будет выведено число 16.
    Для 4-байтных значений типа int при выполнении этого фрагмента кода на экране отобразится число 16 (которое получается в результате умножения 4 байт на 4 элемента массива).
    Как упоминалось выше, оператор sizeof действует во время компиляции программы. Вся информация, необходимая для вычисления размера указанной переменной или заданного типа данных, известна уже во время компиляции.
    Оператор sizeof главным образом используется при написании кода, который зависит от размера C++-типов данных. Помните: поскольку размеры типов дан-

    С++: руководство для начинающих
    345
    Еще о типах данных и операторах
    7
    ных в C++ определяются конкретной реализацией, не стоит полагаться на разме- ры типов, определенные в реализации, в которой вы работаете в данный момент.
    Вопросы для текущего контроля
    1.
    Покажите, как присвоить переменным t1, t2 и t3 значение 10, используя только одну инструкцию присваивания.
    2.
    Как по-другому можно переписать эту инструкцию?
    x = x + 100;
    3.
    Оператор sizeof возвращает размер заданной переменной или типа в
    _______.*
    Сводная таблица приоритетов C++-
    операторов
    В табл. 7.2 показан приоритет выполнения всех C++-операторов (от выс- шего до самого низкого). Большинство операторов ассоциированы слева на- право. Но унарные операторы, операторы присваивания и оператор “?” ассо- циированы справа налево. Обратите внимание на то, что эта таблица включает несколько операторов, которые мы пока не использовали в наших примерах, поскольку они относятся к объектно-ориентированному программированию
    (и описаны ниже).
    1. t1 = t2 = t3 = 10;
    2. x += 100;
    3. Оператор sizeof возвращает размер заданной переменной или типа в байтах.

    346
    Модуль 7. Еще о типах данных и операторах
    Таблица 7.2. Приоритет C++-операторов
    Наивысший
    () [] –> :: .
    ! ++ –– – * & sizeof new delete typeid операторы приведения типа
    .* –>*
    * / %
    + –
    << >>
    < <= > >=
    == !=
    &
    ^
    |
    &&
    ||
    ?:
    = += –= *= /= %= >>= <<= &= ^= |=
    Низший
    ,
    Тест для самоконтроля по модулю 7
    1.
    Покажите, как объявить int-переменную с именем test, которую невоз- можно изменить в программе. Присвойте ей начальное значение 100.
    2.
    Спецификатор volatile сообщает компилятору о том, что значение пере- менной может быть изменено за пределами программы. Так ли это?
    3. Какой спецификатор применяется в одном из файлов многофайловой про- граммы, чтобы сообщить об использовании глобальной переменной, объ- явленной в другом файле?
    4. Каково наиглавнейшее свойство статической локальной переменной?
    5. Напишите программу, содержащую функцию с именем counter(), кото- рая просто подсчитывает количество вызовов. Позаботьтесь о том, чтобы функция возвращала текущее значение счетчика вызовов.
    6. Дан следующий фрагмент кода.
    int myfunc()
    {
    int x;
    int y;
    int z;

    С++: руководство для начинающих
    347
    Еще о типах данных и операторах
    7
    z = 10;
    y = 0;
    for(x=z; x <15; x++)
    y += x;
    return y;
    }
    Какую переменную следовало бы объявить с использованием специфика- тора register с точки зрения получения наибольшей эффективности?
    7. Чем оператор “&” отличается от оператора “&&”?
    8. Какие действия выполняет эта инструкция?
    x *= 10;
    9. Используя функции rrotate() и lrotate() из проекта 7.1, можно за- кодировать и декодировать строку. Чтобы закодировать строку, выполните циклический сдвиг влево каждого символа на некоторое количество раз- рядов, которое задается ключом. Чтобы декодировать строку, выполните циклический сдвиг вправо каждого символа на то же самое количество раз- рядов. Используйте ключ, который состоит из некоторой строки символов.
    Существует множество способов для вычисления количества сдвигов по ключу. Проявите свои способности к творчеству. Решение, представленное в разделе ответов, является лишь одним из многих.
    10. Самостоятельно расширьте возможности функции show_binary(), что- бы она отображала все биты значения типа unsigned int, а не только первые восемь.
    Ответы на эти вопросы можно найти на Web-странице данной книги по адресу: http://www.osborne.com.
    На заметку
    1   2   3   4   5


    написать администратору сайта