Приведённая ниже программа наглядно демонстрирует результаты арифметики указателей.



Задание 7-4

// Задание 7_4.cpp: определяет точку входа для консольного приложения.

// Арифметика указателей

#include "stdafx.h"

#include <iostream>

using namespace std;

int main()

{

       setlocale(LC_ALL, "Russian");

       int *i, j[10];

       double *f, g[10];

       int x;

 

       i = j;

       f = g;

 

       for (x = 0; x<10; x++)

             cout << i + x << " " << f + x << "\n";

return 0;

}

 

Сравнение указателей

Указатели можно сравнивать друг с другом, используя такие операторы отношения как: ==, < и >. В общем случае результат операции сравнения указателей будет иметь смысл, только если оба указателя будут взаимосвязаны. Например, они могут указывать на разные элементы внутри одного и того же массива. Существует и другой вид сравнения указателей: любой указатель можно сравнивать с нулевым указателем, который равен нулю.

Указатели и массивы

В С++ имеется тесная взаимосвязь между указателями и массивами. Во многих случаях указатель и массив являются взаимозаменяемыми понятиями, например:

char str[80];

char *p1;

p1 = str              // p1 будет указывать на адрес элемента str[0]

Примечание:

В С++ использование имени массива без индекса образует указатель на первый элемент массива.

Поэтому доступ к элементам массива можно получить с использованием индекса или с помощью указателя, например к пятому элементу массива можно обратиться:

str[4];

или

*(р1+4)

Оба предложения дадут значение пятого элемента массива. Следует обратить внимание на последовательность выполнения вычислений с учётом приоритета. Операция * имеет более высокий приоритет по отношению к операции +. В связи с чем, при отсутствии скобок, в выражении сначала будет найдено значение, на которое указывает р1 (т.е. первый элемент массива), а затем к этому значению прибавится 4.

Фактически С++ предоставляет два метода обращения к элементам массива: с помощью арифметики указателей и с помощью индексации массива. Необходимо владеть обоими методами, так как иногда арифметика указателей работает быстрее индексации – особенно при обращении к элементам массива в строго последовательном порядке. Поскольку скорость часто является важнейшим критерием в программировании, обращение к элементам массива посредством указателей весьма распространено в программах на С++. Кроме того, используя указатели вместо индексации, иногда можно написать более компактную программу.

Далее приведены две программы обращения регистра, демонстрирующие различия при обращении к элементам массива через указатели и посредством индексации

Задание 7-5

// Задание 7_5.cpp: определяет точку входа для консольного приложения.

// Обращение регистра- индексация массива

#include "stdafx.h"

#include <iostream>

#include <cctype>

 

using namespace std;

int main()

{

setlocale(LC_ALL, "Russian");

int i;

char str[80] = " This Is A Test";

cout << " Исходная строка: " << str << "\n";

for (i = 0; str[i]; i++) {

       if (isupper(str[i]))          //true – если аргумент прописная буква

             str[i] = tolower(str[i]); //преобразование прописной в строчную

       else if (islower(str[i]))     //true – если аргумент строчная буква

             str[i] = toupper(str[i]); //преобразование строчной в прописную

}

cout << " Новая строка: " << str <<"\n";

return 0;

}

 


 

Задание 7-6

// 7_6 UKZMASS.cpp: главный файл проекта.

// Обращение регистра- арифметика указателей

       #include "stdafx.h"

       #include <iostream>

       #include <cctype>

 

       using namespace std;

int main()

{

       setlocale (LC_ALL,"Russian");

       char *p;

       char str[80] = " This Is A Test";

       cout << " Исходная строка: " << str << "\n";

       p = str;     // присвоение адреса начала исходного массива

       while (*p) {

             if (isupper(*p))

                   *p = tolower (*p); //преобразование прописной в строчную;

                   else if (islower (*p))

                   *p = toupper (*p); //преобразование строчной в прописную;

       p++;

       }

       cout << " Преобразованная строка: " << str ;

       cin.get();

}

В задании 7_6  р устанавливается на начало str, затем внутри цикла while буква, на которую указывает р, анализируется и преобразуется, а затем выполняется инкремент р. Цикл завершается, когда р будет указывать на завершающий строку str ноль.

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

Индексация указателя

Итак, для обращения к массиву можно использовать арифметику указателей. В С++ справедливо и обратное; возможно индексировать указатель, как если бы он был массивом

Третий вариант программы обращения регистра является примером индексирования указателя.

Задание 7-7

// Задание 7_7.cpp: определяет точку входа для консольного приложения.

// Индексация указателя как если бы он был массивом

#include "stdafx.h"

#include <iostream>

#include <cctype>

 

using namespace std;

int main()

