- •Тема 1. Алгоритмы и программы 4
- •Тема 2. Характеристика языка Си 6
- •Тема 3. Основы языка Си 11
- •Тема 4.Работа с файлами 33
- •Тема 5.Распределение памяти 40
- •Тема 6. Методы организации данных в памяти эвм 43
- •Тема 7. Некоторые алгоритмы обработки данных 58
- •Тема 1. Алгоритмы и программы Цели и задачи изучения темы
- •1.1.Понятие алгоритма. Понятие программы. Способы записи алгоритмов.
- •1.2.Критерии качества программ
- •1.3.Низкоуровневые и высокоуровневые языки программирования
- •1.4.Принципы структурного программирования
- •Принципы структурного программирования.
- •2.2.Основные характеристики языка Си.
- •2.2.1.Достоинства языка Си
- •2.2.2.Компиляторы и интерпретаторы
- •2.2.3.Сильная типизация
- •2.3.Структура простой программы
- •Вопросы для повторения
- •3.1.2.Основные типы данных
- •3.1.3.Структуры данных
- •3.1.4.Оператор определения имени типа typedef
- •3.1.5.Массивы
- •3.1.6.Указатели
- •3.1.7.Указатели и массивы
- •3.1.8.Внешние и внутренние переменные
- •3.2.Стандартные функции ввода-вывода
- •3.3. Операции, операторы и выражения
- •3.3.1.Оператор присваивания
- •3.3.2.Арифметические операции
- •3.3.3.Операции увеличения и уменьшения
- •3.3.4.Операции сравнения
- •3.3.5.Логические операции
- •3.3.6.Побитовые логические операции
- •3.3.7.Операции сдвига
- •3.3.8.Операции "увеличить на", "домножить на" и т.П.
- •3.3.9.Операции с указателями. Указатели и массивы
- •3.3.10.Операция приведения типа
- •3.4.Управляющие конструкции
- •3.4.1.Фигурные скобки
- •3.4.2.Оператор выбора if и операция условия
- •3.4.3.Оператор множественного выбора switch
- •3.4.4.Оператор цикла while
- •3.4.5.Оператор цикла for
- •3.4.6.Оператор цикла do...While
- •3.5.Данные (более детальные сведения)
- •3.5.1.Структуры
- •3.5.2.Указатели и структуры
- •3.5.3.Структуры и оператор определения имени типа typedef
- •3.5.4.Строки
- •3.5.5.Матрицы и многомерные массивы
- •3.6.Пользовательские функции
- •3.6.1.Определение функций
- •3.6.2.Прототипы функций
- •3.6.3.Аргументы командной строки
- •Вопросы для повторения
- •4.2.Функция открытия файла fopen
- •4.3.Функции бинарного чтения и записи fread и fwrite
- •4.4.Функция закрытия файла fclose
- •4.5.Функции форматного чтения и записи fscanf и fprintf
- •4.6.Другие функции ввода-вывода
- •4.6.1.Функции посимвольного ввода-вывода
- •Int fgetc(file *f); - ввести один символ из файла f.
- •Int fputc(int c, file *f); - записать один символ в файл f.
- •4.6.2.Функции построкового ввода-вывода
- •Char *fgets(char *line,int size, file *f); - ввести строку из файла f.
- •Char *fputs(char *line, file *f); - записать строку в файл f.
- •4.6.3.Функции позиционирования в файле
- •Int fseek(file *f, long offset, int whence); - установить текущую позицию в файле f
- •Long ftell(file *f); - получить текущую позицию в файле f
- •Int feof(file *f); - проверить,достигнут ли конец файла f
- •Функция открытия файла fopen
- •Функции бинарного чтения и записи fread и fwrite
- •Функция закрытия файла fclose
- •5.2.Функции malloc и free
- •5.3.Выделение памяти под матрицы на этапе выполнения программы
- •Функции malloc и free.
- •6.2.Время выполнения программ
- •6.3.Списки
- •6.4.Реализация списков
- •6.5.Стеки
- •6.6.Реализация стеков
- •6.7.Очереди
- •6.8.Реализация очередей
- •6.9.Графы и деревья
- •6.10.Некоторые сд для хранения графов и деревьев
- •Матрица смежности графа, изображенного на рис.6.10
- •Матрица инцидентности графа, изображенного на рис.6.10
- •Матрица весов графа, изображенного на рис.6.11
- •Матрица смежности дерева, изображенного на рис.6.16
- •Вопросы для повторения
- •Реализация стеков.
- •Реализация очередей.
- •7.1.1.Поиск элемента в неупорядоченном массиве
- •7.1.2.Поиск элемента в упорядоченном массиве.
- •7.1.3.Фонетический поиск
- •7.2.Алгоритмы сортировки
- •7.2.1.Сортировка методом пузырька.
- •7.2.2.Сортировка вставками
- •7.2.3.Сортировка выбором
- •7.2.4.Пирамидальная сортировка
- •7.2.5.Быстрая сортировка
- •7.2.6.Сортировка слиянием
- •Этапы слияния файлов f1 и f2
- •7.3.Поиск на графах
- •7.3.1.Поиск в глубину
- •7.3.2.Поиск в ширину
- •7.4.Топологическая сортировка графа
- •7.5.Сетевое планирование
- •Информация о проекте
- •7.5.1.Алгоритм расчета наиболее ранних сроков наступления событий
- •7.5.2.Алгоритм расчета наиболее поздних сроков наступления событий
- •7.5.3.Алгоритм расчета резервов времени
- •Расчет резервов времени
- •Вопросы для повторения
3.5.5.Матрицы и многомерные массивы
Матрицу можно рассматривать как массив элементов типа массив. Например, переменная a представляет матрицу размера 3×3 с вещественными элементами:
double a[3][3];
Для обращения к элементу матрицы надо записать его индексы в квадратных скобках, например, выражение a[i][j] представляет собой элемент матрицы a в строке с индексом i и столбце с индексом j. Элемент матрицы можно использовать в любом выражении как обычную переменную.
Элементы матрицы располагаются в памяти последовательно по строкам. Например, в рассматриваемой матрице сначала идут элементы строки с индексом 0, затем строки с индексом 1, в конце строки с индексом 2. Т.е. элементы матрицы располагаются следующим образом: a[0][0], a[0][1], a[0][2], a[1][0], a[1][1], a[2][2], a[2][0], a[2][1], a[2][2].
Имя матрицы, как и имя массива, это указатель на первый элемент. Например, запись a эквивалентна &a[0][0], запись a+1 эквивалентна &a[0][1] и т.п.
При описании матрицы можно выполнить инициализацию ее элементов:
double a[3][3]={ {10.3, 1.1, 2.3},
{5.2, 6.7, 3.1},
{0.9, 2.3, 9.7}};
Такая реализация матрицы удобна и эффективна. У данной реализации матриц, как и у подобной реализации массивов, есть один существенный недостаток: так можно реализовать только матрицу, размер которой известен заранее, т.е. до начала работы программы на стадии компиляции.
Реализация матриц, размер которых становится известным на стадии выполнения программы, будет рассмотрен в теме 5.
Все, что сказано о матрицах (двумерных массивах), можно обобщить и на трехмерные массивы и т.п.
Трехмерный массив описывается следующим образом:
int a3[10][20][30];
Можно представить данный трехмерный массив в виде массива из десяти элементов. Каждый элемент является двумерным массивом размера 20 на 30.
3.6.Пользовательские функции
3.6.1.Определение функций
В предыдущих разделах уже встречались функции. Пользовательская функция - это функция, определенная пользователем. Общий синтаксис функции следующий:
<тип возвращаемого значения> <имя функции> (<Список формальных параметров>)
Список формальных параметров позволяет описать параметры, передаваемые функции с указанием их типа. Синтаксис данного списка следующий:
<тип параметра 1><идентификатор параметра 1>,<тип параметра 2><идентификатор параметра 2> и т.д.
При вызове функции ей передаются значения фактических параметров. Фактические параметры должны точно соответствовать типу формальных параметров.
Изменение формальных параметров в теле функции не приводит к изменению переменных вызывающей программы, передаваемых функции в качестве фактических параметров. Это обусловлено тем, что при вызове функции значения фактических параметров копируются в стек, т.е. функция работает не с самими переданными переменными, а с копиями их значений. Для пояснения сказанного рассмотрим следующий фрагмент программы:
void f(int x) {
x = 0; // Изменение формального параметра не приводит к
// изменению фактического параметра в вызывающей программе
}
int main() {
int x = 5;
f(x);
// Значение x по-прежнему равно 5
. . .
}
Здесь в функции main вызывается функция f, которой передается значение переменной x, равное пяти. Несмотря на то, что в теле функции f формальному параметру x присваивается значение 0, значение переменной x в функции main не меняется.
Если необходимо, чтобы функция могла изменить значения переменных вызывающей программы, надо передавать ей указатели на эти переменные. Тогда функция может записать любую информацию по переданным адресам. Если в предыдущем примере мы хотим изменять переменную x в теле функции f(), то текст программы должен быть следующий
void f(int *x) {
*x = 0;
}
int main() {
int x = 5;
f(&x);
// Значение x равно 0
. . .
}
Напомним, что в функцию scanf() требуется передавать адрес переменной, значение которой вводится с помощью этой функции.
Если функция должна возвращать некоторое значение, то следует использовать оператор return <возвращаемое значение>. Рассмотрим пример функции, вычисляющей сумму элементов массива состоящего из n элементов.
#define N 5
int a[N]={1,2,3,4,5}
int sum_array(int *x, int n) {
int i,s=0;
for(i=0;i<n;i++) s+=x[i];
return s;
}
int main() {
printf("Сумма элементов массива a=%d",sum_array(a,N));
}
Напомним, что имя массива это указатель на этот массив (указатель на первый элемент массива). Поэтому если в качестве аргумента функции используется имя массива, то функции передается указатель на этот массив. Затем функция использует этот указатель для выполнения изменений в переданном массиве.
В рассмотренном примере заголовок функции производящей суммирование элементов массива был определен следующим образом:
int sum_array(int *x, int n)
Для того чтобы подчеркнуть тот факт, что параметром функции является массив, можно было использовать следующий заголовок:
int sum_array(int x[], int n).
Записи int *x и int x[] эквивалентны.