Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(л0)Переменные_указатели_ссылки_функции.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
538.11 Кб
Скачать

2.2. Передача параметров по адресу

Чтобы заставить функцию работать так, как нужно, следует передавать в нее не значения переменных x и y, а их адреса. Для этого необходимо выполнить следующее:

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

Void swap(int* a, int* b)

{

int temp = *a;

*a = *b;

*b = temp;

}

2. Изменить вызов функции. Т.к. теперь она ожидает получить указатели, то необходимо передавать адреса фактических параметров x и у:

swap(&x, &y);

Теперь в функцию передаются адреса. И работа ведется относительно переданных адресов:

Таким образом, если функция должна менять значение переменной, нужно передавать ей адрес этой переменной.

Примечание: У тех, кто только начинает программировать на C, есть одна распространенная ошибка. При вводе с клавиатуры с помощью функции scanf() они передают значение переменной, а не ее адрес. В этом случае функция scanf(), используя полученное значение в качестве адреса, будет работать неверно.

2.3. Передача больших объемов данных

Предположим, что нам нужно передать в функцию целое число типа int. Таким образом, мы передаем в функцию sizeof(int) байт. Обычно это 4 байта (размер будет зависеть от архитектуры компьютера и компилятора). 4 байта — это немного, они будут выделены в стеке, т.к. имеет место передача по значению.

В современных задачах функциям приходится иметь дело с большими объемами данных, это могут быть десятки и сотни мегабайт. При передаче по значению в таком случае возникает 2 проблемы:

1. Каждый раз при вызове функций придется затрачивать время на копирование всего объема передаваемых данных.

2. Стек программы не всегда в состоянии вместить такой объем.

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

2.4. Инициализация указателей

Указатели — это мощный инструмент. Указатели эффективно и быстро работают, но являются не слишком безопасными, т.к. вся ответственность за их использования ложится на разработчика. Не стоит забывать, что человеку свойственно ошибаться.

Представим ситуацию.

int x;

int* p;

В большинстве компиляторов C и С++ неинициализированные локальные переменные имеют случайное значение. Глобальные обнуляются. Если мы захотим разыменовать указатель и присвоить ему значение, то нужно записать следующую команду:

*p = 10;

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

Указатели нужно обнулять. Для этого есть специальное значение NULL. Для языка С это:

int* p = NULL;

В C++ обычно можно инициализировать указатель нулем.

int* p = 0;

Это возможно из-за того, что в библиотечных файлах языка, дано определение для NULL.

#define NULL (void*)0

То есть NULL — это нулевой указатель.

Давайте решим следующую задачу. Папа Карло дал Буратино 5 яблок. Злой Карабас Барабас отобрал 3 яблока. Сколько яблок осталось у Буратино?

Ответ: неизвестно. Так как нигде не сказано, сколько яблок у Буратино было изначально.

Мораль: При объявлении переменных всегда выполняйте их инициализацию.