Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Visual_Studio_2010

.pdf
Скачиваний:
109
Добавлен:
03.03.2016
Размер:
5.94 Mб
Скачать

Рис. 15.5. Пример интерактивного поиска служебных слов

Задание5

1.В программе используйте прототипы вспомогательных функций.

2.В качестве служебных слов задайте основные типы данных и их производных языка программирования С.

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

4.Функцию анализа вводимых с клавиатуры слов напишите без дополнительного указателя на структуру типа key.

5.В программе предусмотрите копирование консольного содержания в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

Пример 6. Написать программу сравнения введенного целого числа с имеющимися целыми случайными числами одномерного массива на основе структурного типа данных и двоичного поиска (метода половинного деления) для упорядоченного массива.

Программный код решения примера

#include <stdio.h> #include <conio.h>

#include <stdlib.h> #include <time.h>

#include <locale.h>

#define MAX 1000

261

// Функция ввода числа как строки с клавиатуры void getLine(int num[], int m) {

int i, j, k; time_t tic;

srand((unsigned) time(&tic));

for (i = 0; i < m; ++i)

num[i] = (int)m*rand()/RAND_MAX;

printf("\n\t The initial array of numeric data:\n"); for (i = 0; i < m; ++i)

printf(" %3d", num[i]); puts(" ");

// Сортировка массива по возрастанию for (i = 1; i < m; ++i) {

for (j = 0; j < m-1; ++j) { if (num[j] > num[j+1]) {

k = num[j]; num[j] = num[j+1]; num[j+1] = k;

}

}

}

printf("\t Assorted array of numerical data:\n"); printf(" ");

for (i = 0; i < m; ++i) printf(" %3d", num[i]); puts(" ");

}

// Создание структуры глобального типа struct numb {

int index; int numbers;

} tab, *bam;// указатель на структуру

//Вспомогательная функция

//с указателем на структуру numb

struct numb *PTR_ANALYSE(int x, int mass[], int n) { int min = 0;

int max = n - 1; int mid;

struct numb *PTR = &tab;

//Бинарный поиск

while (min <= max) {

mid = (max + min)/2; // переход в середину массива if (x == mass[mid]) {

PTR->numbers = mass[mid]; PTR->index = mid;

return (PTR); // возвращение указателя на структуру

}

262

else if (x < mass[mid]) max = mid - 1;

else

min = mid + 1; } // End while

return NULL; // число не найдено

} // End function

// Главная функция int main (void) { int c, x;

int N, arr[MAX];

// Русские шрифты setlocale(LC_ALL, ".1251");

printf("\n УГАДЫВАНИЕ ЧИСЛА В ЧИСЛОВОМ ОТСОРТИРОВАННОМ МАССИВЕ\n");

// Латинские шрифты setlocale(LC_ALL, "English");

printf("\n The end of the session: press Ctrl+Z after pressing Enter\n");

printf("\n\t Enter the dimension of the array of more than 3: ");

scanf_s("%d", &N); _flushall();

getLine(arr, N); puts(" ");

do {

printf("\t Enter an integer: "); scanf_s("%d", &x);

_flushall(); printf(" ");

bam = PTR_ANALYSE(x, arr, N);

if (bam != NULL) {

printf("\t The number is found: %d\n ", bam->numbers); printf("\t The index number of assorted array: %d\n", bam- >index+1);

printf("\n\t Press Enter to continue or Ctrl+Z to quit: ");

}

else

printf("\t The number is not found.\n Press Enter to continue or

Ctrl+Z to quit: ");

} while ((c = getchar()) != EOF);

printf("\n Press any key: "); _getch();

return 0;

}

263

При двоичном алгоритме поиска после каждого сравнения исключается половина элементов массива, в котором производится поиск [5]. Алгоритм находит средний элемент массива и сравнивает его с ключом поиска (в программе переменная х). Если они равны, ключ считается найденным и возвращается индекс этого элемента. Если они не равны, задача упрощается до поиска в одной половине массива.

Если ключ поиска меньше среднего элемента, поиск производится в первой половине массива, в противном случае – во второй. Если ключ в указанном подмассиве не найден, алгоритм повторяется для четверти массива. Поиск продолжается до тех пор, пока ключ не окажется равен среднему элементу подмассива или пока подмассив не будет состоять из одного элемента, не равного ключу (это означает, что ключ поиска не найден).