{

       setlocale(LC_ALL, "Russian");

       char *p;

       int i;

       char str[80] = " This Is A Test";

       cout << " Исходная строка: " << str << "\n";

       p = str;     // присвоение адреса начала исходного массива

                              // теперь индексируем р

       for (i = 0; p[i]; i++) {

             if (isupper(p[i]))

                   p[i] = tolower(p[i]);

             else if (islower(p[i]))

                   p[i] = toupper(p[i]);

       }

       cout << " Новая строка: " << str <<"\n";

return 0;

}

Примечание:

В С++ выражение p[i] функционально идентично выражению *(p+i).

Строковые константы

В программа вообще и в С++ в частности часто используются строковые константы. В С++ когда компилятор сталкивается со строковой константой, он сохраняет её в таблице строк данной программы и создаёт указатель на эту строку. Поэтому ниже приведённая программа вполне разумно выводит на экран фразу «Указатели увеличивают возможности С++».

       #include "stdafx.h"

       #include <iostream>

 

       using namespace std;

int main()

{

       setlocale (LC_ALL,"Russian");

       char *prt;

       prt = " Указатели увеличивают возможности С++.\n ";

       cout << prt;

 

 

Примечание:

Поскольку указатель на таблицу строк программы создаётся автоматически при использовании строковой константы, может появиться искушение воспользоваться этим указателем для модификации содержимого таблицы строк. Однако это рискованное занятие, так как многие компиляторы С++ создают оптимизированные таблицы строк, в которых одна строковая константа может использоваться в нескольких местах программы. В этом случае изменение строки может привести к нежелательным побочным эффектам.

Как уже отмечалось, сравнение указателей имеет смысл, если оба они указывают на один и тот же объект, например массив. Сравнение указателей можно использовать для рационализации некоторых алгоритмов. Приведённая ниже программа осуществляет переворачивание строки, оставляя её на том же месте. Для выполнения этой операции в программе используются две переменных – указателя. Один указатель первоначально указывает на начало строки, а другой – на её последний символ. В программе же организован цикл, который выполняется до тех пор, пока начальный указатель меньше конечного. В каждом шаге цикла символы, на которые указывают указатели, обмениваются местами, после чего указатели продвигаются (один вперёд, а другой назад). Когда начальный указатель становится равным или большим, чем конечный, цикл завершается, а строка оказывается перевёрнутой.

Задание 7-8

// Задание 7_8.cpp: определяет точку входа для консольного приложения.

// Переворачивание строки

#include "stdafx.h"

#include <iostream>

#include <cstring>

 

using namespace std;

int main()

{

       setlocale(LC_ALL, "Russian");

       char str[] = "это проверка работы программы";

       char *start, *end;

       int len;

       char t;

// Вывод на экран исходной строки, вычисление длины

// Установ начальных адресов

       cout << " Исходная строка: \t" << str << "\n";

       len = strlen(str);

       cout << "Длина строки: " << len << "\n";

       start = str;

       end = &str[len - 1];

// Обращение строки

       while (start<end) {

             t = *start;

             *start = *end;

             *end = t;

// изменение адресов символов строки

             start++;

             end--;

       }

       cout << " Строка наоборот: \t" << str <<"\n\n";

return 0;

}

 

Массивы указателей

Указатели, как и любые другие типы данных, могут образовывать массивы. Например, объявление массива из 10 указателей выглядит так:

       int *pi[10];

Для присваивания адреса переменной типа int с именем var третьему элементу массива указателей следует написать:

       int var;

pi[2] = &var;

Следует помнить, что pi является массивом указателей на int. Единственный вид объектов, которые могут содержаться в элементах этого массива – это адреса целочисленных переменных (не самих переменных!). Чтобы найти значение var, необходимо написать:

*pi[2]

Как и в случае любых других массивов, массив указателей можно инициализировать. Обычное использование инициализированных массивов указателей – хранение указателей на строки. В ниже приведённом примере используется двумерный массив указателей на символы для реализации небольшого толкового словаря.

Задание 7-9

// 7_9 DICT.cpp: главный файл проекта.

// Использование двумерного массива указателей

// для создания словаря

       #include "stdafx.h"

       #include <iostream>

       #include <cstring>

       #include <conio.h>

 

       using namespace std;

int main()

{

       setlocale (LC_ALL,"Russian");

       char *dictionary [][2] = {

             "pencil","Карандаш - Инструмент для рисования.",

             "keyboard","Клавиатура - Устройство ввода.",

             "rifle"," Ружьё - Плечевое огнестрельное оружие.",

       "plane","Самолёт - Воздушное судно с неподвижными крыльями.",

             "net","Сеть - Группа соединённых между собой компьютеров.",

             "", ""

       };

       char word[80];

       int i;

       cout << "Введите слово: " ;

       cin >> word;

       for (i=0; *dictionary [i][0]; i++) {

             if (!strcmp(dictionary [i][0], word)) {

                   cout << dictionary [i][1] <<"\n";

                   break;

             }

       }

       if (!*dictionary [i][0])

             cout << word << " не найдено.\n";

       _getch();

}

 


Дата добавления: 2019-07-15; просмотров: 189; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!