- •Кетков ю.Л.
- •Раздел 5. Системные данные текстового типа 33
- •Раздел 6. Основные синтаксические конструкции языка c 46
- •Раздел 7. Указатели и ссылки 59
- •Раздел 8. Функции и их аргументы 62
- •Раздел 9. Работа с массивами. 74
- •Раздел 10. Пользовательские типы данных. 95
- •Раздел 11. Работа с файлами 104
- •Раздел 12. Библиотеки стандартных и нестандартных функций 118
- •Раздел 15. Классы. Создание новых типов данных 131
- •Раздел 16. Классы как средство создания больших программных комплексов 150
- •Раздел 17. Прерывания, события, обработка исключений 167
- •Введение
- •Раздел 1. Немного истории
- •Раздел 2. Структура программы на языке c
- •Раздел 3. Среда программирования
- •Раздел 4. Системные данные числового типа
- •4.1. Типы числовых данных и их представление в памяти эвм
- •4.1.1. Внутреннее представление целочисленных данных
- •4.1.2. Однобайтовые целочисленные данные
- •4.1.3. Двухбайтовые целочисленные данные
- •4.1.4. Четырехбайтовые целочисленные данные
- •4.1.5. Восьмибайтовые целочисленные данные
- •4.2. Внутреннее представление данных вещественного типа
- •4.3. Внешнее представление числовых констант
- •4.4. Объявление и инициализация числовых переменных
- •4.5. Ввод числовых данных по запросу программы
- •4.5.1. Потоковый ввод данных числового типа
- •4.5.2. Форматный ввод
- •4.6. Вывод числовых результатов
- •4.6.1. Форматный вывод
- •4.6.2. Потоковый вывод
- •4.7. Примеры программ вывода числовых данных
- •4.8. Операции над числовыми данными целого типа
- •4.9. Операции над числовыми данными вещественного типа
- •Раздел 5. Системные данные текстового типа
- •5.1. Символьные данные и их представление в памяти эвм
- •5.2. Строковые данные и их представление в памяти эвм
- •5.3. Ввод текстовых данных во время работы программы
- •5.3.1. Форматный ввод
- •5.3.3. Потоковый ввод
- •5.3.4. Специальные функции ввода текстовых данных
- •5.4. Вывод текстовых данных
- •5.4.1. Форматный вывод
- •5.5.2. Операции над строковыми данными
- •5.6. Управление дисплеем в текстовом режиме
- •Раздел 6. Основные синтаксические конструкции языка c
- •6.1. Заголовок функции и прототип функции
- •6.2. Объявление локальных и внешних данных
- •6.3. Оператор присваивания
- •6.4. Специальные формы оператора присваивания
- •6.5. Условный оператор
- •6.6. Оператор безусловного перехода
- •6.7. Операторы цикла
- •6.8. Дополнительные операторы управления циклом
- •6.9. Оператор выбора (переключатель)
- •6.10. Обращения к функциям
- •6.11. Комментарии в программах
- •Раздел 7. Указатели и ссылки
- •7.1. Объявление указателей
- •7.2. Операции над указателями
- •7.3. Ссылки
- •Раздел 8. Функции и их аргументы
- •8.1. Параметры-значения
- •8.2. Параметры-указатели
- •8.3. Параметры-ссылки
- •8.4. Параметры-константы
- •8.5. Параметры по умолчанию
- •8.6. Функции с переменным количеством аргументов
- •8.7. Локальные, глобальные и статические переменные
- •8.8. Возврат значения функции
- •8.9. Рекурсивные функции
- •8.10. Указатели на функцию и передача их в качестве параметров
- •8.11. "Левые" функции
- •Раздел 9. Работа с массивами.
- •9.1. Объявление и инициализация массивов.
- •9.2. Некоторые приемы обработки числовых массивов
- •9.2. Программирование задач линейной алгебры
- •9.2.1. Работа с векторами
- •9.2.2.Работа с матрицами
- •9.3. Поиск
- •9.3.1. Последовательный поиск
- •9.3.2. Двоичный поиск
- •9.4. Сортировка массивов.
- •9.4.1. Сортировка методом пузырька
- •9.4.2. Сортировка методом отбора
- •9.4.3. Сортировка методом вставки
- •9.4.4. Сортировка методом Шелла
- •9.4.5.Быстрая сортировка
- •9.5. Слияние отсортированных массивов
- •9.6. Динамические массивы.
- •Раздел 10. Пользовательские типы данных.
- •10.1. Структуры
- •10.1.1. Объявление и инициализация структур
- •10.1.2. Структуры – параметры функций
- •10.1.3.Функции, возвращающие структуры
- •10.2. Перечисления
- •10.3. Объединения
- •Раздел 11. Работа с файлами
- •11.1.Файлы в операционной системе
- •11.1. Текстовые (строковые) файлы
- •11.2. Двоичные файлы
- •11.3. Структурированные файлы
- •11.4. Форматные преобразования в оперативной памяти
- •11.5. Файловые процедуры в системе bcb
- •11.5.1. Проверка существования файла
- •11.5.2. Создание нового файла
- •11.5.3. Открытие существующего файла
- •11.5.4. Чтение из открытого файла
- •11.5.5. Запись в открытый файл
- •11.5.6. Перемещение указателя файла
- •11.5.7. Закрытие файла
- •11.5.8. Расчленение полной спецификации файла
- •11.5.9. Удаление файлов и пустых каталогов
- •11.5.10. Создание каталога
- •11.5.11. Переименование файла
- •11.5.12. Изменение расширения
- •11.5.13. Опрос атрибутов файла
- •11.5.14. Установка атрибутов файла
- •11.5.15. Опрос и изменение текущего каталога
- •11.6. Поиск файлов в каталогах
- •Раздел 12. Библиотеки стандартных и нестандартных функций
- •12.2. Организация пользовательских библиотек
- •12.3. Динамически загружаемые библиотеки
- •13.1. Препроцессор и условная компиляция
- •13.2. Компилятор bcc.Exe
- •13.3. Утилита grep.Com поиска в текстовых файлах
- •14.1. Переопределение (перегрузка) функций
- •14.2. Шаблоны функций
- •Раздел 15. Классы. Создание новых типов данных
- •15.1. Школьные дроби на базе структур
- •15.2. Школьные дроби на базе классов
- •15.3. Класс на базе объединения
- •15.4. Новые типы данных на базе перечисления
- •15.5. Встраиваемые функции
- •15.6. Переопределение операций (резюме)
- •15.8. Конструкторы и деструкторы (резюме)
- •Раздел 16. Классы как средство создания больших программных комплексов
- •16.1. Базовый и производный классы
- •16.1.1.Простое наследование
- •16.1.2. Вызов конструкторов и деструкторов при наследовании
- •16.1.3. Динамическое создание и удаление объектов
- •16.1.4. Виртуальные функции
- •16.1.5. Виртуальные деструкторы
- •16.1.6. Чистые виртуальные функции и абстрактные классы
- •16.2. Множественное наследование и виртуальные классы
- •16.3. Объектно-ориентированный подход к созданию графической системы
- •Раздел 17. Прерывания, события, обработка исключений
- •17.1. Аппаратные и программные прерывания
- •17.2. Исключения
9.2. Программирование задач линейной алгебры
9.2.1. Работа с векторами
Создание программ для обработки одномерных массивов на языках C, C++ особых проблем не вызывает. Чтобы это доказать, продемонстрируем несколько функций, реализующих стандартные операции над векторами.
Пример 9.6. Вычисление нормы вектора.
#include <stdio.h>
#include <math.h> //здесь находится прототип функции sqrt
#include <conio.h>
double norm(double *a, int n)
{ double s=0;
for(int i=0; i<n; i++) s += a[i]*a[i];
return sqrt(s);
}
void main()
{ double v1[5]={1.,2.,3.,4.,5.};
printf("norm=%f",norm(v1,5));
getch();
}
//=== Результат работы ===
norm=7.416198
Функцией norm можно воспользоваться и для того, чтобы вычислить "норму" любого фрагмента вектора – достаточно вместо первого аргумента задать адрес начальной компоненты (например, &v1[2]), а в качестве второго аргумента количество обрабатываемых компонент.
Пример 9.7. Нормирование вектора.
#include <iostream.h>
#include <math.h> //здесь находится прототип функции sqrt
#include <conio.h>
void norm_vec(double *a, int n)
{ double s=0;
for(int i=0; i<n; i++) s += a[i]*a[i];
s= sqrt(s);
for(int i=0; i<n; i++) a[i] /= s;
}
void main()
{ double v1[5]={1.,2.,3.,4.,5.};
norm_vec(v1,5);
for(int i=0;i<5;i++)
cout << v1[i]<< " ";
getch();
}
//=== Результат работы ===
0.13484 0.26968 0.40452 0.53936 0.6742
Пример 9.8. Вычисление скалярного произведения двух векторов.
#include <stdio.h>
#include <conio.h>
double scal_prod(double *a, double *b,int n)
{ double s=0;
for(int i=0; i<n; i++) s += a[i]*b[i];
return s;
}
void main()
{ double v1[5]={1.,2.,3.,4.,5.};
printf("scal_prod=%f",scal_prod(v1,v1,5));
getch();
}
//=== Результат работы ===
scal_prod=55.000000
Пример 9.9. Сумма векторов.
#include <stdio.h>
#include <conio.h>
void sum_vec(double *a,double *b,double *c,int n)
{ for(int i=0; i<n; i++) c[i]=a[i]+b[i]; }
void main()
{ double v1[5]={1.,2.,3.,4.,5.};
double v2[5]={1.,0.,1.,0.,1.};
double v3[5];
sum_vec(v1,v2,v3,5);
for(int i=0;i<5;i++)
printf("%3.0f",v3[i]);
getch();
}
//=== Результат работы ===
2 2 4 4 6
9.2.2.Работа с матрицами
Работу с двумерными массивами можно организовать двумя способами. Во-первых, операции над элементами двумерных массивов можно свести к операциям над одномерными массивами, используя приведенные индексы. Во-вторых, можно воспользоваться указателями на строки матрицы (как известно, имя массива одновременно является указателем на ее первую строку). Мы приведем примеры программ, демонстрирующие оба подхода.
Пример 9.10. Формирование единичной матрицы с приведенными индексами.
#include <stdio.h>
#include <math.h>
#include <conio.h>
void eye(int *a, int n)
{ int i,j;
for(i=0; i<n; i++)
for(j=0; j<n;j++)
{ if(i==j) a[i*n+j]=1;
else a[i*n+j]=0;
}
}
void main()
{ int i,j,v[5][5];
eye((int*)v,5);
for(i=0;i<5;i++)
{ for(j=0;j<5;j++)
printf("%3d",v[i][j]);
printf("\n");
}
getch();
}
//=== Результат работы
Обратите внимание на то, что при обращении к функции eye указатель v приводится к типу (int *). После этого указатель будет "смотреть" на элементы массива, а не на его строки.
Пример 9.11. Сложение квадратных матриц. Поскольку в операции сложения участвуют n2 одноименных компонент матриц-слагаемых, то матрицы можно рассматривать как длинные вектора и производить сложение как с векторами:
#include <stdio.h>
#include <math.h>
#include <conio.h>
void add_mat(int *a,int *b,int *c,int n)
{ int i;
for(i=0; i<n*n; i++)
c[i]=a[i]+b[i];
}
void main()
{ int i,j,v3[3][3];
int v1[3][3]={{1,2,3},{4,5,6},{7,8,9}};
int v2[3][3]={{0,0,1},{0,0,2},{0,0,3}};
add_mat((int*)v1,(int*)v2,(int*)v3,3);
for(i=0;i<3;i++)
{ for(j=0;j<3;j++)
printf("%3d",v3[i][j]);
printf("\n");
}
getch();
}
//=== Результат работы ===
Пример 9.12.Умножение квадратных матриц с использованием приведенных индексов.
#include <stdio.h>
#include <conio.h>
void mult_mat(int *a,int *b,int *c,int n)
{ int i,j,k,s;
for(i=0; i<n; i++)
for(j=0; j<n;j++)
{ s=0;
for(k=0;k<n;k++)
s += a[i*n+k]*b[k*n+j]; //s=s+ai,k*bk,j
c[i*n+j]=s; //ci,j=s
}
}
void main()
{ int i,j,v3[2][2];
int v1[2][2]={{1,2},{3,4}};
int v2[2][2]={{5,6},{7,8}};
mult_mat((int*)v1,(int*)v2,(int*)v3,2);
for(i=0;i<2;i++)
{ for(j=0;j<2;j++)
printf("%4d",v3[i][j]);
printf("\n");
}
getch();
}
//=== Результат работы ===
Пример 9.13. Транспонирование матрицы с использованием массива указателей на строки.
#include <stdio.h>
#include <conio.h>
void transp(int *p[],int n)
{ int tmp,i,j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
{ tmp=p[i][j]; p[i][j]=p[j][i]; p[j][i]=tmp; }
}
void main()
{ int v[4][4]={{ 1, 2, 3, 4},
{ 5, 6, 7, 8},
{ 9,10,11,12},
{13,14,15,16}};
//массив указателей на строки
int *p[4]={(int *)&v[0],(int *)&v[1],(int *)&v[2],(int *)&v[3]};
transp(p,4);
for(int i=0; i<4; i++)
{ for(int j=0;j<4;j++)
printf("%3d",v[i][j]);
printf("\n");
}
getch();
}
//=== Результат работы ===
Массив указателей p на строки двумерного массива v может быть сформирован и другими способами:
int *p[4]={(int *)v,(int *)(v+1),(int *)(v+2),(int *)(v+3)};
int *p[4]={v[0],v[1],v[2],v[3]};
int *p[4]={*v,*(v+1),*(v+2),*(v+3)};
Очевидно, что указатель p[0] "смотрит" на элемент v[0][0]. Поэтому указатель p[0][1]=p[0]+1 "смотрит" на элемент v[0][1], указатель p[0][2] – на элемент v[0][2] и т.д. Можно было бы видоизменить заголовок функции transp следующим образом:
void transp(int **p,int n)
Все эти модификации ничего не меняют в алгоритмах работы программ.