Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
knrc (1).pdf
Скачиваний:
16
Добавлен:
12.02.2016
Размер:
926 Кб
Скачать
☆

50 РОЗДIЛ 2. ТИПИ, ОПЕРАТОРИ ТА ВИРАЗИ

{

next = next * 1103515245 + 12345;

return (unsigned int)(next/65536) % 32768;

}

/* srand: встановлює зерно для rand() */ void srand(unsigned int seed)

{

next = seed;

}

Вправа 2-3. Напишiть функцiю htoi(s), яка би обертала ланцюжок з шiстнадцяткових цифр (включаючи можливий 0x або 0X) на вiдповiдне цiле значення (int). Дозволеними цифрами є 0 до 9, a до f або A до F.

2.8Оператори приросту та спаду

C забезпечує двома незвичними операторами приросту та спаду змiнних. Оператор приросту ++ додає 1 до свого операнду, тодi як –, навпаки, вiднiмає 1. Ми вже не раз користувалися ++ для збiльшення значення змiнних, як, наприклад, у

if (c == ’\n’) ++nl;

Незвична сторона полягає в тому, що як ++, так i – можуть використовуватись як префiкснi оператори (перед змiнною, наприклад ++n), так i постфiкснi (пiсля змiнної: n++). В обох випадках, як наслiдок — збiльшується значення n. Але вираз ++n збiльшує n до того, як це значення буде використане, тодi як n++ збiльшує n пiсля того, як було використане початкове значення. Це означає, що в контекстi, де дiйсно використовується значення, а не тiльки самий ефект, ++n i n++ — вiдмiннi. Якщо n дорiвнює 5, тодi

x = n++;

присвоїть x значення 5, зате у випадку

x = ++n;

x дорiвнюватиме вже 6. В обох випадках, n стане рiвним 6. Оператори приросту та спаду можуть використовуватись тiльки зi змiнними; вирази на кшталт (i+j)++ забороненi.

У контекстi, коли значення не потрiбне, а тiльки ефект приросту, як наприклад

2.8. ОПЕРАТОРИ ПРИРОСТУ ТА СПАДУ

51

if (c == ’\n’) nl++;

префiкс i постфiкс тотожнi. Але iснують випадки, коли треба звернутися тiльки до одного, або тiльки до iншого. Наприклад, розглянемо функцiю squeeze(s,c), яка вилучає всi знайденi знаки c з ланцюжка s.

/* squeeze: вилучає всi c з s */ void squeeze(char s[], int c)

{

int i, j;

for (i = j = 0; s[i] != ’\0’; i++) if (s[i] != c)

s[j++] = s[i]; s[j] = ’\0’;

}

Кожного разу, як знайдено не-c, його скопiйовано до поточної позицiї j, i тiльки пiсля цього j збiльшено, щоб бути готовим до наступного знака. Це точний еквiвалент

if (s[i] != c) { s[j] = s[i]; j++;

}

Iнший приклад подiбної конструкцiї походить з функцiї getline, яку ми написали в Роздiлi 1, де ми можемо замiнити

if (c == ’\n’) { s[i] = c; ++i;

}

на компактнiше

if (c == ’\n’) s[i++] = c;

52

РОЗДIЛ 2. ТИПИ, ОПЕРАТОРИ ТА ВИРАЗИ

В якостi третього прикладу, розглянемо стандартну функцiю strcat(s,t), яка зчеплює ланцюжок t iз кiнцем ланцюжка s. strcat припускає, що s має досить мiсця, щоб зберегти комбiнацiю обох ланцюжкiв. Так, як ми це написали, strcat не повертає жодного значення; версiя зi стандартної бiблiотеки повертає покажчик на отриманий ланцюжок.

/* strcat: зчеплює t iз кiнцем s; s має бути досить великим */ void strcat(char s[], char t[])

{

int i, j;

i = j

= 0;

 

while (s[i] != ’\0’)

/* знаходить кiнець s */

i++;

 

while ((s[i++] = t[j++]) != ’\0’)

/* копiює t */

;

 

 

}

Одночасно з копiюванням t до s до них застосовано постфiксний ++, щоб упевнитись, що вони в позицiї для наступного проходження через цикл.

