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

Адреса и указатели

Указатели похожи на метки, которые ссылаются на места в памяти. Представьте сейф с депозитными ячейками различного размера в местном банке. Каждая ячейка имеет номер, уникальный номер, который связан только с этой ячейкой, таким образом можно быстро идентифицировать нужную ячейку. Эти цифры аналогичны адресам ячеек компьютерной памяти. К примеру, у вас есть богатый дядя, который хранит все свои ценности в своем сейфе. И чтобы обезопасить все свои сбережения, он решил завести меньший сейф, в который положит карту, на которой показано местоположение большого сейфа и указан 16-й пароль от большого сейфа, в котором и хранятся реальные драгоценности. По сути, сейф с картой будет хранить расположение другого сейфа. Вся эта организация сбережения драгоценностей эквивалентна указателям в языке Си. В компьютере, указатели просто переменные, которые хранят адреса памяти, как правило, адреса других переменных.

Идея в том, что зная адрес переменной, вы можете пойти по этому адресу и получить данные, хранящиеся в нем. Если вам нужно передать огромный кусок данных в функцию, намного проще передать адрес в памяти, по которому хранятся эти данные, чем скопировать каждый элемент данных! Более того, если программе понадобится больше памяти, вы можете запросить больше памяти из системы. Как же это работает? Система просто возвращает адрес ячейки памяти, и мы должны сохранить этот адрес в переменной-указателе. Так мы сможем взаимодействовать с данными из указанного участка памяти

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

int i; double d; /*   Функции передаются адреса переменных i и d.  После вызова функции

адреса останутся прежними (pass-by-value), но значения могут измениться */ func( &i, &d ); ...

char *s; /* указатель на char */ int *pi; /* указатель на int */ void *pv; /* указатель на void */ char **av /* указатель на указатель на char */ /*   Это указатель на функцию, которая возвращает   int, а в качестве параметра ожидает char */ int (*pf)(char)

Чем «опасны» указатели?

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

void f(int *p) {   *p=1; } int main() {   int i;   int *ptr;   f(ptr);   ...   return0; }

Что делать, если указатель создан, но пока не известно, какой адрес в него записать? Для этого есть специальное значение указателя - в C это символьная константа NULL, в C++ - 0.

#include <stdlib.h> main() {   char *p=NULL;   ...}

void f(int *p) {   if (p != NULL) *p=1;   else {  printf("Help!!! NULL pointer in f()\n"); abort(); } }

int main() {   int i;  int *ptr=NULL;  f(ptr);   ...   return 0;

}

Ввод-вывод

#include <stdio.h> int main() {   /* Печатаем целое число и строку */   printf("integer=%d, string=%s \n", 10, "hello"); }

#include <stdio.h> int main() {   int i;   char c;   /* Вводим целое число и символ */   scanf("%d %c", &i, &c); }

scanf() - чтение данных из потока

int i, j; scanf("%d %d", &i, &j);

// или

int i, j; int *p1,*p2; p1=&i; p2=&j; scanf("%d %d", p1, p2);

Объявление и определение функции

