Мегаобучалка Главная | О нас | Обратная связь


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



2019-08-13 310 Обсуждений (0)
Использование массивов и указателей 0.00 из 5.00 0 оценок




 

В языке С++ массивы и указатели связаны между собой. При объявлении массива в виде : 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

(0)  -> П Е Т Р О В \0  
(1)  -> И В А Н О В \0  
(2)  -> К У Ц \0        
(3)  -> В А Р И Ч \0    
(4)  -> Ю Ш К О \0      
(5)  -> П Л Ю Щ \0      

Приведем илюстрационную программу реализующую вывод подобной информации с использованием массива указателей.

// 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. Как вывести на печать матрицу в естественном виде?

 



2019-08-13 310 Обсуждений (0)
Использование массивов и указателей 0.00 из 5.00 0 оценок









Обсуждение в статье: Использование массивов и указателей

Обсуждений еще не было, будьте первым... ↓↓↓

Отправить сообщение

Популярное:
Почему человек чувствует себя несчастным?: Для начала определим, что такое несчастье. Несчастьем мы будем считать психологическое состояние...
Как выбрать специалиста по управлению гостиницей: Понятно, что управление гостиницей невозможно без специальных знаний. Соответственно, важна квалификация...
Генезис конфликтологии как науки в древней Греции: Для уяснения предыстории конфликтологии существенное значение имеет обращение к античной...
Модели организации как закрытой, открытой, частично открытой системы: Закрытая система имеет жесткие фиксированные границы, ее действия относительно независимы...



©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (310)

Почему 1285321 студент выбрали МегаОбучалку...

Система поиска информации

Мобильная версия сайта

Удобная навигация

Нет шокирующей рекламы



(0.011 сек.)