Возможный результат выполнения программы приведен на рис.15.6.

Рис. 15.6. Результат двоичного поиска по совпадению ключей

Задание6

1.Перед началом бинарного поиска по заданному ключу отсортируйте массив случайных чисел по убыванию.

2.Организуйте случайный массив из 5Х целых чисел. Интервал формирования случайных чисел примите от Х до 5Х, где Х – номер компьютера, на котором выполняется лабораторная работа. Выведите отсортированный массив на консоль. Введите число (ключ поиска), соответствующее последнему элементу массива. Подсчитайте количество итераций (количество сравнений в двоичном поиске), которое потребуется для поиска заданного ключа.

3.Заданную программу дополните поиском по заданному ключу последовательным перебором. Определите количество сравнений, которое потребуется при бинарном поиске и с помощью последовательного перебора.

264

Контрольные вопросы

1.Какие операции над структурами разрешены в языке С?

2.Как осуществляется передача частей структуры в качестве аргументов функции?

3.Как осуществляется возврат частей структуры из функции?

4.Как реализуется возвращение измененной структуры из функции?

5.Как осуществляется обращение к полям структуры, переданной функции в виде аргумента?

6.Допустимо ли объявление переменных глобальной структуры и переменных структуры функции одними и теми же идентификаторами?

7.Как распределить структуру в динамической памяти?

8.Как осуществляется возврат данных структурного типа из пользовательской функции?

БИБЛИОГРАФИЧЕСКИЙ СПИСОК

1.Керниган Б. У. Язык программирования С : пер. с англ./Б. У. Керниган, Д. М. Ритчи. – 2-е изд. – М. : Вильямс, 2007. – 304 с.

2.Шилдт Г. Полный справочник по С : пер. с англ./Г. Шилдт. – 4-е изд. –

М. : Вильямс, 2007. – 704 с.

3.Прата С. Язык программирования С. Лекции и упражнения : пер. с англ. / С. Прата. – 5-е изд. – М. : Вильямс, 2006. – 960 с.

4.Пантелеев А. В. Теория функций комплексного переменного и операционное исчисление в примерах и задачах : учеб. пособие /А. В. Пантелеев, А. С. Якимов. – М. : Высш. шк., 2001. – 445 с.

5.Дейтл Х. М. Как программировать на С : пер. с англ./Х. М. Дейтл, П. Дж. Дейтл. – 4-е изд. – М. : Бином-Пресс, 2006. – 912 с.

265

Тема 16

ОПЕРАЦИИ С РАЗРЯДАМИ (БИТАМИ) В ЯЗЫКЕ С

Рассматриваются операторы и операции по управлению отдельными разрядами (битами) переменных, а также операции с битовыми полями.

ТЕОРЕТИЧЕСКАЯ ЧАСТЬ

1.1. Базовые системы счисления

В языке программирования С предусмотрено управление отдельными разрядами (битами) значения переменной. Эта возможность связывается с представлением числа в компьютере, а именно с различными системами счисления: двоичной, восьмеричной, шестнадцатеричной.

У бита возможны только два значения: 0 и 1. Техническую реализацию таких состояний легко представить, например включено – выключено, положительное значение напряжения – отрицательное значение напряжения (определенного уровня) и т. д.

В языке программирования С термин байт используется для обозначения размера (разрядности) хранения набора символов. Поэтому в языке С байт может содержать 8, 9, 16 и другое количество разрядов. Однако в характеристиках модулей памяти и систем передачи данных предполагается, что байт содержит восемь разрядов [1]. Разряды байта пронумерованы справа налево числами от 0 до 7. Седьмой разряд (крайний левый) называется старшим, а нулевой (крайний правый) – младшим.

Байт имеет наибольшее значение, когда все его разряды установлены, т. е. имеют значение 1. Например, для 8 разрядов с учетом двоичной системы счисления в случае возможного наибольшего значения получим:

128

64

32

16

8

4

2

1

=

255

27

26

25

24

23

22

21

20

=

255

Наименьшему значению соответствует комбинация нулей 00000000, которая представляет собой просто нуль [9].

Байт может хранить числа от 0 до 255, что составляет 256 возможных значений. Программа может интерпретировать комбинацию разрядов иначе и применять байт для хранения чисел от –128 до 127, (также 256 значений). Например, тип unsigned char обычно характеризуется использованием байта для представления чисел в диапазоне от 0 до 255, тип signed char – до 127.

