русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Звертання до елементів масивів через вказівники


Дата додавання: 2014-04-22; переглядів: 6521.


В мові програмування С++ ім’я масиву є константним вказівником на його першій елемент. Це дозволяє звертатися до елементів масиву не тільки за допомогою індексів, але і за допомогою вказівників. При цьому, при використанні вказівників теж допускається використання квадратних дужок і індексів. Тобто, наступні звертання до елементів масиву будуть еквівалентними:

 

#include <iostream>

using namespace std;

int main() {

int a[ 5 ] = { 1, 2, 3, 4, 5 };

int * p = a;

cout << a[ 1 ] << endl;

cout << * ( a + 1 ) << endl;

cout << p[ 1 ] << endl;

cout << * ( p + 1 ) << endl;

p = & a[ 1 ];

cout << * p << endl;

}

 

Для роботи з масивами зручно використовувати додаткові вказівники, які посилаються на елементи масиву, що опрацьовуються в даний момент. Знайдемо середнє значення елементів масиву з 100 випадкових дійсних чисел за допомогою вказівників:

 

#include <iostream>

#include <ctime>

using namespace std;

int main() {

srand( unsigned( time ( NULL ) ) );

const int NUM = 100;

double a[ NUM ], avg, * p;

double * plast = & a[ NUM - 1 ];

for ( int i = 0; i < NUM; ++i ) {

a[ i ] = ( rand( ) % 1001 ) / 1000.;

}

for ( p = a, avg = 0; p <= plast; p++ )

avg += * p;

avg /= NUM;

cout << avg << endl;

}

 

Такий підхід до організації циклів зручно використовувати при опрацюванні рядків символів. При цьому ознакою виходу із циклу є посилання вказівника на нуль – символ. Наприклад, є рядок символів. Символи поділені на такі групи: 1) символи операцій ‘+’, ‘-’, ‘*’, ‘/’; 2) символи пунктуації: ‘,’, ‘.’, ‘;’; 3) інші символи. Знайти кількість символів кожної групи в рядку.

 

#include <iostream>

using namespace std;

int main() {

char c[ ] = "+-*/ 1234 .,; +-*/.,";

char * p = c;

int n[ 3 ] = { };

do

switch ( * p ) {

case '+':

case '-':

case '*':

case '/': n[ 0 ]++; break;

case '.':

case ',':

case ';': n[ 1 ]++; break;

default: n[ 2 ]++;

}

while ( * ++p );

for ( int i = 0; i < 3; i++ )

cout << i << " : " << n[ i ] << endl;

}

 

У виразі * ++p операції інкремента і звертання за адресою мають однаковий пріоритет, асоціативність справа наліво. Тобто, спочатку виконується збільшення вказівника на одиницю, тепер він посилається на наступний символ рядка. Після цього виконується операція звертання за адресою, яка повертає символ рядка. Якщо цим символом є нуль – символ, то виконання циклу завершується.

Елементи багатовимірних масивів займають неперервну ділянку оперативної пам'яті, адресу початку якої зберігає константний вказівник – ім’я масиву. Тому, багатовимірний масив можна розглядати як одновимірний, в якому кожен елемент має свій порядковий номер. Наприклад, елемент двовимірного масиву з індексами i, j буде мати порядковий номер i * кількість_елементів_в_рядку + j.

 

#include <iostream>

using namespace std;

int main() {

const int NROWS = 2; // Кількість рядків матриці

const int NCOLS = 3; // Кількість елементів в кожному рядку

int a[ NROWS ][ NCOLS ] = { { 1, 2, 3} , { 4, 5, 6} };

int * p;

p = ( int * ) a;

cout << a[ 1 ][ 2 ] << endl;

cout << * ( p + 1 * NCOLS + 2 ) << endl;

}

 

Вказівники зручно використовувати у випадках, коли обробка елементів багатовимірних масивів виконується незалежно від положення елемента в цьому масиві. Наприклад, знайдемо максимальний елемент матриці цілих випадкових чисел.

 

#include <iostream>

#include <ctime>

using namespace std;

int main() {

srand( unsigned( time ( NULL ) ) );

const int NROWS = 3; // Кількість рядків матриці

const int NCOLS = 4; // Кількість елементів в кожному рядку

int a[ NROWS ][ NCOLS ];

for ( int i = 0; i < NROWS; i++ ) {

for ( int j = 0; j < NCOLS; j++ ) {

a[ i ][ j ] = rand( ) % 100;

cout << a[ i ][ j ] << "\t";

}

cout << endl;

}

int * p = ( int * ) a;

int * plast = & a[ NROWS - 1 ][ NCOLS - 1 ];

int max = *p++;

do

if ( * p > max )

max = * p;

while ( ++p <= plast );

cout << max << endl;

}

 

