Типизированные и нетипизированные указатели
Рассмотренные указатели являются типизированными, т.е. могут указывать только на заданный тип данных.
Существуют также нетипизированные указатели (void*), способные указывать на любой тип данных. Сохранение размера и типа данного возложено на программиста.
Пример:
int x;
float y;
void *t = &x; //допустимо
*t = 5; // операция НЕДОПУСТИМА, т.к. неизвестен тип данного
*(int *)t = 5; //допустимо обращение при соответствующем приведении типов
t =& y;
*(double*)t = 2.5;
Для типизированных указателей определены операции сложения с числом и вычитания из них числа, при этом результатом является указатель того же типа, смещенный в памяти на заданное количество данных (т.е. на размер данного, умноженного на заданное смещение).
Также для типизированных указателей определена операция разности указателей. Данная операция возвращает количество элементов (размер_области_памяти/размер_элемента) между указателями.
Массивы
Массивы являются набором однотипных данных, последовательно размещённых в памяти.
Одномерный массив можно объявить так:
тип_данного имя_массива[размер];
Например: int x[5];
Обращение к элементам массива происходит через операцию []. Минимальный индекс всегда ноль. Максимальный индекс – на единицу меньше размера массива.
ВНИМАНИЕ Автоматический контроль границ отсутствует.
Имя массива является указателем на начало массива. Операция x[i] тождественно равна *(x+i).
Возможно использование многомерных массивов.
int x[4][4][3];
x[0][0][0] = 5;
Массивы могут инициализироваться значениями в фигурных скобках, при этом допустимо не указывать последнюю (самую левую) размерность. Если заданная размерность меньше инициализирующих аргументов, часть элементов останется неопределенна. Обратная ситуация вызовет ошибку.
Примеры:
int x[3][2]={{1,2},{3,4},{5,6}}; //заданы и размеры массива, и инициализирующие значения
long y[] = {1,2,3,4}; // размер массива определяется фактическому по количеству значений (4)
char t[][4] = {{1,2,3,4},{5,6}}; // последняя размерность определяется по числу значений (2) и // элементы t[1][2] и t[1][3] не определены
Функции работы с памятью
(заголовочные файлы alloc.h, stdlib.h, mem.h)
void* malloc(unsigned s) – выделение памяти s байт.
void* calloc(unsigned n, unsigned m) – выделение n элементов по m байт.
void* realloc(void* ptr, unsigned ns) – перевыделение памяти.
void free(void* ptr) – освобождение памяти.
int memcmp(void* s1, void* s2, unsigned n) – сравнивает две области памяти.
void* memcpy(const void* dest, const void* src, unsigned n) – копирование области памяти n байт из src в dest.
void* memset(void *ptr, int c, unsigned n) – запись числа c в память начиная с ptr.
Консольные функции.
void clreol() – удаление символов от курсора до конца строки.
void clrscr() – очистка экрана.
int cprintf(char *format [,..,]) – вывод строки с учётом параметров консоли.
void gotoxy(int x, int y) – перемещение курсора в позицию (x,y) экрана.
void textbackground(int c) – цвет фона.
void textcolor(int c) – цвет шрифта.
void textmode(int m) – режим (C40, C80, C4350).
Строки.
Строкой является массив данных типа char. Используется строка с завершающим нулём, то есть признаком конца строки является символ с кодом «0».
Строки могут инициализироваться текстом, заключенным в двойные кавычки: строковой константой, – которая имеет тип const char*.
char t[] = “Hello, World”;
Функции работы со строками (библиотека string.h).
char *strcat(char *dest, char *src) – в dest помещается результат объединения dest и src, возвращает ссылку на dest (!!! в dest должно быть достаточно места для помещения результата)
char *strchr(char *str, int c) – поиск символа «c» в str, результат – ссылка на первый найденный символ или NULL, если символ не найден;
int strcmp(char *str1, char *str2) – посимвольное сравнение строк, возвращает -1, если str1<str2, +1 если str1>str2 и 0 если str1==str2;
char* strcpy(char *dest, char *src) – копирует src в dest, возвращает указатель на dest;
unsigned strlen(char *str)
char* strset(char *str, int c) , возвращает s.
char *strstr(const char *str, const char *substr)
Определены модификации некоторых функций, принимающие в качестве дополнительного аргумента длину строки. Данные функции начинаются с strn вместо str. Это функции strncat, strncmp, strncpy, strnset.
Пример:
char* strncat(char *dest, char *src, unsigned n) – то же, что strcat, но используются n символов src.
Указатель на функции
Указатель на функцию используется для передачи точки входа в функцию другой функции в качестве аргумента.
тип_функции (*имя_указателя) (спецификация параметров)
пример:
void qsort(void *base, size_t nelem, size_t width, int (*fcmp)(const void *p1, const void *p2);
вызов: fcmp(p1,p2);
функция сравнения чисел:
int comp(const void *p1, const void *p2)
{
return *(int*)p1 - *(int*)p2;
}
Работа с файлами.
Для взаимодействия с файлами предназначена структура данных FILE. Данная структура хранит служебную информацию об открытых файлах, такую как права доступа, указатель на файловый буфер, положение курсора в файле и т.д.
Для работы с файлом его необходимо открыть, для этого предназначена функция
FILE *fopen(const char *filename,const char *mode);
filename – абсолютное или относительное имя файла, mode – режим открытия и доступа.
Режимы:
"r" – открытие существующего файла только для чтения (файл должен существовать);
"w" – создание пустого файла для записи;
"a" – открытие существующего файла для записи данных в конец файла; создание файла, если файла с заданным именем не существует;
"r+" – открытие существующего файла для чтения и записи (файл должен существовать);
"w+" – создание нового файла для чтения и записи;
"a+" – тоже, что “a”, но с возможностью чтения;
Другие функции работы с файлами:
int fclose( FILE *stream ); // 0 в случае успеха
int _fcloseall( void ); //количество закрытых файлов
int fflush(FILE *stream);
int feof( FILE *stream);
int fgetc( FILE *stream);
int fgetpos( FILE *stream, fpos_t *pos);
int fputc(int c, FILE *stream);
int fseek( FILE *stream, long offset, int origin);
long ftell( FILE *stream);
Существуют стандартные файлы (потоки) (тип данных – FILE*):
stdin – стандартный поток ввода (по умолчанию – клавиатура);
stdout – стандартный поток вывода (по умолчанию – монитор в текстовом режиме);
stderr – стандартный поток ошибок;
stdaux – стандартный вспомогательный поток;
stdprn – стандартный принтер.
Данные потоки могут быть переопределены с использованием функции fopen.
Форматированный ввод-вывод
Для форматированного вывода в поток предназначена функция
fprintf(FILE* stream, const char* formatted_string, arguments, …)
Для подстановки значений переменных в строку вывода используют символы подстановки (спецификаторы формата), начинающиеся с символа «%»:
%[флаги][размер][.точность][модификатор_длины]тип_данного[1]
Флаги:
«-» – выравнивание результата по левому краю (по умолчанию – по правому относительно заданного количества выводимых символов);
«+» – результат всегда начинается со знака (+/-);
«#» – особая форма отображения результата.
Размер показывает сколько символов отводится для записи результата, может быть представлен в следующих форматах:
n – минимум n символов отводится для записи числа, недостающие символы заменяются пробелами;
0n – то же, но недостающие символы заменяются нулями;
* – список аргументов содержит размеры данных.
Точность показывает для вещественных символов количество знаков после десятичной точки.
Модификатор длины может принимать одно из значений:
F – «длинный» указатель;
N – «короткий» указатель;
h – short int;
l – long int, double;
L – long double.
Тип данного может принимать одно из значений:
%d, %i – знаковое десятичное целое;
%u – беззнаковое десятичное целое;
%o – беззнаковое восьмеричное целое;
%x, %X – беззнаковое шестнадцатеричное целое;
%f – знаковое вещественное;
%e, %E – знаковое вещественное в экспоненциальной форме;
%g, %G – знаковое вещественное, форма зависит от числа, размера и точности;
%c – символ;
%s – строка;
%% – символ «%»;
%n, %p – указатель.
Аргументы, передаваемые в функцию, должны соответствовать количеству и типу спецификаторам формата.
Для форматированного ввода данных из потока используется функция
fscanf(FILE* stream, const char* formatted_string, arguments, …)
Строка также может содержать спецификаторы формата, при этом:
– при невозможности предобразования строки в число, число принимает значение ноль;
– строкой считается слово до разделителя (пробел, табуляция, перевод строки).
Для стандартных потоков определены аналогичные функции:
printf(const char* formatted_string, arguments, …)
scanf(const char* formatted_string, arguments, …)
являющиеся аналогами описанных ранее функций, разница заключается в том, что используются стандартные потоки ввода и вывода (stdin, stdout) которые в качестве аргументов не указываются.
Определены функции, использующие вместо потока строку:
sprintf(char *dest, const char* formatted_string, arguments, …)
sscanf(char *src, const char* formatted_string, arguments, …)
[1] Квадратные скобки не являются частью записи формата, а указывают на необязательность аргумента