Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Указатели и массивы⇐ ПредыдущаяСтр 30 из 30
В изучаемых нами языках программирования между массивами и указателями имеется очень тесная связь. Кода мы определяем в программе некоторый массив, например,
int Arr[10] переменная Arr без индексов представляет собой указатель на первый элемент массива в данном случае из 10 целых чисел (содержит адрес первого элемента массива). Если вывести на экран значение переменной Arr cout < < Arr: мы увидим некоторое целое значение в шестнадцатеричном формате, соответствующее адресу первого элемента этого массива. Замечание. Именно по этой причине в языке C++ отсутствует операция присвоения сразу всех значений одного массива другому (в некоторых других языках, например, в Pascal такая возможность имеется). Действительно, если имеются два массива
int A1[10], A2[10] то попытка выполнить присвоение A1 = A2 привела бы к тому, что переменная A1 стала бы указывать на ту же область памяти, что и переменная A2 (мы скопировали адрес из A2 в A1, а не содержимое одного массива в другой). Адрес, который хранился ранее в переменной A1, был бы утерян, что привело бы к утечке памяти (для десяти элементов массива A1 в памяти было выделено место, но теперь мы “забыли”, где оно находится, то есть потеряли память). По этой причине подобные операции с массивами в языке C++ запрещены. Более того, запрещены любые изменения значения переменной массива. Указателю, имеющему такой же базовый тип, как и элементы массива, можно присвоить массив следующим образом:
int Arr[10]; int *p; p = Arr;
Но обратное присвоение выполнить невозможно:
Arr = p; // Ошибка Такое присвоение невозможно, поскольку переменная массива – это константа, изменение которой запрещено. Так как переменная массива является указателем на первый элемент массива, появляются дополнительные возможности по работе с массивами на основе использования арифметики указателей. Например, чтобы получить 5–й элемент массива Arr можно воспользоваться одним из следующих выражений:
Arr[4] или *(Arr + 4) или *(p + 4)
Первое выражение – это пример обычной индексации элементов массива. Во втором и третьем выражениях мы использовали арифметику указателей и с помощью операции + получили адрес пятого элемента массива. Затем с помощью операции * взяли значение по этому адресу и получили значение 5-го элемента массива. Обратите внимание на скобки в этих выражениях, если их не поставить и написать * Arr + 4 или *p + 4, то эти выражения будут равны значению первого элемента массива увеличенного на 4, так как операция * имеет больший приоритет, чем операция +. Вот пример фрагмента программы для работы с массивом с помощью обычной индексации элементов массива. Этот фрагмент обеспечивает ввод элементов целочисленного массива с клавиатуры, вычисление квадратов значений элементов массива, а затем вывод элементов массива на экран:
int A[10]; for (int i = 0; i < 10; ++ i) { cin > > A[i]; A[i] = A[i] * A[i]; } for (int i = 0; i < 10; ++ i) cout < < A[i] < < “ “; cout < < endl; …..
А вот тот же фрагмент, но с использованием арифметики указателей:
int A[10]; for (int *Next = A, *End = Next + 9; Next < = End; ++ Next) { cin > > *Next; *Next = *Next * *Next; // *Next = (*Next) * (*Next); } for (int *Next = A, *End = Next + 9; Next < = End; ++ Next) cout < < *Next < < “ “; cout < < endl; …..
Использование арифметики указателей при работе с массивами приводит обычно к уменьшению объема генерируемого кода программы и к уменьшению времени ее выполнения, то есть к увеличению быстродействия. Поскольку указатель и имя массива, в большой степени, взаимозаменяемы, указатели можно индексировать, как обычные массивы:
int A[10], *P = A; for (int i = 0; i < 10; ++ i) cout < < P[i] < < “ “;
Можно создавать и массивы указателей. Например:
int a = 1, b = 2, c = 3, *M[3]; M[0] = & a; // Элементам массива М присваиваются адреса переменных a, b и c M[1] = & b; M[2] = & c; for (int i = 0; i < 3; ++ i) cout < < *M[i] < < “ ”; cout < < endl;
Массив M – это трехэлементный массив указателей на целые значения, то есть каждый элемент этого массива представляет собой указатель на целое.
С помощью массивов указателей можно моделировать различные интересные конструкции данных. Например, пусть имеется квадратная матрица размерности 5 х 5 симметричная относительно главной диагонали. Для ее однозначного представления достаточно хранить в памяти не все 25 элементов этой матрицы, а только 15 (например, элементы под главной диагональю вместе с элементами главной диагонали). Для этого можно предложить следующую конструкцию:
int A1[1], A2[2], A3[3], A4[4], A5[5], *A[5] = { A1, A2, A3, A4, A5 }; // Вводим 15 целых значений - элементы под главной диагональю и диагональные // элементы матрицы for (int i = 0; i < 5; ++i) for (int j = 0; j < = i; ++ j) cin > > A[i][j]; cout < < endl; // Выводим симметричную матрицу 5 на 5 на экран for (int i = 0; i < 5; ++i) { for (int j = 0; j < = i; ++ j) cout < < A[i][j] < < " "; for (int j = i + 1; j < 5; ++ j) cout < < A[j][i] < < " "; cout < < endl; } cout < < endl;
А это пятиэлементный массив указателей на символы, инициализированный некоторыми текстовыми строками:
char * Words[5] = { " Слово1", " Слово2", " Слово3", " Слово4", " Слово5" }
Как это работает: когда компилятор встречает в программе некоторый текст, заключенный в кавычки, в памяти создается символьный массив соответствующей этому тексту длины и адрес этого символьного массива присваивается соответствующему элементу – указателю массива Words.
|