Выбрать главу

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 <iostream>

#include <cstdio>

#include <cstring>

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 <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

int main()

{

 char s[80];

 char *p1;

 do {

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

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

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

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

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

  cout << '\n';

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