int main() {   int i;   i = 1;   f(i);   ...   return 0;

void f(double x) {   ... }

void f(double x); int main() {   ...

Ввод-вывод - <stdio.h>

FILE *fopen(char *filename, char *mode) открывает поток, связанный с файлом filename. Режим работы определяется строкой mode. Например "r" - открыть на чтение, "w" - на запись. При успешном завершении возвращает указатель на открытый поток, при ошибке -NULL. int fflush(FILE *f) записывает все накопленные в буфере выходного потокаfданные в файл.fflush(NULL)выполняет эту операцию со всеми открытыми выходными потоками. При успешном завершении возвращает 0, при ошибке -EOF. int fclose(FILE *f) закрывает поток f. При успешном завершении возвращает 0, при ошибке -EOF.

Ввод-вывод - <stdio.h>

FILE *tmpfile() создает временный файл для записи. Файл будет автоматически удален по fclose()либо при завершении программы. При успешном завершении возвращает указатель на открытый поток, при ошибке -NULL. char *tmpnam(NULL); char *tmpnam(char result[]); возвращает уникальное имя временного файла (сам файл не создается). Без аргумента возвращает указатель на статическую строку. С аргументом - копирует имя в указанный массив, и возвращает указатель на этот массив.int printf(char *fmt, ...) int fprintf(FILE *f, char *fmt, ...) int sprintf(char *buf, char *fmt, ...) Функции форматного вывода соответственно вstdout, в потокfи в символьный массивbuf. При успешном завершении возвращают число выведенных символов (возможно, 0). При ошибке - отрицательное значение.

Ввод-вывод - <stdio.h>

int scanf(char *fmt, ...) int fscanf(FILE *f, char *fmt, ...) int sscanf(char *buf, char *fmt, ...) Функции форматного ввода соответственно изstdin, из потокаfи из символьного массиваbuf. При успешном завершении возвращают число успешно введенных элементов (не символов, а элементов, введенных по спецификациям, заданным в форматной строке). При ошибке возвращаютEOF. int getchar() int fgetc(FILE *f) Считывают одиночный символ изstdin(getchar()) или из входного потокаf(fgetc()). Возвращают либо символ в видеunsigned char(неотрицательный результат), либоEOF, если поток исчерпан и при ошибке. int putchar(int c) int fputc(int c, FILE *f) Записывают одиночный символ вstdout(putchar()) или в выходной потокf(fputc()). Возвращают переданный в поток символ либо, при ошибке,EOF.

int ungetc(int c, FILE *f) "Посмотрели на символ - не понравился". Функция отправляет символ c обратно во входнойпотокf. Стандарт гарантирует возвращение только одного символа (некоторые реализации позволяют и больше). Функция возвращает переданный обратно в поток символ либо, при ошибке,EOF. char *gets(char *buf) Считывает строку (от начала строки до символа '\n') изstdinв символьный массивbuf. Символ \n из строки удаляется, точнее, заменяется нулевым байтом. Функция потенциально опасна - не позволяет защититься от ввода строк, длина которых превышает размер массиваbuf. При успешном вводе возвращаетbuf. По исчерпанию ввода и при ошибке -NULL. char *fgets(char *buf, int size, FILE *f) Ввод строки из потокаf. Работает аналогичноgets. Отличия: - во-первых, вводит из потока не болееsize-1символов (защита от переполнения строкиbuf); во вторых - не удаляет из строки символ '\n' (но нулевой байт в конец строки добавляет)

int puts(char *s) int fputs(char *s, FILE *f) Выводят C-строку в stdout (puts()), либо в поток f (fputs()). Возвращают неотрицательное значение при успешном завершении , либоEOFпри ошибке.

int fseek(FILE *f, long offset, int fromwhere) Позиционирование в файле (функция смещает указатель записи-чтения для данного файла). Второй аргумент указывает, на сколько надо сместиться. Третий аргумент позволяет выполнять смещение от начала или конца файла, либо от текущей позиции. Возвращает 0 при успешном завершении, -1 при ошибке. long ftell(FILE *f) Позволяет получить текущую позицию указателя записи-чтения в открытом файле f. При ошибке возвращает -1. void rewind(FILE *f) Устанавливает указатель записи-чтения файла на начало. Ничего не возвращает. size_t fread(void *ptr, size_t size, size_t nobj, FILE *f) size_t fwrite(void *ptr, size_t size, size_t nobj, FILE *f)

size_t fread(void *ptr, size_t size, size_t nobj, FILE *f) size_t fwrite(void *ptr, size_t size, size_t nobj, FILE *f) Функции позволяют читать из потока, либо записывать в него произвольные данные. При этом первый аргумент - указатель на массив, куда данные надо передавать из потока, либо откуда брать для записи в поток. Второй аргумент -size- задает размер одного элемента, третий - максимальное число объектов, которое можно считать, либо записать.

Функция fread()возвращает количество считанных объектов. Чтобы понять, была ли при вводе ошибка и был ли исчерпан потокf, надо использовать функцииferror()иfeof().

Функция fwrite()также возвращает количество объектов (только не считанных, а записанных). Но об ошибке можно догадаться безferror(), поскольку функция вернет меньшее значение, чем указано вnobj.

int feof(FILE *f) возвращает ненулевое значение, если у потока установлен индикатор конца файла (например, если при последнем вводе из потока данные были исчерпаны). int ferror(FILE *f) возвращает ненулевое значение, если у потока установлен индикатор ошибки (при последней операции с потоком возникла ошибка). void clearerr(FILE *f) Очищает в потокеfиндикаторы конца файла и ошибки. void perror(char *header) Выводит внятное сообщение в потокstderr.

Соседние файлы в предмете Информатика