Использование массивов и указателей
В языке С++ массивы и указатели связаны между собой. При объявлении массива в виде : int mas [20]; имя массива mas определяется как указатель-константа на первый (нулевой) элемент массива, т.е. на адрес первого элемента массива &mas[0]. Для доступа к элементам массива существует два способа: — использование индекса элемента массива, например, mas[2] или mas[i]; — использование адресного выражения т.е. выражения с указателем на массив, например, *( mas +2 ) или *( mas+i ). Имя массива-указатель, можно записать в следующем виде:
int mas [20]; int *ptr1; ptr1 = mas; // или ptr1 = &mas[0]; После объявления массива int mas [20]; выражения &mas[0] и mas являются эквивалентными. Для обнуления элементов объявленного массива достаточно инициализировать его первый элемент: int mas[0] = {0} ; При этом первому элементу не обязательно присваивать значение 0. Если в объявленном массиве инициализируется несколько первых элементов, то остальные инициализируются нулями. Например, в случае когда float mas [10] ={ 12.2, 34.56 }; ,оставшиеся восемь элементов получат значение 0. Глобальные массивы автоматически инициализируются двоичными нулями, в том числе и символьные. При объявлении массивов можно использовать одну из форм записи : < тип > < имя > [n] // Объявление одномерного // массива из n элементов < тип > < имя > [n] = { значения } // Значения элементов массива < тип > < имя > [ ] = { значения } // разделены запятой Например: float m[6]; float m[6] = { 3.4, 4.5, 5.6, 6.7, 8.9, 10.3 }; float m[ ] = { 3.45, 4.56, 5.67, 6.78 }; Двумерные и многомерные массивы объявляются аналогичным образом, т.е. правомерна запись :
int mas [2][5] ={ 1, 2, 3, 4, 5, 10, 11, 13, 14, 25 }; int mas [ ][5] ={ 1, 2, 3, 4, 5, 10, 11, 13, 14, 25 }; . При объявлении одномерных массивов их размер можно не указывать, если объявленный массив сразу инициализируется. В объявлении многомерных массивов можно опускать количество индексов только первого измерения при одновременной инициализации. Если во время объявления массивов инициализация не проводится , то количество индексов надо указывать всегда и везде. Поскольку для массивов всегда в памяти отводится сплошной блок ячеек памяти , в которых располагаются элементы, то адрес следующего элемента mas[1] можно указать путем увеличения указателя на 1, т.е. если p = &mas[0] , то p=p + 1 или ( p += 1) и для i элемента массива адрес может быть определен как p + i; . При этом автоматически выполняется операция увеличения адреса с учетом типа массива и отводимого количества байт для каждого его элемента, следовательно : адрес х[i] = адрес x[0] + i*sizeof ( тип ) ; . Если два указателя р1 и р2 указывают на элементы одного массива, то к ним применимы операции отношения: == , != , < , <= , > , >= . Например, отношение вида р1 < р2 истинно, если р1 указывает на более ранний элемент, чем р2 . Любой указатель можно сравнить с нулем. Следует обратить внимание, что для указателей, ссылающихся на элементы разных массивов, результат арифметических операций и отношений не определен. В арифметике с указателями можно использовать адрес не существующего "следующего за массивом " элемента. Кроме того, к указателю можно прибавить некоторое целое значение, например можно записать: р + n ,
где n — целое значение, а р — указатель. Это выражение определяет область объекта, занимающего n -е место после объекта, на который указывает р, при этом n автоматически умножается на коэффициент, равный соответствующей длине объекта. Например , если int занимает 4 байта , то этот коэффициент равен четырем. Допускаются также вычитания указателей, указывающих на элементы одного массива. Например, если р1< p2, то р2 - р1+1 — это число элементов массива от р1 до р2 включительно. Таким образом, с указателями допускаются следующие операции : — присваивание значения одного указателя другому; — сложение и вычитание указателей и данного целого типа ( р+5 ); —сравнение двух указателей, ссылающихся на элементы одного массива; — присваивание указателю нуля и сравнение с нулем. Остальные операции с указателями запрещены. Для указателя разрешаются выражения вида:
р1 = mas; или р++ ,
здесь р — указатель , mas — массив. Рассмотрим демонстрационные примеры программ работы с указателями. Пример 2.4 Вычислить среднее значение положительных элементов одномерного массива. Приведем несколько вариантов программной реализации этой задачи. // P2_7.CPP — вычисление среднего значения // положителных элементов массива // программа без использования указателей # include < iostream. h> void main( ) { const int n = 5; float mas[n], s = 0; int kol = 0; for( int i = 0; i < n; i++) { cout << "Введите " << i << "элемент mas" << endl; cin >> mas[ i ]; if ( mas[ i ] > 0 ) { s += mas[ i ]; kol ++; } } s/ = kol; cout << "s=" << s << endl; } Используя имя массива как указатель на начало массива (первый элемент), эту программу можно переписать следующим образом:
// P2_8.CPP — вычисление среднего значения // положителных элементов массива // использование имени массива как указателя на его начало #include < iostream.h> void main ( ) { const int n = 5; float mas[n], s = 0; int kol = 0; for ( int i=0; i < n; i++) { cout << "Введите " << i << "элемент mas" << endl; cin >> *( mas+i); if(* ( mas+i ) > 0 ) { s+= *(mas+i); kol++; } } s/=kol; cout << "s=" << s << endl;
} Если описать указатель, связать его с массивом (адресовать на начало массива),то используя арифметику указателей, можно написать эту программу в виде: // P2_9. CPP —— вычисление среднего значения // положителных элементов массива // использование арифметики указателей # include < iostream. h> Void main ( ) { int kol = 0; const int n = 5; float mas[n], s = 0; float *pm = mas; // допустимазапись pm=&mas[0] for ( int i = 0; i < n; i++) { cout << "Введите " << i << "элемент mas" << endl; cin >> *pm++; cout << mas[i] << endl; if (mas[i] > 0) { s+=mas[i]; kol++; } } s/= kol; cout << "s=" << s << endl; }
В приведенной программе при вводе массива использовался указатель *pm , а при работе с ним — имя массива с индексом. Если бы при работе с массивом использовался указатель *pm , то результат был бы не верным. Это объясняется тем, что указатель *pm в операциях ввода он увеличивает свой адрес ( pm++) после ввода очередного элемента массива и в дальнейшем указывает еще не введенный элемент. Приведем еще один вариант программной реализации этой же задачи. // P2_10.СРР —— вычисление среднего значения // положителных элементов массива // использование указателей # include < iostream. h > void main ( ) { const int n = 5; float mas[n], s = 0; float *pm = mas; // *pm=&mas[0] int kol = 0; for ( int i = 0 ; i < n ; i++) { cin >> *pm; cout << "Введите " << i << "элемент mas" << endl; if (*pm > 0) { s += *pm; kol ++; *pm ++; } } s/= kol; cout << "s=" << s << endl; }
Пример 2.5. Составить программу сортировки одномерного массива по убыванию методом вставки. // P2_11.CPP — сортировка методом вставки (по убыванию) // применение указателей #include < iostream.h > #include < conio.h > void main ( ) { int stc, mas [6], i, j; int *pmas; pmas = mas; cout << "Введите 6 элементов массива " << endl; for ( i = 0; i < 6; i++) cin >>*pmas++; // Следующий оператор снова устанавливает указатель на начало массива // (иначе он будет указывать на следующий за массивом адрес) pmas = mas; for ( i =1; i < 6; i++) { stc = *(pmas + i); j = i - 1; while ( j >= 0 && stc > *(pmas+j)) { *(pmas+j+1) = *(pmas+j); j - - ; } *(pmas+j+1) = stc; } cout << "Результат " << endl; for ( i = 0; i < 6; i++) cout << i << " элемент " << *(pmas + i ) << endl; // Можно использовать и такую конструкцию оператора // cout << i << " элемент " << * pmas++ << endl; getch ( ); // Для задержки экрана вывода результата } Массивы указателей Как и другие переменные, указатели можно группировать в массивы, каждый элемент которого содержит адрес строки массива данных в памяти. Таким образом можно хранить данные с "рваными" краями. Этот массив похож на двумерную таблицу с одним исключением: все строки в таком массиве могут иметь разную длину. При хранении строк это позволяет экономить память, а при выполнении сортировки строк, она выполняется значительно быстрее, т.к. изменяются только указатели, а не содержимое строк. Fio
Приведем илюстрационную программу реализующую вывод подобной информации с использованием массива указателей. // P2_11.CPP #include <iostream.h> void main ( ) { char * fio [ ] = { "Петров", "Иванов" , "Куц", "Варич", "Юшко", "Плющ " }; int str; for ( str = 0; str <= 5; str++) cout << " stroka " <<( str +1 ) << ” = ” << *( fio+str ) << endl; } Особенностью массива указателей является то, что каждый из этих указателей элементов массива может указывать на массив произвольной длины. Так двумерный массив чисел можно записать как матрицу, и как одномерный массив указателей, например: int matr[5][7]; или int *pmt [5]; . При этом двумерный массив рассматривается как одномерный массив строк, каждый элемент которого — это тоже массив столбцов, т.е. массив массивов, поэтому индексирование элементов матрицы записывается в виде mas [i][j]. Если двумерный массив описан с помощью массива указателей, то доступ к mas [i][j] элементу может осуществляться одним из способов:
* ( pm[i]+j ) или *( *( pm+i )+j ) . Пример 2.6 К элементам матрицы, имеющим четные значения, прибавить число и вывести полученную матрицу в естественном виде. Первый вариант программной реализации — матрица описывается явным способом и работа ведется с ее элементами.
// P2_12.CPP — работа ведется без указателей. #include < iostream.h > Void main( ) { int mat [2][3]; int i, j; cout << " Введите матрицу "<< endl; for ( i = 0; i < 2; i++) for ( j = 0; j < 3; j++) cin >> mat [i] [j] ; // Обработка и вывод матрицы cout << " Матрица mat " << endl; for ( i = 0; i < 2; i++) { for ( j = 0; j< 3; j++) { if ( ( mat [i][j] /2 )*2 == mat[i][j]) mat[i][j] = mat[i][j] + 5; cout << mat [ i][ j] << " "; } cout << endl; // Перевод строки при выводе матрицы } } Второй вариант программной реализации — матрица описана как массив указателей.
//P2_13.CPP — матрица описана как массив указателей: #include < iostream.h > void main ( ) { int i, j, *pm[2]; cout << "Введите матрицу "<< endl; for ( i = 0; i < 2; i++) for ( j = 0; j < 3; j++) cin >> *( pm[i] + j ); cout << " Матрица МАТ "<< endl; for ( i = 0; i < 2; i++) { for ( j = 0; j < 3; j++) { if ( *(pm[i] + j) / 2*2 == *( pm[i] + j ) ) *( pm [i] + j ) += 10; cout << *( pm [i] + j) << " "; } cout << endl; } } В рассматриваемой программе для вывода матрицы можно использовать другой вид оператора :
с out << ( (j == 0) ? '\t':' ') << *( pm[i]+j ) << ( (j == 2) ? '\ n':' ') ; Имя двумерной матрицы является указателем-константой на массив указателей-констант, каждый из которых указывает на начало соответствующей строки матрицы, например для матрицы mat [2] [2] имеем :
mat [0] — указатель-константа на нулевую строку матрицы; mat [1] — указатель-константа на первую строку матрицы; mat [2] — указатель-константа на вторую строку матрицы; т.е.: mat[0] == &mat[0][0]; mat[1] == &mat[1][0]; mat[2] == & mat[2][0]; Вывод матрицы, можно реализовать следующим образом:
cout << mat [i] [j]; cout << *( mat [i] +j ); cout << *(* ( mat + i )+ j ); В С++ можно описать переменную, имеющую тип "указатель на указатель". Признаком такого типа является повторение символа "*" при описании переменной, например int ** pmt; при этом память для такой переменной не выделяется. Ее надо привести к соответствующему массиву. При описании указатель на указатель может инициализировать, например :
int x = 20; int *px1 = &x; int** px2 = &px1; int ***px3 = &px2; Доступ к переменной x теперь можно осуществить одним из трех способов: *px1; **px2; ***px3; . Для доступа к памяти через указатели на указатели можно использовать как индексы так и символы "*", например, эквивалентными будут ссылки на переменную x: px1 [0] * px1; px2 [0][0] ** px2; px3 [0][0][0] ***px3; 2.6 Контрольные вопросы 1. Что такое массив? 2. Как осуществляется описание массивов в программе? 3. Как выбирается элемент массива из памяти? 4. Какие еще операторы языка C++ можно использовать для ввода элементов массива в память компьютера? 5. Сколько циклов надо использовать для ввода, вывода и перебора элементов матрицы? 6. Как обратиться к произвольному элементу массива? 7. Какие ограничения существуют в C++ на размер и размерность массивов? 8. Как вывести на печать матрицу в естественном виде?
Популярное: Генезис конфликтологии как науки в древней Греции: Для уяснения предыстории конфликтологии существенное значение имеет обращение к античной... Почему двоичная система счисления так распространена?: Каждая цифра должна быть как-то представлена на физическом носителе... Как распознать напряжение: Говоря о мышечном напряжении, мы в первую очередь имеем в виду мускулы, прикрепленные к костям ... Как построить свою речь (словесное оформление):
При подготовке публичного выступления перед оратором возникает вопрос, как лучше словесно оформить свою... ©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (320)
|
Почему 1285321 студент выбрали МегаОбучалку... Система поиска информации Мобильная версия сайта Удобная навигация Нет шокирующей рекламы |