Вправа 2-4. Напишiть альтернативну версiю squeeze(s1,s2), яка би вилучала кожний знак iз s1, який збiгається iз будь-яким знаком s2.

Вправа 2-5. Напишiть функцiю any(s1, s2), яка повертає перше положення в ланцюжку s1 одного iз знакiв ланцюжка s2, або -1, якщо жодного не знайдено. (Функцiя strpbrk зi стандартної бiблiотеки здiйснює те саме, тiльки повертає покажчик на положення.)

2.9Розряднi оператори

Мова C забезпечує шiстьма операторами для обробки бiтiв; їх можна застосовувати лише з цiлочисельними операндами, тобто char, short, int i long, як зi знаком, так i беззнаковими. & розрядний I | розрядний включний АБО ˆ розрядний виключний АБО << лiве змiщення >> праве змiщення ˜ доповнення (унарний оператор) Розрядний I (оператор &) часто використовується для того, щоб приховати набiр бiтiв, наприклад

n = n & 0177;

обнулює всi бiти n крiм молодших 7-и.

Розрядний АБО (оператор |) використовується для ввiмкнення бiтiв:

x = x | SET_ON;

2.9. РОЗРЯДНI ОПЕРАТОРИ

53

встановлює в одиницю всi бiти x, що дорiвнюють одному в SET_ON. Розрядний виключний АБО (оператор ˆ) встановлює в одиницю кожну позицiю, де операнди мають вiдмiннi бiти, i в нуль там де вони збiгаються.

Не слiд плутати розряднi оператори & та | з логiчними операторами && та ||, в яких iдеться про злiва направо оцiнку iстинного значення. Наприклад, якщо x дорiвнює 1 а y дорiвнює 2, тодi x & y оцiнюється як нуль, зате x && y — як один.

Оператори змiщення << й >> здiйснюють лiве та праве змiщення лiвого операнда на кiлькiсть бiтiв, вказаних правим операндом; останнiй має бути додатнiм числом. Таким чином, x << 2 змiщує значення x на два положення, заповнюючи вакантнi бiти нулями; це рiвнозначно множенню на 4. Праве змiщення беззнакової величини завжди заповнюватиме звiльненi бiти нулями. Праве змiщення величини зi знаком заповнюватиме бiтами знака ( арифметичне змiщення ) на деяких машинах i 0-бiтами ( логiчне змiщення ) на iнших.

Унарний оператор ˜ видає протилежне значення вказаного цiлого; тобто, вiн перетворює кожний 1-бiт на 0-бiт, i навпаки. Наприклад

x = x & ~077

встановлює останнi шiсть бiтiв x у нуль. Зауважте, що x & ˜077 не залежить вiд довжини слова , тому йому надається перевага над, скажiмо, x & 0177700, яке припускає, що x — 16-бiтна величина. Портабельна форма не забирає додаткових ресурсiв оскiльки ˜077 — це сталий вираз, який оцiнюється пiд час компiляцiї.

Як iлюстрацiя деяких розрядних операторiв розглянемо функцiю getbits(x,p,n), яка повертає (вирiвняне з правого боку) n-бiтне поле x, починаючи з положення p. Ми припустимо, що бiтове положення 0 знаходиться з крайнього правого боку i, що n iз p — це чиннi додатковi значення. Так, наприклад, getbits(x,4,3) повертає три бiти, що знаходяться у 4-iй, 3-iй i 2-iй позицiї, вирiвнянi справа.

/* getbits: добуває n бiтiв, починаючи з положення p */ unsigned getbits(unsigned x, int p, int n)

{

return (x >> (p+1-n)) & ~(~0 << n);

}

Вираз x >> (p+1-n) перемiщує потрiбне нам поле на правий край слова. ˜0 складається з одних 1-бiтiв; змiщення його лiворуч на n позицiй за допомогою ˜0<<n розмiстить нулi в n бiтiв з правого боку; додання до цього ˜ створює маску з одиниць для n бiтiв справа.

Вправа 2-6. Напишiть функцiю setbits(x,p,n,y), яка би повертала x, в якому n бiтiв, починаючи з положення p, дорiвнюють крайнiм правим n бiтам y, залишаючи решту бiтiв незмiнними.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]