В основании восьмеричной системы счисления лежит число 8 (23). Каждое знакоместо восьмеричного числа соответствует определенной степени восьми. Для записи используются цифры от 0 до 7. Каждая цифра восьмеричного числа соответствует трем двоичным цифрам. Двоичные эквиваленты таких цифр представлены в табл.16.1.

266

Таблица 16.1

 

Двоичные эквиваленты восьмеричных цифр

 

 

 

Восьмеричная цифра

 

Двоичный эквивалент

 

 

 

0

 

000

1

 

001

2

 

010

3

 

011

4

 

100

5

 

101

6

 

110

7

 

111

 

 

 

В шестнадцатеричной системе счисления используются степени числа 16 и цифры от 0 до 15. Для представления цифр, соответствующих десятичным значениям от 10 до 15, применяются буквы от A до F [1]. Например, в шестнадцатеричном числе A3F (в языке С записывается как 0xA3F) заложено следующее значение:

10162 + 3 161 + 15 160 = 2 623 (по основанию 10).

Вприведенной записи числу 10 соответствует А, а числу 15 – F.

Язык С допускает использование букв нижнего и верхнего регистра (строчных и прописных) для обозначения шестнадцатеричных цифр. Таким образом, число 2 623 в указанной системе счисления можно записать как 0xA3F, так и 0xa3f. Каждая цифра шестнадцатеричного числа соответствует 4- значному двоичному числу [1], следовательно, две шестнадцатеричные цифры – одному восьмиразрядному байту. Первая цифра представляет 4 старших разряда, а вторая – 4 младших.

Соответствие между шестнадцатеричными цифрами, десятичными и двоичными числами показано в табл.16.2.

 

 

 

Таблица 16.2

 

Эквиваленты шестнадцатеричных чисел

 

 

 

 

Десятичное число

 

Шестнадцатеричная цифра

Двоичный эквивалент

 

 

 

 

1

 

2

3

 

 

 

 

0

 

0

0000

1

 

1

0001

2

 

2

0010

3

 

3

0011

4

 

4

0100

5

 

5

0101

6

 

6

0110

7

 

7

0111

8

 

7

1000

9

 

9

1001

 

 

 

 

267

 

 

Окончание табл. 16.2

 

 

 

1

2

3

 

 

 

10

A

1010

11

B

1011

12

C

1100

13

D

1101

14

E

1110

15

F

1111

В языке С существуют два средства управления разрядами [1]. Первое представляет собой набор поразрядных операций, а второе – форму полей данных, которая гарантирует доступ к разрядам значения типа int.

Далее будут использоваться 8-разрядные числа в двоичной системе счисления.

1.2. Логические поразрядные операции

В языке программирования С существуют два вида поразрядных операций: логические и операции сдвига [1]. Поразрядные операции выполняются над каждым разрядом независимо от того, находится он слева или справа, а также над целыми числами. Рассмотрим логические поразрядные операции.

Поразрядное отрицание обозначается символом тильда (~). Унарная операция ~ преобразовывает все единицы в нули и все нули в единицы (предполагается, что операции производятся над двоичными числами). Ее называют также операцией «дополнение», т. е. все биты, равные 0, переводятся в 1, а равные 1 – в 0.

Поразрядная операция И обозначается символом &. Двоичная операция & создает новое значение за счет выполнения поразрядного сравнения двух операндов. Для каждой позиции результирующий разряд будет иметь значение 1 только в случае, когда соответствующие разряды обоих операндов имеют значение 1. Можно сказать, что когда над двумя значениями производится операция поразрядного умножения &, то двоичные представления чисел сравниваются бит за битом [2]. Например, пусть одна переменная w1 есть число 25, а другая w2 – число 77. Соответственно в двоичном представлении 25 =

= 0000000000011001, 77 = 0000000001001101. Тогда в результате поразрядной операции & получим число w3 = w1 & w2. Результат действия оператора & можно представить следующим образом:

Поразрядная операция И (&)

 

w1

0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1

(25)

w2

0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1

(77)

w3

0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1

(9)

В результате поразрядной операции & над двумя числами (25 и 77 в двоичном представлении), которые имеют, например, 16 бит, получили новое число 9.

268

