|
Программирование >> Аргументация конструирования
Трудно предсказать, что может случиться, если сохранить переменные одного типа по адресам, выделенным под переменные другого типа. Сохранение переменных, имеющих большую длину, вероятно, приведет к уничтожению располо- женных рядом. Такая ситуация наглядно продемонстрирована с помощью программы Layout Error: демонстрирует результат неаккуратного обращения с указателями #inciude <stdio.h> tinclude <iostream.h> int pszArgs[]) rnt upper = 0; rnt n = 0; int lower = 0; выводим значения объявленных переменных cout upper = << upper \n ; cout << n = n \n ; cout lower = << lower \n ; сохраняем значение типа в памяти, выделенной для int cout \пСохранение double в int\n ; double* pD = (double*) bn; *pD = 13.0; показываем результаты cout upper = <<;upper \n ; cout << n = n << \n ; cout lower = lower \л ; return 0; первых трех строках функции происходит объявление трех переменных типа int. Допустим, что в памяти эти перемеппые находятся друг за другом. Следующие три строки выводят значения этих переменных на экран. Не удивительно, что все три оказываются равными нулю. После этого происходит присвоение *pD = 13.0;, в результате которого число, имеющее тип double, записывается в переменную г., имеющую тип int. Затем все три переменные снова выводятся на экран. После записи действительного числа в целочисленную переменную п переменная upper оказалась забитой каким-то мусором. На языке домов и адресов эта программа будет выглядеть так: house* houseAddress = & 123 Main Street ; hotel* hotelAddress; *hotelAddress = TheRitz; Указатель houseAddress инициализирован как указатель на мой дом. Переменная hotelAddress содержит адрес отеля. После этого вместо адреса моего дома записывается адрес отеля. Затем отель Ритц устанавливается по адресу моего дома. Однако, поскольку Ритц куда больше моего дома, не удивительно, что он уничтожит не только мой дом, но и дома моих соседей (хоть что-то приятное в результате ошибки!). Типизация указателей предохраняет программиста от неприятностей, связанных с сохранением данных большего размера в меньшем объеме памяти. Присвоение piiitvar = 100. С не вызывает никаких проблем, поскольку C + + известно, что plntVar указывает на целочисленную цеременную и приводит 100.0 перед присвоением к тому же типу. JlefteqaHa ((/сазсипелей (рнкцилм Одним из путей использования указателей является передача аргументов функции. Для того чтобы понять всю важность этого метода, необходимо разобраться, как происходит передача аргументов функциям. Передача аргументов по значению Вы мсгли заметить, что обычно нельзя изменить значение переменной, которая передавалась функции как аргумент. Рассмотрим следующий фрагмент кода: void fn(intArg) int intArg =10; здесь значение intArg равно 10 void parent(void) int nl = 0 ; fn(nl); здесь nl равно 0 Функция parent () инициализирует переменную nl нулем. После этого значение ni нередается в качестве аргумента функции fn(). В fn () неременной intArg нри-сваивается значение 10. тем самым в fn() осуществляется попытка изменить аргумент функции. Поскольку в качестве аргумента выступает переменная nl, можно ожидать, что после возврата в parent () эта переменная должна иметь значение 10. Тем не менее nl остается равной 0. Дело 1) том, что С + + передает функции не переменную, а значение, которое в момент вызова функции находится в переменной. При вызове функции происходит вычисление значения передаваемого функции выражения, даже если это просто переменная. ti* Обычно, экономя слова, многие говорят что-то вроде передаем переменную х функции fn() На самом деле это означает, что функции передается значение выражения х. Передача значений указателей как и любая другая переменная, может быть передан функции в качестве аргумента. voi int pintAg} { *pintArg = 10; void parent(void) { int r. = 0; fn(sn); так передается адрес п теперь п равно 10 В этом случае вместо значения п функции fn () передается адрес этой переменной. Чем отличается передача значения переменной от передачи значения указателя на менную, станет понятно, если рассмотреть присвоение, выполняющееся в функции (). Предположим, что и находится но адресу 0xi02. В этом случае функции f п () передается аргумент, равный 0x102. Внутри fn () присвоение tArg = 10 выполняет запись целого значения в переменную типа int, которая находится по адресу 0x102. Таким образом, ноль в переменной л заменяется на 10, поскольку в данном случае 0x102 и есть адрес Передача аргументов по ссылке В C++ возможна сокращенная запись приведенного выше фрагмента, которая не от программиста непосредственной работы с указателями. В приведенном ниже примере переменная п перелается по ссылке. При передаче по сс1лке вместо значения переменной функции передается ссьшка на переменную (ссылка, по сути, является синонимом слова адрес). voi ints. intArg) intArg = 10; void parent(void) int n = 0; fn(n) теперь значение п равно 10 В этом примере функция frs () получает не значение переменной п, а ссылку на нее и, в свою очередь, записывает 10 в переменную типа int, на которую ссылается intArg. использование fcif4U Куна (heap) - это блок памяти изменяемого размера, который при необходимости может использоваться программой. Далее в этом разделе поясняется, зачем нужна куча и как ею пользоваться. Очевидно, что если можно передать функции указатель, то можно и вернуть его как результат работы функции. Функция, которая должна вернуть некоторый адрес, объявляется следующим образом: double* При работе с возвращаемыми указателями следует быть очень осторожным. Чтобы понимать, чем чревато неаккуратное использование указателей, следует познакомиться с концепцией области видимости переменных (т.е. с тем, где именно от переменных остается только видимость...). Область видимости Кроме значения и типа, переменные в C++ имею те одно свойство - область видимости, т.е. часть программы, в которой эта переменная определена. Рассмотрим следующий фрагмент кода:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |