суббота, 14 января 2012 г.

Возможности С++. Интересные фишки. Начало

Решил написать этот пост, чтобы получше разобраться и помочь разобраться другим с возможностями С++, которых немало.

  1. Тернарный условный оператор.
       Мне очень приглянулась эта вещь, хотя на практике я её пока что не использую. Выглядит это следующим образом:
    (условие) ? (выражение, если условие верно) : (выражение , если условие ложно)
    return (a<b) ? a : b;
    Этот фрагмент кода проверит на истинность значение выражение (a<b) и в случае его истинности возвратит a, иначе - b.

    Таким образом функция минимума из двух чисел выглядит так:
    int minimum ( int a, int b)
    {
        return (a<b) ? a : b;
    }
    По-моему такой код выглядит очень изящно и эстетично.

    Вот ещё пример функции с одним тернарным условным оператором:
    int fact_ter ( int n )
    {
        return n==1 ?  1 : n*fact_ter(n-1);
    }
    Эта функция считает фрактал числа n.
  2. Макросы в С++
       Их много, но особенно сильно мне приглянулся макрос #define. Этот макрос имеет следующую структуру:
    #define [заменяемая строка] [строка замены
    #define [заменяемая строка](аргументы) [строка замены]
    Эта функция работает предельно просто - заменяемую строку ( указанную первой после макроса ) она меняет на строку замены.
    #include <iostream>
    using namespace std;
    #define PI 3.14159
    int main()
    {
       cout << PI;
       return 0;
    }
    Вывод: 3.14159
    Видно, что макрос просто заменил строку PI на 3.14159.

    Также, макрос #define может работать с переменными, сопровождающими заменяемую строку. Данный набор переменных нужно указывать строго после заменяемой строк, причем между набором переменных и строкой не должно быть никаких символов (даже пробела). Таким образом такой код воспримется компилятором так, как нужно:
    #define neg(a) -a 
    А такой нет:
    #define neg (a) -a 

    Приведу пример работу с таким типом макроса #define:
    #include <iostream>
    using namespace std;
    #define sum(a, b) a+b
    int main()
    {
       int a=1, b=2;
       cout << sum(a, b);
       return 0;
    }
    
    Вывод: 3

    В данном примере #define заменяет строку sum(a, b) на a+b, и в итоге на выходе мы получаем 3.

    Ещё одна интересная возможность #define - возможность заключать имена переменных в кавычки. Это осуществляется при помощи знака #(октоторп) который ставится перед нужной нам переменной. Рассмотрим следующий код:
    #include <iostream>
    using namespace std;
    #define pv(a) cout << #a
    int main()
    {
       int a, b;
       pv(b);
       return 0;
    }
    
    Вывод: b
    Т.е. после замены строки pv(b); она стала выглядеть как cout << "b";

    Как человек, немного увлекающийся спортивным программированием,  иногда требуется фиксить баги, а т.к. увлекаюсь немного, то пользоваться Debug-ом я неприучен, а приучен выводить различные переменные в различных частях кода. Написав небольшой макрос можно заметно упростить эту операцию:
    #include <iostream>
    using namespace std;
    #define pv(a) cout << #a "=" << a << ' ';
    int main()
    {
       int a=1, b=2;
       pv(a);
       pv(b);
       return 0;
    }
    
    Вывод: a=1 b=2
    Разберемся в работе этого кода:
    1. Макрос заменяется строчки pv(a); и pv(b); на соответствующие им:
      cout << "a" "=" << a;
      cout << "b" "=" << b;
      (т.к. переменная, перед которой стоит # отдельно заключается в кавычки)
    2. Компилятор С++ одинаково воспринимает строки разделенные пробелами
      ("a" "b") как одну строку ("ab"), поэтому наша запись модифицируется в запись следующего рода:
      cout << "a=" << a;
      cout << "b=" << b;
    3. Profit.

    Наконец хочу сказать, что с макросом #define нужно быть предельно аккуратным, т.к. в этом макросе вы пишете не функцию, а лишь строчку, на которую вы замените некоторый текст. Следующий код поможет лучше выразить мою мысль:
    #include <iostream>
    using namespace std;
    #define two(a) a+a
    int main()
    {
       int a=1, b=2;
       cout << two(a)*two(b);
       return 0;
    }
    
    Вывод: 5
    Логичнее было бы ожидать вывод - 8 (2*4), но давайте подробнее разберемся в том, что происходит с этим кодом:
    1. Макрос заменяет cout на следующую строку:
      cout << a+a*b+b;
    2. Значение выражения считается с учетом приоритета операций, т.е. a+(a*b)+b. Значение этого выражение как раз равно 5

    С макросом #define я на этом закончу. В процессе написания этого пункта я сам запутался с ним, поэтому советую как можно чаще использовать его ( я лично собираюсь использовать его только для отладки ).

    P.S. Код, который ввел меня в ступор:
    #include <iostream>
    using namespace std;
    #define two(a) a+a;
    int main()
    {
       int a=1, b=2;
       cout << two(a)+two(b);
       return 0;
    }
    
    Вывод: 2

Комментариев нет:

Отправить комментарий