- •1.Базовые элементы языка с. Алфавит и словарь языка
- •2. Основные типы данных. Классификация их типов. Модификация базовых типов.
- •3. Константы.
- •4. Переменные.
- •5. Структура с - программы. Понятие локальных и глобальных переменных. Функция main().Директивы препроцессора (#include и #define). Комментарии.
- •6. Операции языка с. Арифметические, логические операции. Поразрядные операции.
- •7. Операции языка с. Операция присваивания и отношения. Операция определения размера. Оператор последовательного вычисления.
- •8. Операции языка с. Условная операция. Операция (), операция [].
- •9. Приоритет операций и порядок вычислений.
- •11. Ввод-вывод символов
- •12. Форматированный ввод-вывод. Модификаторы формата. Спецификаторы преобразования. Подавление ввода.
- •13. Операторы языка с. Условные операторы (if и switch).
- •16. Одномерные массивы.
- •17. Строковый литерал. Чтение и запись строк.
- •18. Двухмерные массивы. Массивы строк.
- •20.Способы доступа к элементам массива
- •21. Понятие указателя. Инициализация указателей.
- •22. Указательные переменные. Операции получения адреса (&) и раскрытия ссылки(*).
- •23. Указательные выражения. Адресная арифметика.
- •Динамическое выделение памяти для массивов.
- •Функции. Определения функций. Оператор return.
- •Тип_результата id_функции (список);
- •Функции. Прототипы функций.
- •Тип_результата id_функции (список);
- •Функции. Вызов функций: вызов по значению и по ссылке.
- •Тип_результата id_функции (список);
- •Передача массива в функцию.
- •Классы памяти. Область видимости.
- •Аргументы функции main(): argv и argc.
- •Вызов библиотечных функций.
- •Директива препроцессора #define: создание макрофункций с помощью директивы #define.
- •Директивы условной компиляции #if, #else, #elif, #endif, #ifdef, #ifndef.
- •Понятие структуры. Доступ к членам структуры.
- •Присваивание структур.
- •Id_структуры . Id_поля
- •Передача членов структур функциям. Передача целых структур функциям.
- •Указатели на структуры. Средство typedef.
- •Понятия объединения и перечисления. Битовые поля.
- •Основы файловой системы. Стандартные потоки. Указатель файла. Открытие файла. Закрытие файла.
Основы файловой системы. Стандартные потоки. Указатель файла. Открытие файла. Закрытие файла.
Потоки
Потоки представляют собой удобный переносимый способ чтении и записи данных. Они обеспечивают гибкие и эффективные средства для ввода/вывода.
Поток - это байтовая последовательность, передаваемая в процессе ввода, которая управляется через указатель на поток.
Потоковый ввод/вывод - буферизированный: это означает, что блок данных фиксированного размера читается/пишется в файл не посредственно, а через временную область хранения (буфер).
Это повышает эффективность ввода/вывода, но будьте осторожны: данные, записанные в буфер, не появятся в файле или на устройстве, пока буфер не будет очищен. Всякое неуспешное завершение программы может вызвать проблемы. Потоковый ввод/вывод эффективен для символов и строк.
Основы файловой системы
Основным понятием, связанным с информацией на внешних устройствах ЭВМ, является понятие файла. Всякая операция ввода/вывода трактуется как операция обмена с файлами: Ввод- это чтение из файла в оперативную память; вывод - это запись из оперативной памяти в файл. Сначала нужно открыть поток перед выполнением каких-либо операций ввода/вывода, затем выполнить операции доступа (чтения/записи) и потом закрыть.
В языке Си файл - это байтовая последовательность, заканчивающаяся EOF.
В языке Си отсутствует понятие типа файла.
Указатель файла
Работа с файлами начинается с объявления указателя на поток:
FILE *имя_указателя;
FILE *fp;
FILE внутренняя C-структура данных языка Си,которая используется для работы с потоками и определена в stdio.h. Стуктура FILE содержит следующую информацию: указатель на буфер, указатель текущей позиции в потоке.
Открытие файла
Открыти файла возможно при помощи функции fopen(), синтаксис которой следующий:
FILE *fopen(char *name, char *mode)
fopen возвращает указатель на структуру FILE. Строка name содержит имя файла. Строка mode определяет способ доступа. Если файл не может быть открыт по какой-либо причине, функция возвращает NULL.
Способы доступа включают:
"r" - чтение,
"w" - запись,
"a" - добавление в конец.
Также способ доступа может включать:
"t" - текстовый,
"b" - бинарный.
Для открытия файла myfile.dat на чтение необходимо:
FILE *stream, *fopen();
/* описание потока и прототипа fopen */
stream = fopen("myfile.dat","r");
Необходимо проверять, что файл открылся:
if ((stream = fopen("myfile.dat", "r")) == NULL)
{ printf("Нельзя открыть %s\n", "myfile.dat");
exit(1);
}
......
Закрытие файла
Для того, чтобы закрыть файл, используется функция fclose. Ее синтаксис:
fclose(FILE *stream)
Пример. Ввести матрицу из файла inputfile.dat.Файл входных данных имеет следующую структуру:
n - количество строк
m - количество столбцов
a a ... a
...
a a ... a,
где
n - количество строк
m - количество стобцов
a - элементы матрицы.
И вывести ее в файл outputfile.dat.
#include <stdio.h> void main(){ int A[100][100]; // массив 100х100 int i,j; // индексы для перемещения по массиву int n; // кол-во строк int m; // кол-во столбцов FILE *fp;
// открытие файла на чтение if ((fp = fopen("inputfile.dat", "r")) == NULL) { printf("Нельзя открыть %s\n", "inputfile.dat"); return; } // ввод размеров матрицы fscanf(fp,"%d",&n); fscanf(fp,"%d",&m); // ввод значений матрицы for (i=0;i<n;i++) for (j=0;j<n;j++){ fscanf(fp,"%d",&A[i][j]); } fclose(fp); // открытие файла на запись if ((fp = fopen("outputfile.dat", "w")) == NULL) { printf("Нельзя открыть %s\n", "outputfile.dat"); return; } // вывод значение матрицы for (i=0;i<n;i++){ for (j=0;j<n;j++) fprintf(fp,"%d ",A[i][j]); fprintf(fp,"\n"); } fclose(fp);
}
Форматированный ввод-вывод в файл.
С помощью функции форматного вывода можно формировать на диске текстовый файл с результатами вычислений, представленными в символьном виде. В дальнейшем этот файл может быть просмотрен на экране, распечатан на принтере, отредактирован с помощью текстового редактора. Общий вид функции форматного вывода:
int fprintf (указатель_на_поток, форматная_строка, список_переменных);
Использовавшаяся нами ранее функция printf () для организации вывода на экран является частным вариантом функции fprintf (). Функция printf () работает лишь со стандартным потоком stdin, который всегда связывается системой с дисплеем. Не будет ошибкой, если в программе вместо printf () написать fprintf (stdin, …).
Правила использования спецификаторов форматов при записи в файлы на диске точно такие же, как и при выводе на экран.
Пример 5. Составим программу, по которой будет рассчитана и записана в файл таблица квадратных корней для целых чисел от 1 до 10. Для контроля эта же таблица выводится на экран.
//Таблица квадратных корней
#include <stdio.h>
#include <iostream.h>
#include <math.h>
void main()
{ FILE *fp;
int x;
fp = fopen(“test.dat”, “w”);
//Вывод на экран и в файл шапки таблицы
printf(“\t Таблица квадратных корней \n”);
fprintf(fp, “\t Таблица квадратных корней \n ”);
printf(“\t x\t\tsqrt(x) \n”);
fprintf(fp, “\t x\t\tsqrt(x) \n ”);
\\Вычисление и вывод таблицы квадратных корней
\\на экран и в файл
for(x = 1; x<=10; x++)
{ printf(“\t%f\t%f\n”, float(x), sqrt(float(x)));
fprintf(fp, “\t%f\t%f\n”, float(x), sqrt(float(x)));
}
fclose(fp);
}
Форматный ввод из текстового файла осуществляется с помощью функции fscanf (), общий формат которой выглядит следующим образом:
int fscanf(указатель_на_поток, форматная_строка, список_адресов_переменных);
Данной функцией удобно пользоваться в тех случаях, когда исходные данные заранее подготавливаются в текстовом файле.
Запись и чтение символов. Ввод/вывод строк. Стирание файлов.
Запись и чтение символа
Функции записи и чтения символа подобны fprintf и fscanf, только пишут и читают не в поток/из потока, а в строку/из строки:
int sprintf(char *string, char *format, args..)
int sscanf(char *string, char *format, args..)
Пример:
float full_tank = 47.0;
float miles = 300;
char miles_per_litre[80];
sprintf( miles_per_litre,"Miles per litre = %2.3f", miles/full_tank);
Ввод/вывод строк
Стандартная библиотека содержит функцию fgets. В результате обращения
fgets(line, maxline, fp)
следующая строка ввода (включая символ новой строки) считывается из файла fp в символьный массив line; самое большое maxline_1 символ будет прочитан. Результирующая строка заканчивается символом \0. Нормально функция fgets возвращает line; в конце файла она возвращает null.
Предназначенная для вывода функция fputs записывает строку (которая не обязана содержать символ новой строки) в файл:
fputs(line, fp)
Очистка буфера потока
Функция fflush очищает буфер потока:
fflush(FILE *stream)
Понятия очереди, стеков, связанных списков и деревьев.
Понятия очереди, стеков, связанных списков и деревьев
В зависимости от метода доступа к элементам линейного списка различают разновидности линейных списков называемые стеком, очередью и двусторонней очередью.
Стек – это конечная последовательность некоторых однотипных элементов – скалярных переменных, массивов, структур или объединений, среди которых могут быть и одинаковые. Стек обозначается в виде: S= и представляет динамическую структуру данных; ее количество элементов заранее не указывается и в процессе работы, как правило, изменяется. Если в стеке элементов нет, то он называется пустым и обозначается S=< >.
Допустимыми операциями над стеком являются:
- проверка стека на пустоту S=< >,
- добавление нового элемента Sn+1 в конец стека - преобразование < S1,...,Sn> в < S1,...,Sn+1>;
- изъятие последнего элемента из стека - преобразование < S1,...,Sn-1,Sn> в < S1,...,Sn-1>;
- доступ к его последнему элементу Sn, если стек не пуст.
Таким образом, операции добавления и удаления элемента, а также доступа к элементу выполняются только в конце списка. Стек можно представить как стопку книг на столе, где добавление или взятие новой книги возможно только сверху.
Очередь – это линейный список, где элементы удаляются из начала списка, а добавляются в конце списка (как обыкновенная очередь в магазине).
Двусторонняя очередь – это линейный список, у которого операции добавления и удаления элементов и доступа к элементам возможны как вначале так и в конце списка. Такую очередь можно представить как последовательность книг стоящих на полке, так что доступ к ним возможен с обоих концов.
Реализация стеков и очередей в программе может быть выполнена в виде последовательного или связанного хранения. Рассмотрим примеры организации стека этими способами.
Одной из форм представления выражений является польская инверсная запись, задающая выражение так, что операции в нем записываются в порядке выполнения, а операнды находятся непосредственно перед операцией.
Например, выражение
(6+8)*5-6/2
в польской инверсной записи имеет вид
6 8 + 5 * 6 2 / -
Особенность такой записи состоит в том, что значение выражения можно вычислить за один просмотр записи слева направо, используя стек, который до этого должен быть пуст. Каждое новое число заносится в стек, а операции выполняются над верхними элементами стека, заменяя эти элементы результатом операции. Для приведенного выражения динамика изменения стека будет иметь вид
S = < >; <6>; <6,8>; <14>; <14,5>; <70>;
<70,6>; <70,6,2>; <70,3>; <67>.
Ниже приведена функция eval, которая вычисляет значение выражения, заданного в массиве m в форме польской инверсной записи, причем m[i]>0 означает неотрицательное число, а значения m[i]<0 - операции. В качестве кодировки операций сложения, вычитания, умножения и деления выбраны отрицательные числа -1, -2, -3, -4. Для организации последовательного хранения стека используется внутренний массив stack. Параметрами функции являются входной массив a и его длина l.
float eval (float *m, int l)
{ int p,n,i;
float stack[50],c;
for(i=0; i < l ;i++)
if ((n=m[i])<0)
{ c=st[p--];
switch(n)
{ case -1: stack[p]+=c; break;
case -2: stack[p]-=c; break;
case -3: stack[p]*=c; break;
case -4: stack[p]/=c;
}
}
else stack[++p]=n;
return(stack[p]);
}
Рассмотрим другую задачу. Пусть требуется ввести некоторую последовательность символов, заканчивающуюся точкой, и напечатать ее в обратном порядке (т.е. если на входе будет "ABcEr-1.", то на выходе должно быть "1-rEcBA"). Представленная ниже программа сначала вводит все символы последовательности, записывая их в стек, а затем содержимое стека печатается в обратном порядке.
Это основная особенность стека - чем позже элемент занесен в стек, тем раньше он будет извлечен из стека. Реализация стека выполнена в связанном хранении при помощи указателей p и q на тип, именованный именем STACK.
#include
typedef struct st /* объявление типа STACK */
{ char ch;
struct st *ps; } STACK;
main()
{
STACK *p,*q;
char a;
p=NULL;
do // заполнение стека
{ a=getch();
q=malloc(sizeof(STR1));
q->ps=p; p=q;
q->ch=a;
} while(a!= ’. ’);
do // печать стека
{ p=q->ps;free(q);q=p;
printf("%c",p->ch);
} while(p->ps!=NULL);
}
Упорядоченные списки А и В длин М и N сливаются в один упорядоченный список С длины М+N, если каждый элемент из А и В входит в С точно один раз. Так, слияние списков А=<6,17,23,39,47> и В=<19,25,38,60> из 5 и 4 элементов дает в качестве результата список С=<6,17,19,23,25,38,39,47, 60> из 9 элементов.
Для слияния списков А и В список С сначала полагается пустым, а затем к нему последовательно приписывается первый узел из А или В, оказавшийся меньшим и отсутствующий в С.
Составим функцию для слияния двух упорядоченных, расположенных рядом частей массива s. Параметром этой функции будет исходный массив s с выделенными в нем двумя расположенными рядом упорядоченными подмассивами: первый с индекса low до индекса low+l, второй с индекса low+l+1 до индекса up, где переменные low, l, up указывают месторасположения подмассивов. Функция merge осуществляет слияние этих подмассивов, образуя на их месте упорядоченный массив с индексами от low до up.
/* слияние списков */
double *merge(double *s, int low, int up, int l)
{
double *b,*c,v;
int i,j,k;
b=calloc(l,sizeof(double));
c=calloc(up+1-l,sizeof(double));
for(i=low;i< low+l;i++)
b[i-low]=s[i];
for(i=0;i< up-l;i++)
c[i]=s[i+l+low];
v=(b[l]=(c[up-l]=(s[low+l-1]>s[up-1]) ? (s[low+l-1]+1) : (s[up-1]+1)));
i=(j=0);
k=low;
while(b[i]< v||c[j]< v)
{ if(b[i]< c [j]) s[k]=b[i++];
else s[k]=c[j++];
k++;
}
return (s);
}