Основы программирования. Учебное пособие
.pdf
Определение переменной типа указатель на значение специфицированного типа:
<спецификация типа> * <идентификатор>; Здесь символ ′*′ является признаком типа указатель.
Пример определения переменных типа указатель: int *pv;
float *py;
Переменная pv – это указатель на значение типа int (т. е. значение pv это адрес области памяти, в которой может храниться число типа int), а py – указатель на значение типа float. Для вышеописанных массивов в результате присваивания pv = vector, pv будет указывать на первый элемент массива, иначе говоря, значение pv – это адрес эле-
мента vector[0];
*pv – это выражение с унарной операцией косвенной адресации (разыменование), ее результатом является значение первого элемента массива, что эквивалентно vector[0];
*(pv+i) – это выражение с унарной операцией косвенной адресации, результатом которой будет значение i–того элемента массива, что эквивалентно vector[i], если pv указывает на первый элемент массива (если нет, то на i-ый после pv, а pv - i на i-ый перед pv).
pv+2: pv: pv+1:
vector:
vector[0] vector[9]
Переменную py можно использовать для ссылки на любой из массивов с элементами типа float. Если присвоить py =&mas[0][0], то py равно указателю на mas[0][0], выражение *(py+i)+j это указатель на элемент mas[i][j]. Если присвоить py=&x[i][j], то py указывает на x[i][j] элемент массива x, выражение py+1 – это указатель на элемент следующий после элемента x[i][j]. Изменяя значение указателя (например, py++) можно переходить от одного элемента массива к другому.
31
4.4. ПРИМЕНЕНИЕ МАССИВОВ ПРИ РЕШЕНИИ ЗАДАЧ
Необходимость в использовании массивов при решении задач возникает всякий раз, когда приходится иметь дело с большим, но конечным числом однотипных данных. В таком случае все данные можно объединить в каком-то порядке следования в единую структуру, которой дается одно имя. Это позволяет в компактном и единообразном виде записать действия над отдельными данными как над элементами массива (используя обобщенное обозначение элемента массива).
Особенностью алгоритмов обработки массивов является то, что все или большинство (или какое-то число) элементов обрабатываются одинаково (по одному алгоритму). Поэтому, решая задачу, приходится в том или ином порядке просматривать (перебирать) элементы массивов. Чтобы осуществить перебор надо определить правило изменения индекса элементов (для многомерных массивов – индексов). В случае многомерных массивов (если индексы не должны изменяться одновременно) изменение одного индекса должно быть вложено в правило изменения другого.
Пример: для матрицы float x[10][10], перебор элементов можно организовать по строкам, столбцам или диагоналям. Если перебор идет
по строкам, то первый индекс (индекс строки) изменяется 0 i 9, вто-
рой индекс (индекс столбца) изменяется 0 j 9 для каждого значения i.
Схема обработки всех элементов матрицы может быть представлена следующим образом:
i := v0; while (i vn )
{S1; j := t0; while( j tm )
{ S2; j := j+1 ;} S3; i := i+1;}
Здесь i принимает последовательно значения v0, v0+1, v0+2, ... , vn. Ее можно использовать в операторах S1, S2, S3 как один из индексов (номер строки или столбца) элемента матрицы. Переменная j принимает последовательно значения t0, t0+1, t0+2, ... , tm и ее можно использовать в операторе S2 как второй индекс (номер столбца или строки).
32
Если, обрабатывая массив, приходится перебирать все его элементы или известное количество, то удобно воспользоваться оператором цикла с заданным числом повторений (со счетчиком):
for (v=a; v b; v++) S; |
(1) |
где v – параметр цикла – переменная целого типа; a – начальное значение параметра цикла; b – конечное значение параметра цикла (a и b
задаются выражениями, при этом a b); S – оператор (тело цикла) или
for (v =a; v b; v-- ) S; |
(2) |
здесь a b.
Выполнение действий в цикле происходит следующим образом: в цикле (1):
v = a; while (v b) {S; v++;}
в цикле (2):
v= a; while( v b) {S; v--;}
Шаг изменения параметров цикла v может быть и больше единицы. В таких циклах, как правило, параметр цикла v используется в ка-
честве индекса элемента массива.
Так как размер массива фиксируется при его описании, задавайте его, используя именованные константы, тогда вы получите более общее описание. В этом случае фактический размер массива может быть меньше или равен объявленному:
const int n = 20; const int m = 10; void main ( )
{
int p, k, i, j, x[n][m];
printf ("Введите размер матрицы: "); scanf("%d%d ", &p,&k);
// Тогда ввод значений элементов массива x по строкам можно описать:
33
for (i= 0; i < p; i++ )
for (j = 0; j < k; j++) scanf ("%f ", &x[i][j]);
//Во входной строке значения элементов матрицы должны следовать друг
//за другом через пробел и перечисляться по строкам.
//После ввода элементов строки удобно с целью разделения строк
//нажимать ENTER;
// Ввод значений элементов массива x по столбцам можно описать: for (i = 0; i< k; i++ )
for (j = 0; j < p; j++) scanf("%f "&x[j][i]);
//Во входной строке значения элементов матрицы должны следовать друг //за другом через пробел и перечисляться по столбцам.
//После ввода столбца нажимайте ENTER для разделения столбцов.
}
4.5.ЗАДАЧИ И РЕШЕНИЯ
1.Написать программу решения задачи:
1) Задана последовательность из n (n ≤ 50) вещественных чисел. Вычислить выражение x12 + x32 + x52 + … + xn2 .
#include <stdio.h >
#include <conio.h > const int m = 50; void main ( )
{
int n;
float s, x[m];
printf ("\n введите размер последовательности: "); scanf("%d ", &n);
printf ("\n введите последовательность: "); for (int i = 0; i < n; i++ )
scanf ("%f ", &x[i]);
for (i = 0, s = 0; i < n; i = i + 2 ) s = s + x[i] * x[i];
34
printf ("\n%f ", s); getch ( );
}
2) Задана последовательность X из n (n ≤ 50) вещественных чисел. Вычислить выражение x1 + x1x2 + x1x2x3 + … + x1x2…xm , где m– либо номер первого отрицательного элемента последовательности X, либо число n, если в последовательности X нет отрицательных элементов.
#include <stdio.h >
#include <conio.h >
const int m = 50; void main ( )
{
int n, i;
float s, b, x[m];
printf ("\n введите размер последовательности: "); scanf("%d ", &n);
printf ("\n введите последовательность: "); for (i = 0; i < n; i++ )
scanf ("%f ", &x[i]); s = b = x[0];
for ( i 1; i n & & x i-1 0; i ) { b * x i ; s b;} printf ("\ n% f ", s );
getch ( );
}
3) Заданы две квадратные матрицы A и B n -го порядка каждая (n ≤ 20). Вычислить C = A + B.
#include <stdio.h >
#include <conio.h >
const int m = 20; void main ( )
35
{
int n, k, i, j;
float A[m][m] , B[m][m] , C[m][m];
printf ("\n введите размер матрицы: "); scanf("%d ", &n);
printf ("\n введите матрицы: ");
for (i = 0; i < n; i++ )
for (j = 0; j < n; j++) scanf ("%f ", &A[i][j]); for (i = 0; i < n; i++ )
for (j = 0; j < n; j++) scanf ("%f ", &B[i][j]); for (i = 0; i < n; i++ )
for (j = 0; j < n; j++) C[i][j] = A[i][j] + B[i][j]; for (i = 0; i < n; i++ ) {
for (j = 0; j < n; j++) printf ("%.2f ", C[i][j]); printf ("\n ");}
getch ( );
}
4) Дана квадратная матрица A n -го порядка (n ≤ 20). Вычислить A = A Т (транспонировать матрицу).
# include <stdio.h >
# include <conio.h >
const int m = 20; void main ( )
{
int n, i, j;
float A[m][m], r;
printf ("\n введите размер матрицы: "); scanf("%d ", &n);
36
printf ("\n введите матрицу: "); for (i = 0; i < n; i++ )
for (j = 0; j < n; j++) scanf ("%f ", &A[i][j]); for (i = 0; i < n - 1; i++ )
for (j = i + 1; j < n; j++) {r = A[i][j]; A[i][j] = A[j][i]; A[j][i] = r;} for (i = 0; i < n; i++ ) {
for (j = 0; j < n; j++) printf ("%.2f ", A[i][j]); printf ("\n ");}
getch ( );
}
5) Дана прямоугольная матрица A размером n×m (n, m ≤ 20). Сформировать последовательность B, k-й элемент которой равен единице, если k-тая строка матрицы A симметрична, в противном случае k-й элемент равен нулю.
#include <stdio.h >
#include <conio.h > const int p = 20; void main ( )
{
int n, m, k, i, j;
int A[p][p], B[p], r;
printf ("\n введите размер матрицы: "); scanf("%d %d ", &n, &m);
printf ("\n введите матрицу: "); for (i = 0; i < n; i++ )
for (j = 0; j < m; j++) scanf ("%d ", &A[i][j]); for (i = 0; i < n; i++ )
{k = 1;
for ( j = 0; j < m / 2 && k; j++) {if ( A[i][j] != A[i][m - j-1]) k = 0;} B[i] = k;
}
printf ("\n ");
37
for (i = 0; i<n; i++ ) printf ("%d ", B[i]); getch ( );
}
6) Дана квадратная матрица A n -го порядка (n ≤ 50). Найти наибольшее значение среди элементов главной диагонали матрицы A:
#include <stdio.h>
#include <conio.h> const int m = 50; void main()
{
int n, i, j;
float A[m][m], max;
printf ("Введите размер матрицы: "); scanf("%d ", &n);
printf ("Введите матрицу: "); for (int i = 0; i < n; i++ )
for (j = 0; j < n; j++) scanf ("%f ", &A[i][j]);
for (i = 1, max = A[0][0]; i < n; i++ ) if ( A[i][i] > max)
max = A[i][i]; printf ("\n %.2f ", max); getch();
}
38
ТЕМА 5
ОБРАБОТКА ТЕКСТОВОЙ ИНФОРМАЦИИ
5.1. ПОНЯТИЕ ОБРАБОТКИ ТЕКСТА
Обработка текста – это пример задачи из нечисловой предметной области. Обработка текста сводится к решению двух основных подзадач:
а) поиск в некоторой заданной последовательности слов или символов другой заданной последовательности слов или символов. При этом результатом поиска является не только вхождение одной последовательности в другую, но и позиция вхождения.
б) редактирование последовательности слов или символов, т. е. замена одной последовательности на другую, включение в текст новой последовательности, удаление из текста некоторой последовательности.
Важной особенностью обработки текста является то, что объем текстовой информации достаточно велик, а сама обработка, как правило, состоит в просмотре всего текста. Поэтому, решая такие задачи, необходимо стремиться к тому, чтобы каждый символ текста просматривался один и только один раз.
5.2. СТРОКОВЫЙ ТИП
Значением «строкового» типа является последовательность символов (слово строковый заключено в кавычки, так как в Си явно такой тип не определен и, говоря о строковом типе, мы имеем в виду тип данных, обладающий свойствами строкового типа). «Строковый» тип (или просто строка) в Си рассматривается как подмножество типа массив. Строка задается одномерным массивом, элементы которого символы, последний символ массива – ′\0′. Этот «нуль-символ», является признаком конца строкового значения. Символ ′\0′ также как другие символы входит в строку. Если первым элементом строки является ′\0′ – это пустая строка (пустое строковое значение). Размер строки (количество символов) определяется решаемой задачей и ограничивается доступным объемом памяти.
39
Пример определения переменной строкового типа (строки): char str[10];
char word[ ] = {′a′,′b′,′c′,′d′,′\0′}; char stroka[ ] = "ABCDEF";
В первом примере определен массив из 10 элементов типа char. Чтобы использовать такой массив как строку надо позаботиться о том, чтобы при задании значений элементам этого массива один из элементов получил значение символа ′\0′.
Например: char ch, i;
scanf ("%c", &ch); i = 0;
while (ch != ′,′) { str[i++] = ch; scanf ("%c", &ch);} str[i] = ′\0′;
Читая последовательность символов, помещаем очередной символ в массив str, пока не введем символ ′,′. После ввода символа ′,′ и выхода из цикла добавляем к символам в массиве str символ ′\0′- признак конца строки. Максимальная длина последовательности символов в строке str – 9 символов (10-й символ это ′\0′).
Во втором примере определен и инициализирован массив word из пяти символов, последним из которых является признак конца строки.
В третьем примере определен и инициирован массив stroka из 7 символов, последним из которых также является символ ′\0′, так как массив инициирован строковой константой "ABCDEF" (символ ′\0′ всегда завершает строковую константу). Количество элементов в массиве (во втором и третьем примерах) определяет компилятор по числу начальных значений в списке инициализации.
Так как строковый тип – это одномерный массив символов, дополненный специальным символом, то для строки сохраняются все свойства регулярного типа (т. е. над отдельными элементами можно выполнять операции, допустимые для базового типа). С «нуль-cимволом» можно работать, как и с остальными символами (не забывая, о его основном назначении).
Кроме этого, для строк определен набор стандартных функций. Функции работы со строками позволяют обрабатывать строку как единое значение. Для использования функций работы со строками надо подключить к программе файл string.h.
40
