Читайте также:
|
|
Для того чтобы объявить указатель, который будет ссылаться на переменную, необходимо сначала получить адрес этой переменной. Чтобы получить адрес памяти переменной (её расположение в памяти), нужно использовать знак & перед именем переменной. Это позволяет узнать адрес ячейки памяти, в которой хранится значение переменной. Эта операция называется — операция взятия адреса и выглядит вот так:
int var = 5; // простое объявление переменной с предварительной инициализацией int *ptrVar; // объявили указатель, однако он пока ни на что не указывает ptrVar = &var; // теперь наш указатель ссылается на адрес в памяти, где хранится число 5 |
В строке 3 использовалась операция взятия адреса, мы взяли адрес переменной var и присвоили его указателюptrVar. Давайте рассмотрим программу, которая наглядно покажет всю мощь указателей. Итак, вот исходник:
#include <stdio.h>
int main()
{
int var; // обычная целочисленная переменная
int *ptrVar; // целочисленный указатель (ptrVar должен быть типа int, так как он будет ссылаться на переменную типа int)
ptrVar = &var; // присвоили указателю адрес ячейки в памяти, где лежит значение переменной var
scanf("%d", &var); // в переменную var положили значение, введенное с клавиатуры
printf("%d\n", *ptrVar); // вывод значения через указатель
getchar();
}
Изучив указатели в языке Си, мы открыли для себя возможности динамического выделения памяти. Что это значит? Это значит то, что при динамическом выделении памяти, память резервируется не на этапе компиляции а на этапе выполнения программы. И это дает нам возможность выделять память более эффективно, в основном это касается массивов. С динамическим выделением память, нам нет необходимости заранее задавать размер массива, тем более, что не всегда известно, какой размер должен быть у массива. Далее рассмотрим каким же образом можно выделять память.
Выделение памяти в Си (функция malloc)
Функция malloc() определена в заголовочном файле stdlib.h, она используется для инициализации указателей необходимым объемом памяти. Память выделяется из сектора оперативной памяти доступного для любых программ, выполняемых на данной машине. Аргументом функции malloc() является количество байт памяти, которую необходимо выделить, возвращает функция — указатель на выделенный блок в памяти. Функция malloc() работает также как и любая другая функция, ничего нового.
Так как различные типы данных имеют разные требования к памяти, мы как-то должны научиться получить размер в байтах для данных разного типа. Например, нам нужен участок памяти под массив значений типа int — это один размер памяти, а если нам нужно выделить память под массив того же размера, но уже типа char — это другой размер. Поэтому нужно как-то вычислять размер памяти. Это может быть сделано с помощью операции sizeof(), которая принимает выражение и возвращает его размер. Например, sizeof(int) вернет количество байтов, необходимых для хранения значения типа int. Рассмотрим пример:
Результат работы программы:
CppStudio.com
6
6
В строке 10, printf() выводит значение, хранящееся в переменной var. Почему так происходит? Что ж, давайте посмотрим на код. В строке 5, мы объявили переменную var типа int. В строке 6 — указатель ptrVar на целое значение. Затем указателю ptrVar присвоили адрес переменной var, для этого мы воспользовались оператором присвоения адреса. Затем пользователь вводит номер, который сохраняется в переменную var, помните, что это то же самое место, на которое указывает ptrVar. В самом деле, так как мы используем амперсанд чтобы присвоить значение переменной var в функции scanf(), должно быть понятно, что scanf() инициализирует переменную var через адрес. На этот же адрес указывает указатель ptrVar.
Затем, в строке 10, выполняется операция «разыменования» — *ptrVar. Программа, через указатель ptrVar, считывает адрес, который хранится в указателе, по адресу попадает в нужную ячейку памяти, и возвращает значение, которое там хранится.
Обратите внимание, что в приведенном выше примере, перед тем как использовать указатель, он сначала инициализируется, это нужно для того, чтобы указатель ссылался на определенный адрес памяти. Если бы мы начали использовать указатель так и не инициализировав его, он бы ссылался на какой угодно участок памяти. И это могло бы привести к крайне неприятным последствиям. Например, операционная система, вероятно, помешает вашей программе получить доступ к неизвестному участку памяти, так как ОС знает, что в вашей программе не выполняется инициализация указателя. В основном это просто приводит к краху программы.
Если бы такие приемчики были позволены в ОС, вы могли бы получить доступ к любому участку памяти. А это значит, что для любой запущенной программы вы могли бы внести свои изменения, например, если у вас открыт документ в Word, вы могли бы изменить любой текст программно. К счастью, Windows и другие современные операционные системы остановит вас от доступа к этой памяти и преждевременно закроют вашу программу.
Поэтому, сразу запоминаем, чтобы избежать сбоя в работе вашей программы, вы всегда должны инициализировать указатели, прежде чем использовать их.
#
Дата добавления: 2015-02-16; просмотров: 93 | Поможем написать вашу работу | Нарушение авторских прав |