Поразрядный оператор & часто используется для операций маскирования. С его помощью принудительно можно установить определенный бит данных в значение 0. Например, в утверждении

w3 = w1 & 3;

переменной w3 присваивается значение переменной w1, для которой выполнена поразрядная операция & со значением 3. При этом все биты левее двух младших битов устанавливаются в 0, а остальные сохраняют свое значение [2]. Маска представляет собой некоторую комбинацию разрядов [1]. Разряды маски с нулевыми значениями можно считать аналогом непрозрачных ячеек реальной маски, а разряды со значениями 1 – прозрачными ячейками.

Поразрядная операция & называется также конъюнкцией, или логическим умножением, часто обозначается словом AND.

Поразрядная операция ИЛИ обозначается символом |. Когда над двумя значениями производится эта операция, то последовательно сравниваются значения всех битов при их двоичном представлении [5]. Если соответствующий бит имеет значение 1 в первом или втором операнде, то результирующее значение будет равно 1. Рассмотрим предыдущий пример с поразрядной операци-

ей ИЛИ:

Поразрядная операция ИЛИ (|)

 

w1

0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1

(25)

w2

0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1

(77)

w3

0 0 0 0 0 0 0 0 0 1 0 1 1 1 0 1

(93)

Данную операцию обычно используют для установки заданных битов слова в 1. Ее называют также включающей дизъюнкцией, или логическим сложением. Часто применяется обозначение OR.

Поразрядная операция исключающего ИЛИ (^) работает следующим об-

разом [5]. Сравниваются соответствующие биты двух операндов, и если только один из битов равен 1, будет получен результат 1, а при равенстве обоих соответствующих битов или 0, или 1 результат будет равен 0. Для двух операндов b1, b2 при использовании исключающего ИЛИ справедлива таблица истинности (табл.16.3).

Таблица 16.3

Таблица истинности операции исключающего ИЛИ

b1

b2

b1 ^ b2

 

 

 

0

0

0

 

 

 

0

1

1

 

 

 

1

0

1

 

 

 

1

1

0

 

 

 

Если операцию исключающего ИЛИ использовать для одного и того же значения, то в результате получится нуль. Этот прием часто использовался программистами в языке ассемблера как наиболее быстрый путь установить значение в нуль или сравнить два значения на их равенство. Данный способ не реко-

269

мендуется использовать в языке программирования С, так как скорость работы не повышается, а программа становится менее понятной [2]. Операция исключающего ИЛИ может применяться для перестановки значений двух переменных без выделения дополнительной памяти (и соответственно без использования дополнительной переменной).

Поразрядная операция исключающего ИЛИ называется также исключающей дизъюнкцией, применяется обозначение XOR.

1.3. Поразрядные операции сдвига

Оператор сдвига влево <<

Когда оператор сдвига влево << выполняется над некоторым значением, все биты, составляющие это значение, сдвигаются влево [2]. Связанное с данным оператором число показывает количество бит, на которое значение должно переместиться. Биты, сдвигающие со старшего разряда, считаются потерянными, а на место младших битов всегда помещаются нули.

Оператор сдвига вправо >>

Операция сдвига вправо >> сдвигает разряды левого операнда вправо на количество позиций, указываемое правым операндом. Выходящие за правую границу разряды теряются. Для типов данных без знака (unsigned) освобождаемые слева позиции заполняются нулями. Для знаковых типов результат зависит от используемой системы. Освобождаемые позиции могут заполняться нулями либо копиями знакового (первого слева) разряда [1].

Поразрядные операции сдвига могут служить удобным и эффективным средством выполнения операций умножения и деления на числа, представляющие собой степени двойки [1]. Они аналогичны смещению десятичной точки при умножении или делении на 10.

1.4. Битовые поля

Второй метод управления разрядами состоит в использовании битового (разрядного) поля [1], которое представляет собой последовательную цепочку разрядов в рамках значения типа signed int или unsigned int. Оно может быть только элементом структуры или объединения [3]. Создается путем объявления структуры (объединения), которая помечает каждое поле и определяет его разряд.

Приведем пример с использованием битовых полей в структуре [2]:

struct packed_struct { unsigned int : 3; unsigned int f1 : 1; unsigned int f2 : 1; unsigned int f3 : 1; unsigned int type : 8;

unsigned int index : 18; };

270

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