Читаем C++: базовый курс полностью

Здесь указатель р содержит неизвестный адрес, поскольку он нигде не определен. У вас нет возможности узнать, где записано значение переменной х. При небольших размерах программы (например, как в данном случае) ее странности (которые заключаются в том, что указатель р содержит адрес, не принадлежащий ни коду программы, ни области данных) могут никак не проявляться, т.е. программа внешне будет работать нормально. Но по мере ее развития и, соответственно, увеличения ее объема, вероятность того, что р станет указывать либо на код программы, либо на область данных, возрастет. В один прекрасный день программа вообще перестанет работать. Способ не допустить создания таких программ очевиден: прежде чем использовать указатель, позаботьтесь о том, чтобы он ссылался на что-нибудь действительное!

Некорректное сравнение указателей

Сравнение указателей, которые не ссылаются на элементы одного и того же массива, в общем случае некорректно и часто приводит к возникновению ошибок. Никогда не стоит полагаться на то, что различные объекты будут размещены в памяти каким-то определенным образом (где-то рядом) или на то, что все компиляторы и операционные среды будут обрабатывать ваши данные одинаково. Поэтому любое сравнение указателей, которые ссылаются на различные объекты, может привести к неожиданным последствиям. Рассмотрим пример.

char s[80];

char у[80];

char *p1, *р2;

p1 = s;

р2 = у;

if(p1 < р2) . . .

Здесь используется некорректное сравнение указателей, поскольку C++ не дает никаких гарантий относительно размещения переменных в памяти. Ваш код должен быть написан таким образом, чтобы он работал одинаково устойчиво вне зависимости от того, где расположены данные в памяти.

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

int first[101;

int second[10];

int *p, t;

p = first;

for(t=0; t<20; ++t) {

 *p = t;

 p++;

}

Цель этой программы — инициализировать элементы массивов first и second числами от 0 до 19. Однако этот код не позволяет надеяться на достижение желаемого результата, несмотря на то, что в некоторых условиях и при использовании определенных компиляторов эта программа будет работать так, как задумано автором. Не стоит полагаться на то, что массивы first и second будут расположены в памяти компьютера последовательно, причем первым обязательно будет массив first. Язык C++ не гарантирует определенного расположения объектов в памяти, и потому эту программу нельзя считать корректной.

Не забывайте об установке указателей

Следующая (некорректная) программа должна принять строку, введенную с клавиатуры, а затем отобразить ASCII-код для каждого символа этой строки. (Обратите внимание на то, что для вывода ASCII-кодов на экран используется операция приведения типов.) Однако эта программа содержит серьезную ошибку.

// Эта программа некорректна.

#include

#include

#include

using namespace std;

int main()

{

 char s [80];

 char *p1;

 p1 = s;

 do {

  cout << "Введите строку: ";

  gets(p1); // Считываем строку.

  // Выводим ASCII-значения каждого символа.

  while(*p1) cout << (int) *p1++ << ' ';

  cout << ' \n';

 }while(strcmp (s, "конец"));

 return 0;

}

Сможете ли вы сами найти здесь ошибку?

В приведенном выше варианте программы указателю p1 присваивается адрес массива s только один раз. Это присваивание выполняется вне цикла. При входе в do-while-цикл (т.е. при первой его итерации) p1 действительно указывает на первый символ массива s. Но при втором проходе того же цикла p1 указатель будет содержать значение, которое останется после выполнения предыдущей итерации цикла, поскольку указатель p1 не устанавливается заново на начало массива s. Рано или поздно граница массива s будет нарушена.

Вот как выглядит корректный вариант той же программы.

// Эта программа корректна.

#include

#include

#include

using namespace std;

int main()

{

 char s[80];

 char *p1;

 do {

  p1 = s; // Устанавливаем p1 при каждой итерации цикла.

  cout << "Введите строку: ";

  gets(p1); // Считываем строку.

  // Выводим ASCII-значения каждого символа.

Перейти на страницу:

Все книги серии Изучайте C++ с профессионалами

C++: базовый курс
C++: базовый курс

В этой книге описаны все основные средства языка С++ - от элементарных понятий до супервозможностей. После рассмотрения основ программирования на C++ (переменных, операторов, инструкций управления, функций, классов и объектов) читатель освоит такие более сложные средства языка, как механизм обработки исключительных ситуаций (исключений), шаблоны, пространства имен, динамическая идентификация типов, стандартная библиотека шаблонов (STL), а также познакомится с расширенным набором ключевых слов, используемым в .NET-программировании. Автор справочника - общепризнанный авторитет в области программирования на языках C и C++, Java и C# - включил в текст своей книги и советы программистам, которые позволят повысить эффективность их работы. Книга рассчитана на широкий круг читателей, желающих изучить язык программирования С++.

Герберт Шилдт

Программирование, программы, базы данных

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных