учебное пособие. Часть1. Информатика
.pdfсив А = { 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