Site hosted by Angelfire.com: Build your free website today!
 

 


 
 


 

Указатели. Динамическое выделение памяти.


Обычно в программе ты работаешь с переменными и не задумываешься, как и где хранятся значения, которые ты в них кладешь. Но бывает, что тебе надо знать, где в памяти лежит твоя переменная, либо тебе надо динамически создать новую переменную. Или даже не одно, а некоторое количество переменных.
Например, программа спрашивает у пользователя, сколько чисел он хочет сложить, потом запрашивает по очереди эти числа, потом складывает, потом выводит результат.
Где же лучше всего хранить набор чисел одного и того же типа?
Правильный ответ - в массиве. Но какого размера задать массив? Мы же не знаем изначально, сколько чисел захочет пользователь сложить. Безответственный программист сделает так: задаст большой массив чисел на 9999 или вроде того и решит, что авось хватит. Устанет юзер столько вводить :)
Конечно, юзер устанет. Но если юзер с головой и ему надо сложить числа, записанные в текстовый файл, он может не вводить их руками, а направить на вход программе заранее сделанный (или сгенерированный другой программой) текстовый файл. И тут программа выполнит недопустимую операцию, когда попытается записать 10000-ое число в массив.
Ответственный программист, но не владеющий техникой динамического выделения памяти поставит проверку после запроса у юзера количества складываемых элементов.
И выдаст на экран сообщение о том, что программа в состоянии сложить не более 9999 чисел. Это уже лучше. Однако тут юзер все равно будет материть программиста, который написал настолько маломощную программу.
Грамотное решение в этом случае - динамически создать массив такого размера, какого надо. Размер этого массива будет лишь ограничен размером свободной памяти у юзера. Таким образом, если юзер попытается сложить столько чисел, что программа не сможет выделить достаточно памяти для их хранения, то программа просто скажет юзеру, что он не имеет достаточно памяти. Т.е. все свалит на него, это его проблема, что он решил складывать столько чисел, а компьютер у него не тянет. И бедный юзер побежит в магазин докупать памяти :-)
Хотя совсем умный программист поймет, что чтобы найти сумму чисел совсем не обязательно их все хранить в памяти. Но это уже не важно - главное, что юзер поймет, что в том, что программа не может выполнить его задачу, виноват он сам.
Итак, указатель - это адрес в памяти. Но не только просто адрес, а еще тип данных, который должен лежать по этому адресу. Т.е. это тоже переменная, в которой лежит целое число - адрес. Записывается так:
int *a;

a - <указатель на int> или другими словами в а может лежать адрес в памяти.
Как воспользоваться указателем?
После объявления, как в любой другой переменной в нем может лежать что угодно. Его надо проинициализировать, т.е. положить в него какое-нибудь значение. Например, можно в него положить число 1. Однако такой указатель мы не сможем никак использовать. Хрен его знает, что лежит в памяти по адресу 1. Обычно инициализируют указатель следующим образом:

1. заносят в него адрес другой переменной, чтобы иметь возможность считывать из нее и писать в нее через указатель. Чтобы получить адрес переменной используют оператор <&>. Чтобы по адресу получить значение используют оператор <*>. Оператор <*> не имеет никакого отношения к такому же значку, используемому для объявления переменной-указателя.
Пример:
int *a;
int b;
a=&b; // теперь <а указывает на b>, т.е. в а лежит адрес b
b=3; // в b лежит 3
printf("b=%d\n",*a); // выводим значение из b через указатель
*a=4;
printf("b=%d\n",b); // увидим,что в b теперь лежит 4
2. динамически выделяют память для хранения данных, и адрес этого куска памяти присваивают указателю.
Пример :
int *a;
a= new int; // выделяем память под одно число типа int
*a=3; // заносим в эту память число
delete a; // освобождаем память

как видишь, после выделения памяти её необходимо освобождать, как только тебе она больше не нужна.
В реальной жизни под одно число никто память не выделяет динамически. Для этого можно создать обычную статическую переменную. Память выделяют динамически под ряд чисел, особенно, если заранее не известно, сколько их будет.
Получаются т.н. динамические массивы.
Пример:
int *a;
int n=25;
a= new int[n]; // выделяем память под массив размером n
for(int i=0;i<n;i++){
a[i]=i*i; // заносим в массив квадраты чисел от 0 до n-1
}
// тут как-то используем эти числа
delete a; // освобождаем память как только закончим использовать

Как видишь, работа с динамическими массивами ничем особенно не отличается от работы с обычными. Надо лишь выделить память, а после работы освободить.

Задача ?1
Сделать описанную выше программу сложения чисел, динамически выделяя память.


То, что я рассказывал ранее - это общее для ДОС и Вин. Теперь чисто ДОСовская штука.
В начале рассказа об указателях я гипотетически предложил занести в переменную-указатель единицу. Это, конечно, бред. Однако, есть ряд известных адресов, куда можно установить указатель. Один из них - это видеопамять. Это кусок памяти с фиксированным адресом, где лежит образ экрана. Компьютер с определенной частотой считывает оттуда данные и выводит их на экран. Следовательно, если изменить что-то в видеопамяти, это отразится на экране. На этом основан способ быстрого <прямого> вывода изображения на экран. Тебе надо будет использовать <дальние>указатели, чтобы достать до видеопамяти.
Я сейчас не буду останавливаться на устройстве памяти и дальних указателях. Просто используй следующие строчки:
int far *a; // это объявление дальнего указателя на int
a=( int far *)MK_FP(0xB800,0); // установка указателя на адрес B800:0000
MK_FP - Make far pointer - создает указатель на адрес c заданным сегментом и смещением. Функция эта придумана Борландом. В других Си её может и не быть. Более того, это верно только для DOS-приложений.
Экранная память устроена как длинный массив чисел, каждое из которых представляет собой символ и цвет, которым он выводится.

Задача ?2
1. Установить указатель на видеопамять
2. Заполнить видеопамять числами от 1 до 80*5 (80 символов в строке, 5 строк)
3. насладиться бредом на экране
4*. Поэкспериментировать с выводом чисел в видео память.
ћ Постараться понять, как вывести символ в заданные координаты.
ћ Постараться понять, как вывести заданный символ разного цвета - для этого использовать указатель char far *a;

 

Заглавна Форум Компилатори за C++