Для багатовимірних масивів ім’я масиву зберігає адресу першого байти масиву. Але багатовимірні масиви в С++ - це масиви, елементами яких є масиви меншої вимірності. Тобто, двовимірний масив – це одновимірний масив, елементами якого є одновимірні масиви. Ім’я масиву – це константний вказівник на його перший елемент, тобто це вказівник на початок першого одновимірного підмасива. Через це в попередніх прикладах необхідно було виконувати перетворення типів в виразі p = ( int * ) a.

Для масиву а з попереднього приклада, вирази a[ 0 ] i * a виділяють перший елемент масиву а, який є одновимірним масивом з чотирьох елементів цілого типу. Значення a[ 0 ], a[ 1 ], a[ 2 ] є адресами масивів кожного рядка матриці. При цьому, значення адреси, яка зберігається в а, і значення a[ 0 ] однакові, але а вказує на перший рядок матриці, а a[ 0 ] – на перший елемент першого рядка.

Оскільки a[ і ] є константною адресою і-го рядка матриці, то вираз a[ і ] + j обчислює адресу j-го елемента цього рядка. До елементів багатовимірних масивів можна звертатися, використовуючи тільки індексну або тільки вказівникові форму доступу, а також різні комбінації обох форм:

 

#include <iostream>

using namespace std;

int main() {

const int NROWS = 2; // Кількість рядків матриці

const int NCOLS = 3; // Кількість елементів в кожному рядку

int a[ NROWS ][ NCOLS ] = { { 1, 2, 3} , { 4, 5, 6} };

// Звертання до першого елемента матриці

cout << a[ 0 ][ 0 ] << endl;

cout << * a[ 0 ] << endl;

cout << * * a << endl;

// Звертання до j-го елемента першого рядка матриці

int j = 1;

cout << a[ 0 ][ j ] << endl;

cout << * ( a[ 0 ] + j ) << endl;

cout << * ( * a + j ) << endl;

// Звертання до першого елемента і-го рядка матриці

int i = 1;

cout << a[ i ][ 0 ] << endl;

cout << * a[ i ] << endl;

cout << * * ( a + i ) << endl;

// Звертання до j-го елемента і-го рядка матриці

cout << a[ i ][ j ] << endl;

cout << * ( a[ i ] + j ) << endl;

cout << * ( * ( a + i ) + j ) << endl;

cout << ( * ( a + i ) ) [ j ] << endl;

}

 

Для звернення до елементів багатовимірних масивів можна також використовувати більш складні оголошення:

 

#include <iostream>

using namespace std;

int main() {

const int NROWS = 2; // Кількість рядків матриці

const int NCOLS = 3; // Кількість елементів в кожному рядку

int a[ NROWS ][ NCOLS ] = { { 1, 2, 3} , { 4, 5, 6} };

int ( * b )[ NCOLS ];

b = a; // Вказівник на перший рядок матриці

cout << * ( * b + 0 ) << endl;

cout << * ( * b + 1 ) << endl;

cout << * ( * b + 2 ) << endl;

b++; // Вказівник на другий рядок матриці

cout << * ( * b + 0 ) << endl;

cout << * ( * b + 1 ) << endl;

cout << * ( * b + 2 ) << endl;

}

В цьому прикладі оголошення int ( * b )[ NCOLS ]; створює вказівник на масив з NCOLS цілих чисел. В складних оголошеннях такого типу квадратні і круглі дужки справа від ідентифікатора мають пріоритет перед зірочкою зліва від ідентифікатора. Квадратні і круглі дужки мають однаковий пріоритет і розкриваються зліва направо. Специфікатор типу розглядається на останньому кроці, коли оголошення повністю інтерпретоване. Можна використовувати круглі дужки, щоб змінити порядок інтерпретації на необхідний.

Для інтерпретації складних оголошень використовується просте правило, яке складається з чотирьох кроків:

1) почати з ідентифікатора і подивитись направо, чи є там квадратні або круглі дужки;

2) якщо вони є, то виконати інтерпретацію цієї частини оголошення, після цього подивитись наліво, чи є там зірочка;

3) якщо на будь-якій стадії інтерпретації закриваючу круглу дужку, то спочатку необхідно застосувати всі ці правила всередині круглих дужок, і після цього продовжити інтерпретацію;

4) виконати інтерпретацію специфікатора типу.

 


<== попередня лекція | наступна лекція ==>
Void – вказівники, типізація вказівників | Масиви символьних рядків і масиви вказівників


Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн