- •Содержание
- •Лекция 1. Общее знакомство
- •Происхождение языка Си
- •Достоинства языка Си
- •Будущее языка Си
- •Использование языка Си
- •Использование текстового редактора для подготовки программ
- •Исходные и выполняемые файлы
- •Пример простой программы на языке Си
- •Пояснения к программе
- •Первый просмотр
- •Второй просмотр
- •Структура простой программы
- •Дополнительный пример
- •Лекция 2. Данные, символьные строки, директива #define
- •Основные типы данных
- •Описание различных типов, переменные и константы
- •Символьные строки
- •Препроцессор языка Си
- •Лекция 3. Операции
- •Основные операции
- •Операция вычитания: -
- •Операция изменения знака: -
- •Операция умножения: *
- •Операция деления: /
- •Дополнительные операции
- •Операция деления по модулю: %
- •Операция уменьшения: --
- •Перечень операций языка Си
- •Операции, уровень приоритета которых равен 1
- •Операция уменьшения: --
- •Операция вычитания: -
- •Операции, уровень приоритета которых равен 5
- •Операции, уровень приоритета которых равен 6
- •Операции, уровень приоритета которых равен 7
- •Операция, уровень приоритета которой равен 8
- •Операция, уровень приоритета которой равен 12
- •Операция логическое или: ||
- •Операция, уровень приоритета которой равен 13
- •Операция условный оператор: ?
- •Операция, уровень приоритета которой равен 14
- •Операция присваивания
- •Операция, уровень приоритета которой равен 15
- •Операция запятая: ,
- •Лекция 4. Операторы
- •Выражения
- •Простейшие выражения
- •Операторы
- •Составные операторы
- •Оператор цикла while
- •Изучение и использование функций printf( ) и scanf( )
- •Применение функции scanf( )
- •Лекция 5. Преобразование типов
- •Эквивалентность типов
- •Преобразование типов
- •Разбор программы
- •Операция приведения
- •Неявное преобразование типа
- •Арифметические преобразования
- •Явные преобразования типов
- •Синтаксис типов
- •Лекция 6. Функции и переключение ввода-вывода
- •Ввод и вывод одного символа
- •Чтение одной строки
- •Чтение файла
- •Переключение и работа с файлами
- •Переключение ввода
- •Комбинированное переключение
- •Операционные системы, отличные от oc unix
- •Лекция 7. Выбор вариантов
- •Выбор вариантов
- •Оператор if
- •Расширение оператора if
- •Операции отношения
- •Что такое истина
- •Осложнение с понятием истина
- •Логические операции
- •Операция условия: ?:
- •Множественный выбор
- •Лекция 8. Циклы и другие управляющие средства. Структурное программирование
- •Структурное программирование
- •Цикл с предусловием
- •Цикл со счетчиком
- •Цикл с постусловием
- •Другие управляющие операторы
- •Оператор break
- •Оператор continue
- •Оператор goto
- •Лекция 9. Функции
- •Создание и использование функций
- •Аргументы функции
- •Возвращение значений
- •Локальные переменные
- •Нахождение адресов
- •Указатели, первое знакомство
- •Операция косвенной адресации *
- •Описание указателей
- •Подведем итоги по указателям
- •Функции с переменным количеством аргументов
- •Лекция 10. Классы памяти и разработка программ
- •Классы памяти и область действия
- •Автоматические переменные
- •Внешние переменные
- •Статические переменные
- •Внешние статические переменные
- •Регистровые переменные
- •Лекция 11. Препроцессор языка Си
- •Общие сведения
- •Символические константы: #define
- •Замена идентификаторов
- •Использование аргументов с #define
- •Макроопределение или функция?
- •Включение файла: #include
- •Условная компиляция
- •Вспомогательные директивы Номер строки и имя файла
- •Реакция на ошибки
- •Пустая директива
- •Встроенные макроимена
- •Лекция 12. Массивы и указатели
- •Указатели и массивы
- •Массивы
- •Указатели
- •Динамические объекты
- •Создание динамических объектов
- •Доступ к динамическим объектам
- •Время жизни динамического объекта
- •Связь между указателями и массивами
- •Строки - дополнительные сведения о тесной связи между указателями и массивами
- •Инициализация массивов и классы памяти
- •Функции, массивы и указатели
- •Операции с указателями
- •Лекция 13. Символьные строки и функции над ними
- •Строковые константы
- •Массивы символьных строк и их инициализация
- •Массив и указатель: различия
- •Указатели и строки
- •Ввод-вывод строк
- •Обработка строк
- •Лекция 14. Структуры
- •Определение структурных переменных
- •Доступ к компонентам структуры
- •Поля битов в структурах
- •Объединения
- •Перечисления
- •Переменные структуры
- •Указатели и структуры
- •Массив структур
- •Переименование типов
- •Лекция 15. Библиотека языка Си и файлы ввода-вывода
- •Стандартные библиотечные функции
- •Доступ в библиотеку языка Си
- •Открытие файла: fopen( )
- •Закрытие файла: fclose( )
- •Текстовые файлы с буферизацией
- •Ввод-вывод текстового файла: getc( ), putc( )
- •Ввод-вывод файла: fprintf( ), fscanf( ), fgets( ), fputs( )
- •Функции fprintf( ) и fscanf( )
- •Функция fgets( )
- •Функция fputs( )
- •Функция fseek( )
- •Распределение памяти Функция malloc( )
- •Функция calloc( )
- •Лекция 16. Функции в примерах
- •Функция получения случайных чисел
- •Поиск узлов из простых чисел
- •Матрица инцидентности
- •Структуры данных
- •Очереди
- •Связанные списки
- •Все операции со стеком
- •Подведем итог
- •Дополнения
- •Литература
Структуры данных
Решение комбинаторных задач предполагает выделение структур сложного типа с их последующей реализацией средствами выбранного языка программирования. При этом структура данных может не зависеть от конкретных языковых конструкций (абстрактная структура данных ).
Под структурой данных понимают совокупность элементов фиксированных типов и набор базисных операций, определяющих организацию и способ обработки данных.
Рассмотрим некоторые основные структуры данных.
Стеки
Стеком называется структура данных, загрузка или увеличение элементов для которой осуществляется с помощью указателя стека в соответствии с правилом LIFO ( last-in, first-out - последним введен, первым выведен).
Указатель стека sp (stack pointer) содержит в любой момент времени индекс (адрес) текущего элемента, который является единственным элементом стека, доступным в данный момент времени для работы со стеком (для случая, когда указатель стека всегда задает ячейку, находящуюся непосредственно над его верхним элементом).
Начальная установка:
sp=1;
Загрузка элемента х в стек:
stack[sp]=x;
sp=sp+1;
Извлечение элемента из стека:
sp=sp-1;
x=stack[sp];
Проверка на переполнения и загрузка элемента в стек:
if(sp<=sd) {stack[sp]=x;sp=sp+1}
else// переполнение
Здесь sd - размерность стека.
Проверка наличия элементов и извлечение элемента стека:
if (sp>1){sp=sp-1;x=stack[sp]} //антипереполнение
Чтение данных из указателя стека без извлечения элемента:
x=stack[sp-1];
Очереди
Очередь - одномерная структура данных, для которой загрузка или извлечение элементов осуществляется с помощью указателей начала ( head ) и конца ( tail ) очереди в соответствии с правилом FIFO ( first-in, first-out - первым введен, первым выведен).
Начальная установка:
head=1; tail=1;
Добавление элемента:
queue[tail]=x; tail=tail+1;
if(tail>qd) tail=1;
Здесь qd - размерность очереди.
Исключение элемента:
x=queue[head]; head=head+1;
if(head>qd) tail=1;
Проверка переполнения очереди и включение в нее элемента:
temp=tail+1;
if(temp=head)
{Переполнение}
else {queue[tail]=x; tail=temp}
Проверка наличия элементов и исключение элемента х:
if(head==tail) { очередь пуста}
else{ x=queue[head]; head=head+1;
if(head>qd) head=1;}
Отметим, что, при извлечении элемента из очереди, все элементы могут также перемещаться на один шаг к ее началу.
Связанные списки
Связанный список представляет собой структуру данных, состоящую из узлов (как правило, записей), содержащих указатели на следующий узел. Указатель, который ни на что не указывает, снабжается значением null. Таким образом, в каждый элемент связанного списка добавляется указатель (звено связи).
Приведем основные базисные операции для работы с однонаправленным связанным списком.
Включение элемента после элемента p:
link[q]=link[p];
link[p]=q;
Здесь q - индекс элемента, который должен быть вставлен в список после элемента с индексом.
Исключение преемника элемента x:
if(link[x] != NULL) link[x]=link[link[x]];
else;
{элемент не имеет преемника}
Отметим, что элемент, следующий в списке за элементом x, называется преемником элемента x, а элемент, расположенный перед элементом x, называется предшественником элемента x. Если элемент x не имеет преемника, то содержащемуся в нем указателю присваивается значение null.
Включение элемента y перед элементом x:
prev=0;
while((link[prev]!=null) && (link[prev]!=x)) do
prev=link[prev];
if (link[prev]==x) {
link[prev]=y; link[y]=x;
};
else;
{ элемент x не найден };
Здесь link[0] является началом списка.
Отметим, что исключение последнего элемента из однонаправленного списка связано с просмотром всего списка.
В двунаправленном связанном списке каждый элемент имеет два указателя ( succlink - описывает связь элемента с преемником, predlink - с предшественником).
Приведем основные базисные операции для работы с двунаправленным связанным списком.
Включение элемента перед элементом x:
succlink[y]=x;
predlink[y]=predlink[x];
succlink[predlink[x]]=y;
predlink[x]=y;
Включение элемента y после элемента x:
succlink[y]=succlink[x];
predlink[y]=x;
predlink[succlink[x]]=y;
succlink[x]=y;
Исключение элемента x:
predlink[succlink[x]]=predlink[x];
succlink[predlink[x]]=succlink[x];
Пример 1:
/* В список помещаются цифры 1...10
Вводится число 11, сначала вставляется за цифрой 10,
затем рвется связь между 3 и 4, между ними вставляется число 11.
Пример дает навык работы:
- с динамической памятью;
- создания абстрактной структуры данных - список и
модификации списка;
- со структурами данных;
- с функциями. */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <dos.h>
struct List {
int i;
List *next;
};
/* структура данных, первое поле для хранения целого, второе поле-адрес в динамической памяти*/
List*head=NULL; /* начальный адрес*/
void Hed(int i) /* функция, которая создает очередной элемент списка */
{
if(head==NULL) {
head=( List*)malloc(sizeof(List));
head->i=1;
head->next=NULL;
} else {
struct List *p,*p1;
p=head;
while(p->next!=NULL)
p=p->next;
p1=new List;
p1->i=i;
p1->next=NULL;
p->next=p1;
}
}
int s=0;
void Print(List*p)/* вывод списка на экран */
{
printf(" %d",p->i);
if(p->next!=NULL)Print(p->next);
}
void delist()/* освобождение динамической памяти */
{
List*p;
while(head!=NULL) {
p=head;
head=head->next;
free(p);
}
}
void Vstavka(int i1,int c)
/*вставка нового элемента*/
{
List*p=head,*p1;
while(p->i!=i1)
p=p->next;
p1=new List;
p1->i=c;
p1->next=p->next;
p->next=p1;
}
void main()/* вход в программу */
{
clrscr();/* очистить экран */
for(int i=1;i<=10;i++)
Hed(i);/* создание списка */
Print(head);/* вывод списка на экран */
Vstavka(10,11);
printf("\n");
Print(head);
Vstavka(3,11);
printf("\n");
Print(head);
delist();
getch();
}