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

учебное пособие. Часть1. Информатика

.pdf
Скачиваний:
42
Добавлен:
04.06.2015
Размер:
2.87 Mб
Скачать

сив А = { 1, 2, 3, 4, 5, 6, 7 } превращается в массив А = { 4, 5, 6, 7, 1, 2, 3 }.

Фактически задача состоит в том, что необходимо поменять местами две час- ти массива АВ так, чтобы получить массив ВА. Если решать задачу «в лоб», то можно выполнить k циклов перемещения влево на одну позицию всех элементов массива, либо использовать дополнительный массив. Эта задача выглядит трудной до тех пор, пока не посетит озарение [16]. Пусть есть функция ver, которая реверсирует массив (меняет порядок следования эле- ментов на обратный). Используя эту функцию, сначала реверсируем весь массив, потом переворачиваем первые n-k элементов, затем оставшиеся k элементов:

А= { 7, 6, 5, 4, 3, 2, 1 }

А= { 4, 5, 6, 7, 3, 2, 1 }

А= { 4, 5, 6, 7, 1, 2, 3 }

Код, использующий функцию переворота оказывается эффективным и мало требовательным к памяти, и настолько короток и прост, что в нем до- вольно трудно допустить ошибку. Эта программа очень хорошо подходит для перемещения строк в редакторе текстов.

//Пример 27 //Функция переворота массива

void ver ( int x[], int k, int n )

{

int d;

for( int i=k; i<=n/2; i++ )

{

d = x[i]; x[i] = x[n-i]; x[n-i] = d;

}

}

int main ()

{

int n, k, i;

cout << "\n Введите n и k= "; cin >> n >> k;

k = k%n;

int *a = new int[n];

cout << "\n Введите элементы массива\n"; for ( i = 0; i<n; i++)

231

cin >> a[i] ; if (k)

{

ver (a, 0, n-1); ver (a, 0, n-1-k);

ver (&a[n-k], 0, k-1);

}

cout << "\n Массив после сдвига \n"; for ( i = 0; i<n; i++)

cout << a[i] << " "; return 0;

}

Рассмотрим пример, демонстрирующий передачу двумерного массива в функцию. Дано два двумерных массива. Требуется поменять местами ми- нимальные элементы массивов. Программа разбита на четыре функции:

главная функция main;

ввода двумерного массива vvod;

вывода двумерного массива vivod;

поиска минимального элемента двумерного массива min. // Пример 28 //Прототипы функций

void vvod (int **x, int nx,int mx); void vivod (int **x, int nx,int mx);

void min( int **x, int nx,int mx,int &imin,int &jmin); // Главная функция

int main()

{

int n, m, k, l;//Количество строк и столбцов массивов int **a, **b;//Указатели на двумерные массивы

int j, i; //Переменные цикла и размерности массивов int imina, jmina, iminb, jminb;//Индексы минимальных

//элементов

int d; // Дополнительная переменная для обмена printf ( "\nВведите pазмеpность массива а " ); scanf ( "%d%d", &n, &m );

printf ( "\n Введите pазмеpность массива b " ); scanf ( "%d%d", &k, &l );

a = new int*[n]; for ( i=0; i<n; i++ ) a[i] = new int [m]; b = new int*[k]; for ( i=0; i<k; i++ )

232

b[i] = new int [l];

printf ( "\nВведите массив а" ); vvod ( a, n, m );

printf ( "\n Введите массив b" ); vvod ( b, k, l );

//Контpольный вывод элементов массива printf ( "\n Массив а:" );

vivod ( a, n, m );

printf ( "\n Массив b:" ); vivod ( b, k, l );

//Вызов функции поиска минимального элемента min ( a, n, m, imina, jmina );

min (b, k, l, iminb, jminb );

//Меняем местами минимальные элементы d = a[imina][jmina];

a[imina][jmina] = b[iminb][jminb]; b[iminb][jminb] = d;

//Контpольный вывод элементов массива

printf ( "\nМассив а:" ); vivod ( a, n, m );

printf ( "\nМассив b:" ); vivod ( b, k, l );

return 0;

}

//Описание функции ввода двумерного массива void vvod (int **x, int nx, int mx )

{

int j, i;

for ( i=0; i<nx; i++ ) for ( j=0; j<mx; j++ )

scanf ( "%d", &x[i][j] );

}

//Описание функции вывода двумеpного массива void vivod ( int **x, int nx, int mx )

