Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lektsii_po_si.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
71.13 Кб
Скачать

Указатели.

Указатель – это переменная, значением которой является адрес, по которому располагаются данные. Адрес – это номер ячейки памяти, в которой или с которой располагаются данные.

По типу данных в СИ указатели делятся на:

  Типизированный указатель – указатель, содержащий адрес данных определенного типа (системного или пользовательского).

  Не типизированный указатель – указатель, содержащий адрес данных неопределенного типа (просто адрес).

  объявление указателя;

  установка указателя;

обращение к значению, расположенному по указателю. Объявление (описание) указателя в языке СИ имеет следующий вид:

  тип [near|far] *имя [=значение];

Указатель в СИ при объявлении можно инициализировать, указав через знак присвоения соответствующее значение. Данное значение должно быть адресом, записанном в одном из следующих виде:

  •нулевое значение (идентификатор NULL);

  •другой указатель;

  •адрес переменной (через операцию взятия адреса);

  •выражение, представляющее собой арифметику указателей;

  •адрес, являющийся результатом выделения динамической памяти.

Пример:

#include <stdio.h>

int main()

{

int var; // обычная целочисленная переменная

int *ptrVar; // целочисленный указатель (ptrVar должен быть типа int, так как он будет ссылаться на переменную типа int)

ptrVar = &var; // присвоили указателю адрес ячейки в памяти, где лежит значение переменной var

scanf( "%d", &var ); // в переменную var положили значение, введенное с клавиатуры

printf( "%d\n", *ptrVar ); // вывод значения через указатель

getchar();

}

Результат выполнения: 6 6

Лекция №3.

Функции.

Функция – это синтаксически выделенный именованный программный модуль, выполняющий определенное действие или группу действий. Каждая функция имеет свой интерфейс и реализацию. Интерфейс функции – заголовок функции, в котором указывается название функции, список ее параметров и тип возвращаемого значения.

Описание функции на языке СИ осуществляется в любом месте программы вне описания других функций и состоит из трех элементов:

  1. прототип функции;

  2. заголовок функции;

  3. тело функции.

Прототип функции – необязательная часть описания функции, предназначенная для объявления некоторой функции, интерфейс которой соответствует данному прототипу.Объявление прототипа имеет следующий вид:

  тип имя(список типов формальных параметров);

Параметры функции – значения, передаваемые в функцию при ее вызове.

Заголовок функции – описание интерфейсной части функции, которая содержит: тип возвращаемого значения, имя функции и список формальных параметров функции. Синтаксис объявления заголовка функции:

  тип имя(список формальных параметров)

Примеры заголовков функций:

  int func(int i, double x, double y)

  void func(int ind, char *string)

  double func(void)

Тело функции – часть-реализация, содержащая программный код, выполняемый при вызове функции. Тело функции всегда следует сразу после заголовка функции (разделять их нельзя) и заключено в фигурные скобки.

Пример:

Реализация функции на СИ для вычисления факториала числа.

  double factorial(unsigned);

  ...

  double factorial(unsigned num)

  {

   double fact = 1.0;

   for(unsigned i=1;i<=num;i++)

    fact *= (double)i;

   return fact;

  }

Структуры.

Структура – это сложный тип данных представляющий собой упорядоченное в памяти множество элементов различного типа. Каждый элемент в структуре имеет свое имя и называется полем.

Объявление в СИ структуры имеет вид:

  struct [имя типа]

  {

   поле_1;

   поле_2;

   ...

   поле_N;

  } [список переменных];

 Объявление полей структуры возможно только без инициализации. Если несколько полей следующих друг за другом в описании структуры имеют один и тот же тип, то для их описания можно использовать синтаксис объявления нескольких переменных одного и того же типа.

Файлы.

Файл – это именованная область данных на каком-либо носителе информации. Типы файлов (относительно языка «СИ»):   текстовые;   бинарные. Основные операции производимые над файлами: 1.Открытие файлов. 2.Чтение и запись данных. 3.Закрытие файлов.

Дополнительные операции: 1.Навигация по файлу. 2.Обработка ошибок работы с файлами. 3.Удаление и переименование файлов. 4.Описание переменной

Режимы открытия файлов с СИ

r

только чтение

w

Только запись. Если файл существовал, то он переписывается.

a

Добавление: открытие файла для записи в конец, или создание файла.

r+

Открывает файл для обновления (чтение и запись).

w+

Открывает файл для обновления (чтение и запись), переписывая файл, если он существует.

a+

Открывает файл для записи в конец файла или для чтения.

Перенаправление потоков  FILE * freopen(const char *filename, const char *mode, FILE *stream); Функция возвращает:  Указатель на файл – все нормально,  NULL – ошибка переопределения.

Закрытие файла  int fclose(FILE *stream);  stream - указатель на открытый файл. Функция возвращает:  0 – файл успешно закрыт.  1 – произошла ошибка закрытия файла. Проверка на достижение конца файла  int feof(FILE *stream);  stream - указатель на открытый файл. Функция возвращает:  0 – если конец файла еще не достигнут.  !0 – достигнут конец файла.

Открытие текстовых файлов Во втором параметре дополнительно указывается символ t (необязательно):  rt, wt, at, rt+, wt+, at+

Чтение из текстового файла

Форматированное чтение  int fscanf(FILE *stream, const char * format, [arg] ...); Функция возвращает:  >0 – число успешно прочитанных переменных,  0 – ни одна из переменных не была успешно прочитана,  EOF – ошибка или достигнут конец файла. Чтение строки  char * fgets(char * buffer, int maxlen, FILE *stream); Функция возвращает:  buffer – все нормально,  NULL – ошибка или достигнут конец файла. Чтение строки  char * fgets(char * buffer, int maxlen, FILE *stream); Функция возвращает:  buffer – все нормально,  NULL – ошибка или достигнут конец файла. Чтение символа  int fgetc(FILE *stream); Функция возвращает:  код символа – если все нормально,  EOF – если ошибка или достигнут конец файла. Помещение символа обратно в поток  int ungetc(int c, FILE *stream); Функция возвращает:  код символа – если все успешно,  EOF – произошла ошибка.

Запись в текстовый файл в СИ

Форматированный вывод  int fprintf(FILE *stream, const char *format, [arg] ...); Функция возвращает:  число записанных символов – если все нормально,  отрицательное значение – если ошибка. Запись строки  int fputs(const char *string, FILE *stream); Функция возвращает:  число записанных символов – все нормально,  EOF – произошла ошибка. Запись символа  int fputc(int c, FILE *stream); Функция возвращает:  код записанного символа – все нормально,  EOF – произошла ошибка. Открытие бинарных файлов  Во втором параметре дополнительно указывается символ b (обязательно):rb, wb, ab, rb+, wb+, ab+ Чтение из бинарных файлов  size_t fread(void *buffer, size_t size, size_t num,FILE *stream); Функция возвращает количество прочитанных блоков. Если оно меньше num, то произошла ошибка или достигнут конец файла. Запись в бинарный файл  size_t fwrite(const void *buffer, size_t size, size_t num, FILE *stream); Функция возвращает количество записанных блоков. Если оно меньше num, то произошла ошибка.

Навигация по файлу

Чтение текущего смещения в файле:  long int ftell(FILE *stream); Изменение текущего смещения в файле:  int fseek(FILE *stream, long int offset, int origin);  SEEK_SET (0) – от начала файла.  SEEK_CUR (1) – от текущей позиции.  SEEK_END (2) – от конца файла. Функция возвращает:  0 – все нормально,  !0 – произошла ошибка. Перемещение к началу файла:  void rewind(FILE *stream); Чтение текущей позиции в файле:  int fgetpos(FILE *stream, fpos_t *pos); Установка текущей позиции в файле:  int fsetpos(FILE *stream, const fpos_t *pos); Функции возвращают:  0 – все успешно,  !0 – произошла ошибка. Структура fpos_t:  typedef struct fpos_t {   long off;   mbstate_t wstate;  } fpos_t; Получение признака ошибки:  int ferror(FILE *stream); Функция возвращает ненулевое значение, если возникла ошибка. Функция сброса ошибки:  void clearerr(FILE *stream); Функция вывода сообщения об ошибке:  void perror(const char *string);

Буферизация

Функция очистки буфера:  int fflush(FILE *stream); Функция возвращает:  0 – все нормально.  EOF – произошла ошибка. Функция управления буфером:  void setbuf(FILE *stream, char * buffer); Создает буфер размером BUFSIZ. Используется до ввода или вывода в поток.

Временные файлы

Функция создания временного файла:  FILE * tmpfile(void); Создает временный файл в режиме wb+. После закрытия файла, последний автоматически удаляется. Функция генерации имени временного файла:  char * tmpnam(char *buffer);

Удаление и переименование

Функция удаления файла:  int remove(const char *filename); Функция переименования файла:  int rename(const char *fname, const char *nname); Функции возвращают:  0 – в случае успеха,  !0 – в противном случае.

Лекция №4.

Стек.

Стек (stack) является как бы противоположностью очереди, поскольку он работает по принципу "последним пришел — первым вышел" (last-in, first-out, LIFO). Чтобы наглядно представить себе стек, вспомните стопку тарелок. Первая тарелка, стоящая на столе, будет использована последней, а последняя тарелка, положенная наверх — первой. Стеки часто применяются в системном программном обеспечении, включая компиляторы и интерпретаторы.

При работе со стеками операции занесения и извлечения элемента являются основными. Данные операции традиционно называются "затолкать в стек" (push) и "вытолкнуть из стека" (pop). Поэтому для реализации стека необходимо написать две функции: push(), которая "заталкивает" значение в стек, и pop(), которая "выталкивает" значение из стека. Также необходимо выделить область памяти, которая будет использоваться в качестве стека. Для этой цели можно отвести массив или динамически выделить фрагмент памяти с помощью функций языка С, предусмотренных для динамического распределения памяти. Как и в случае очереди, функция извлечения получает из списка элемент и удаляет его, если он не хранится где-либо еше. Ниже приведена общая форма функций push() и pop(), работающих с целочисленным массивом. Стеки данных другого типа можно организовывать, изменив базовый тип данных массива.

int stack[MAX];

int tos=0; /* вершина стека */

/* Затолкать элемент в стек. */

void push(int i)

{

if(tos >= MAX) {

printf("Стак полон\n");

return;

}

stack[tos] = i;

tos++;

}

/* Получить верхний элемент стека. */

int pop(void)

{

tos--;

if(tos < 0) {

printf("Стек пуст\n");

return 0;

}

return stack[tos];

}

Переменная tos ("top of stack" — "вершина стека") содержит индекс вершины стека. При реализации данных функций необходимо учитывать случаи, когда стек заполнен или пуст. В нашем случае признаком пустого стека является равенство tos нулю, а признаком переполнения стека — такое увеличение tos, что его значение указывает куда-нибудь за пределы последней ячейки массива.

Пример работы со стеком.

Действие

Содержимое стека

push(A)

A

push(B)

В А

push(C)

C B A

рор() извлекает С

В А

push(F)

F В А

рор() извлекает F

В А

рор() извлекает В

А

рор() извлекает А

пусто

Стек будет размешаться в динамически распределяемой памяти, а не в массиве фиксированного размера. Хотя применение динамического распределения памяти и не требуется в таком простом примере, мы увидим, как использовать динамическую память для хранения данных стека.

Пример:

/* Простой калькулятор с четырмя действиями. */

#include <stdio.h>

#include <stdlib.h>

#define MAX 100

int *p; /* указатель на область свободной памяти */

int *tos; /* указатель на вершину стека */

int *bos; /* указатель на дно стека */

void push(int i);

int pop(void);

int main(void)

{

int a, b;

char s[80];

p = (int *) malloc(MAX*sizeof(int)); /* получить память для стека */

if(!p) {

printf("Ошибка при выделении памяти\n");

exit(1);

}

tos = p;

bos = p + MAX-1;

printf("Калькулятор с четырьмя действиями\n");

printf("Нажмите 'q' для выхода\n");

do {

printf(": ");

gets(s);

switch(*s) {

case '+':

a = pop();

b = pop();

printf("%d\n", a+b);

push(a+b);

break;

case '-':

a = pop();

b = pop();

printf("%d\n", b-a);

push(b-a);

break;

case '*':

a = pop();

b = pop();

printf("%d\n", b*a);

push(b*a);

break;

case '/':

a = pop();

b = pop();

if(a==0) {

printf("Деление на 0.\n");

break;

}

printf("%d\n", b/a);

push(b/a);

break;

case '.': /* показать содержимое вершины стека */

a = pop();

push(a);

printf("Текущее значение на вершине стека: %d\n", a);

break;

default:

push(atoi(s));

}

} while(*s != 'q');

return 0;

}

/* Занесение элемента в стек. */

void push(int i)

{

if(p > bos) {

printf("Стек полон\n");

return;

}

*p = i;

p++;

}

/* Получение верхнего элемента из стека. */

int pop(void)

{

p--;

if(p < tos) {

printf("Стек пуст\n");

return 0;

}

return *p;

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]