{

int j, i;

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

{

printf ( "\n" );

for (j=0; j<mx; j++ ) printf ( "%5d", x[i][j] );

}

233

}

/*Описание функции поиска индексов минимального элемента двумеpного массива*/

void min(int **x, int nx, int mx, int &imin, int &jmin)

{

int j, i;

imin = 1; //Hачальные значения для

jmin = 1; // индексов минимального элемента for ( i=0; i<nx; i++ )

for ( j=0; j<mx;j++ )

if (x[i][j]<x[imin][jmin] )

{

imin = i; jmin = j;

}

}

В функции min используются качестве параметров ссылки int &imin, int &jmin. Если здесь передать параметры по значению, то изменение фор- мальных параметров не повлечет изменения фактических параметров.

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

1.Для чего предназначены функции?

2.Как описываются ссылочные переменные?

3.Как происходит передача параметров в функцию по значению?

4.Как происходит передача параметров в функцию по указателю?

5.Как происходит передача параметров в функцию по ссылке?

6.Какие требования предъявляются к списку формальных параметров?

7.Какого типа значения может возвращать функция?

8.Для чего предназначен оператор return?

9.Какие значения будут напечатаны в результате работы следующей программы:

#include<cstdio> using namespace std; int a=1, b=2, c=3;

int f (int a, int &b, int *c)

{

a+=2; b++; *c=*c+1; return a+b;

}

int main ()

234

{

c = f (a+1, b, &c);

printf ( "\n a =%5d b =%5d c =%5d \n", a, b, c); return 0;

}

10.Как передать в функцию одномерный массив?

11.Как передать в функцию двумерный массив?

235

6. СТРОКИ СИМВОЛОВ

Символьная переменная это величина размером в 1 байт, которая ис-

пользуется для представления литер и целых чисел в диапазоне от 0 до 255 или от –128 до 127. Диапазон зависит от того, знаковая это переменная или нет. Символьные константы заключаются в апострофы. Например, ’a’, ’=’, ’9’. Используется специальный код для перевода чисел в символы. Чаще всего это код ASCII (американский стандартный код обмена инфор- мацией). Латинская буква А имеет код 65, а русская буква А 128. Поэто- му при работе с русским алфавитом, необходимо использовать беззнаковые целые (unsigned char), диапазон представления которых лежит в ин- тервале от 0 до 255. Буквы латинского алфавита в таблице ASCII распо- ложены по порядку. Буквы русского алфавита имеют разрыв, но их код воз- растает в соответствии с алфавитом. Некоторые символы не печатаются, в этом случае используется номер символа с обратной косой чертой, например ’\007’ (этот символ используется для выдачи короткого звукового сигна- ла) или ’\n’ (перевод курсора на новую строку).

Для ввода символов можно использовать специальные функции ввода- вывода. Функция getchar () получает один символ, поступающий с кла- виатуры, и передает его выполняющейся в данный момент программе. Функ- ция putchar() получает один символ, поступающий из программы, и пе- редает его для вывода на экран. Рассмотрим пример программы, принимаю- щей один символ с клавиатуры и выводящей его на экран:

//Пример pr28

#include <cstdio> using namespace std; int main()

{

unsigned char ch; ch = getchar (); putchar (ch); return 0;

}

Составим программу, которая определяет, сколько символов считано

из входного потока и сколько из них символов ’a’. Ввод завершается, когда

встретится символ '#'.

// Пример pr29 #include <cstdio>

using namespace std; int main()

{

unsigned char ch;

236

int k = 0,k1 = 0;

while (( ch = getchar ()) != '#')

{

k++; //Количество символов в тексте

if (ch == 'a') k1++; //Количество букв ’a’ в тексте

}

printf ( "\n k= %d k1= %d ", k, k1); return 0;

}

При подсчете символов будут учитываться все символы, включая про- белы и перевод курсора на новую строку ’\n’ (при нажатии клавиши enter).

Символьные строки представляют один из наиболее полезных и важ- ных типов данных. В языке С++ символьная строка является символьным массивом, который заканчивается нуль-символом (\0). Если строка должна содержать N символов, то в описании нужно указать N+1 элемент [4]. При- меры описания, ввода и вывода строк символов приведены в pr30.

// Пример pr30 #include <cstdio> using namespace std; #include <string> //Строковая константа

#define msg "На экзамене по программированию" char msg1[] = "студенты получают "; //Инициализация

// внешнего массива char *msg2 = " вопрос и задачу"; //Инициализация

// указателя внешнего символьного массива

int main()

{

unsigned char name[10];

static unsigned char *tema[5] =//Массив указателей

// на символьный тип

{"Массивы динамические", "Функции и массивы", "Строки символов ", "Структуры", "Файлы текстовые"

};

puts ("Введите ваше имя:"); gets (name);

strcat (name, "!"); // Сцепление двух строк puts (name);

puts (msg);

237

puts (msg1); puts (msg2);

puts ("на следующие темы:"); for (int i = 0; i < 5; i++)

puts (tema[i]);

puts ("Не забудьте про блок-схему!"); return 0;

}

Здесь продемонстрированы различные способы описания и ини- циализации символьных строк, а также некоторые функции обработки строк. Функция gets() получает строку с клавиатуры. Функция читает символы до тех пор, пока не встретит символ новой строки (’\n’),

который создается при нажатии клавиши enter. Функция берет все символы до ’\n’

и присоединяет к ним символ ’\0’. Аргументом функции должен быть указатель на строку символов. Функция puts() выводит строку, указа- тель на которую является аргументом этой функции, на экран. Функция puts() прекращает свою работу, как только встретит нуль-символ (по- этому надо следить, чтобы он был), и заменяет его символом новая строка.

Для работы со строками существует специальная библиотека, опи-

сание которой находится в файле string. Рассмотрим наиболее часто используемые функции из этой библиотеки.

strlen (s) определяет длину строки (без нуль-символа). s указатель на строку символов.

strcat (s1, s2) – объединяет две строки. s1, s2 – указа- тели на строку символов. Копия второй строки присоединяется к концу первой, и это объединение становится новой первой строкой. Строка s2 ос- тается без изменения, а s1должна быть достаточно большой, чтобы размес- тить две строки.

strcmp (s1, s2) сравнивает содержимое двух строк. s1, s2- указатели на строку символов. Эта функция возвращает 0, если строки одинаковые. Если строки разные, то функция возвращает разни- цу в кодах у первой пары несовпадающих символов.

strcpy (s1, s2) – копирование строки: строка, на которую указывает второй аргумент, копируется в строку, на которую указывает первый.

strchr (s, c) – ищет в строке s первое вхождение символа с и возвращает указатель на этот символ, если не обнаружит, то возвраща-

ет NULL.

strstr (s1, s2) ищет в строке s1 первое вхождение под- строки s2 и возвращает указатель на найденную подстроку, если не об- наружит, то возвращает NULL.

238

Рассмотрим примеры, демонстрирующие использование этих функций.

// Пример pr31 int main (void)

{

char string[15]; char *ptr, c = 'r';

strcpy (string, "This is a string"); ptr = strchr (string, c);

if (ptr)

printf ( "The character %c is at position: %d\n", c, ptr-string); else

printf("The character was not found\n"); return 0;

}

Результатом работы этой программы будет строка:

The character r is at position: 12

Следующий пример демонстрирует использование функции

strstr:

//Пример pr32 int main (void)

{

char *str1 = "Borland International", *str2 = "nation", *ptr;

char *ptr;

ptr = strstr (str1, str2);

printf ("The substring is: %s\n", ptr); return 0;

}

Далее рассмотрим программу, определяющую, количество символов, строк и слов в тексте, читаемом с клавиатуры [7].

// Пример pr33 #define YES 1

#define NO 0 int main()

{

int c,// Текущий символ

nl, nw, nc,//Количество символов, строк и слов inword; //Переменная, отвечающая за положение

//текущего символа: в слове или вне слова nl = nw = nc = 0; inword = NO;

while (( c = getchar ()) != EOF ) //Читаем символы, // пока не встретится конец файла

239

{

 

 

++nc;

// Подсчет символов

if ( c == '\n')

//Если символ новая строка,

++nl;

//то увеличиваем число строк

if ( c == ' ' || c=='\n' || c=='\t' ) //Если,

inword = NO;

// встретился разделитель

else

// то символ вне слова

 

 

if ( inword == NO ) //Если не разделитель и вне

{ inword=YES; // слова, то первый символ слова

++nw;

// Увеличиваем число слов

}

 

 

}

 

 

printf ("nc =%d \t nl =%d \t nw =%d",nc, nl, nw);

}

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

240