Академический Документы
Профессиональный Документы
Культура Документы
Массивы и указатели
Массивы и указатели
Массивы
Массив представляет собой набор однотипных объектов, имеющих общее имя и различающихся
местоположением в этом наборе (или индексом, присвоенным каждому элементу массива). Элементы
массива занимают один непрерывный участок памяти и располагаются последовательно друг за
другом.
Описание массивов
тип имя [размер] [={инициализатор} ];
тип *имя_указателя_на_переменную_заданного_типа;
где тип может быть любым, кроме ссылки и битового поля, причем тип может быть к этому
моменту только объявлен, но еще не определен.
int *ptri; //указатель на переменную целого типа
char *ptrc; //указатель на переменную символьного типа
float *ptrf; //указатель на переменную с плавающей точкой
Звездочка относится непосредственно к имени, поэтому для того, чтобы объявить несколько
указателей, требуется ставить ее перед именем каждого из них.
int a=10, b;
int *ptr=&a; //инициализация указателя адресом переменной а
cоut<<"указатель = "<<рtr<<"\nПеременная="<<*ptr;
ptr=&b; //теперь ptr указывает на переменную b
Результатом вычитания двух адресов (указателей) является целое число, указывающее, сколько
элементов базового типа может разместиться между ячейками с соответствующими адресами.
Например, если указатель р имеет в качестве значения адрес 3000, а указатель q - значение 2000 (при
условии, что базовый тип занимает 4 байта), то результатом команды p–q будет число 250 (результат
определяется как (3000-2000)/4=250). Если от меньшего по абсолютной величине адреса
отнимается больший адрес - число будет отрицательным. Суммирование двух указателей не
допускается.
В данном случае мы естественным образом пришли к процедуре сравнения адресов (указателей).
Сравнение выполняется так же, как и сравнение обычных переменных. Поскольку адрес как таковой
является не чем иным, как числовым значением, то большим считается тот адрес, числовое значение
которого больше. Сравнение указателей широко применяется при работе с массивами.
Указатель на массив
Еще одна особенность C++ связана с тем, что имя массива (без индексов) является константным
указателем на его нулевой элемент. В самой по себе ссылке на первый элемент проку было бы мало,
если б не то принципиальное обстоятельство, что элементы массива размещаются в смежных ячейках.
Поэтому, зная адрес первого элемента и количество элементов в массиве, получаем доступ ко всему
массиву. Хотя доступ может быть получен и через имя массива и индекс элемента, арифметические
операции с адресами выполняются быстрее, по сравнению с индексированием массива. Кроме того,
указатель, который ссылается на массив, можно индексировать точно так же, как если бы это было
имя массива.
Например, если массив создается командой int n[10], то имя массива n является указателем
(адресом) на первый элемент массива n[0] – это то же самое, что &n[0] и оба значения являются
константами типа указатель, т.к. они неизменны на протяжении работы программы, а к і-му элементу
массива можно обратиться, используя выражение *(n+i).
Можно описать указатель, присвоить ему адрес начала массива и работать с массивом через
указатель.
int n[10], *p;
p=n;
for(int i=0;i<10;i++)
{ p[i]= 10-i;
cout<< *(p+i);} // cout<< p[i];
или
int n[10];
for (int i=0; i<10; i++)
{ *(n+i)=10-i; cout << n[i]<< "\n";}
или
for (i=0;i<10;i++)
{ *pb=pa[i]; pb++;}
или
for (i=0;i<10;i++)
{*pb=pa[i]; pb++;}
Отличие от обычного двумерного массива: для дин. массива выделенная память не представляет
собой сплошной участок памяти, т.к она выделяется с помощью нескольких операций new.
Заполнение массива реализуется в рамках двойного оператора цикла
for (i=0 ;i<n;i++)
for(j=0 ;j<m;j++)
{ mas[i][j] = (i*m+j)%10 ;
cout<< mas[i][j]<< " ";}
for(i=0 ;i<n;i++)
delete [] p[i];
delete [] p;
Ссылки
Ссылка (reference) - это видоизмененная (неявная) форма указателя. По своей природе, ссылка
действительно схожа с указателем. Однако, в отличие от указателя, при работе со ссылкой
пользователь не получает прямого доступа к адресу ячейки памяти. В некотором смысле ссылка - это
указатель, но только со скрытым адресом. Поэтому для ссылок не требуется дополнительной памяти.
Ссылку можно рассматривать как указатель, kоторый всегда разыменовывается.Способ объявления и
использования ссылок в программе полностью отличается от способов работы с указателями.
Переменные ссылочного типа могут использоваться в след. целях:
ссылка вместо передачи в функцию объекта по значению;
для определения конструктора копии;
для перезагрузки унарных операций;
для предотвращения неявного вызова конструктора копии при передачи в ф-ию по
значению объекта определенного пользователем класса
Обычно ссылки используются при передаче аргументов функциям, при возвращении значений
функций через ссылки, а также при создании псевдонимов объектов (переменных). В последнем
случае речь идет о независимой ссылке (independent reference) которая используется в качестве
псевдонима (другого имени) переменной, указанного при инициализации ссылки. Для определения
ссылки используется символ &, указываемый перед переменной–ссылкой. Формат объявления ссылки:
тип & имя;
где тип - это тип величины, на которую указывает ссылка, &-оператор ссылки, означающий, что
следующее за ним имя является именем переменной ссылочного типа, например:
Значение ссылки - это значение переменной, на которую ссылка выполнена (в этом смысле она
отличается от указателя, значением которого является адрес ячейки, на которую ссылается указатель).
При объявлении ссылки необходимо сразу указывать, на какую переменную она ссылается (в этом
случае говорят об инициализации ссылки). Ссылка инициализируется только один раз. В дальнейшем
имя ссылки служит еще одним альтернативным названием для переменной, на которую выполнена
ссылка.
int n;
int ©=n;
copy=100;
n++; //n=101;
Использование независимых ссылок:
#include<iostream.h>
int main()
{int t=15,&r=t// инициализация ссылки на t теперь
//r синоним имени t , а &r-адрес
cout<<"t="<<t; //выводит 15
r+=10; //изменение значения t через ссылку
count<<"t="<<t; //выводит 25
return 0;
}
int n,*p,*q;
int ©=n;
p=&n;
copy=100;
(*p)/=10;
q=©
n++;
cout << n << "\n" ;
cout<<copy<<" \n";
cout << * p << "\n";
cout << * q << "\n" ;
cout <<p<<"\n";
cout<<q<<" \n";
Сначала поэлементно заполняется символьный массив str размера 20 (размер задан через
целочисленную константу n). Занесенные в массив значения также поэлементно выводятся на экран
одной строкой. Перебираются все элементы массива. Для заполнения массива и вывода значений на
экран используется оператор цикла. Далее пользователю предлагается ввести текстовую строку. При
считывании строка заносится в массив. Строка командой cout<<str<<endl выводится на экран,
после чего с помощью оператора цикла выводятся все элементы массива. Если в качестве строки
пользователя ввести фразу Hello, World!, то результат выполнения программы может быть
следующим:
ABCDEFGHIJKLMNOPQRSТ
Enter a string: Hello, World!
Hello, World!
Hello, World! OPQRST
Интерес представляют предпоследняя и последняя строки вывода результатов выполнения
программы. В предпоследней строке выводится фраза Hello, World! (та фраза, что введена
пользователем с клавиатуры). Это результат выполнения команды cout<<str. При считывании
фразы пользователя и записи ее в массив последним после непосредственно текста строки
автоматически добавляется нуль-символ. Поэтому при выполнении команды cout<<str вывод на
экран осуществляется до этого символа.
Последняя строка вывода результатов получается при выполнении команд cout<<str[i] в
рамках последнего оператора цикла. Поскольку перебираются все элементы массива, то на экран
выводятся не только элементы массива до нуль-символа, но и элементы, размещенные после этого
символа.
Сам нуль-символ отображается в виде пробела. В этом смысле нуль-символ является очень
важным индикатором, который отделяет полезный, рабочий текст, занесенный в символьный массив,
от “мусора”, размещенного в хвосте массива.
//Операции со строками
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
int main()
{
char s1 [20],s2 [20];
strcpy(s1,"My name is ") ;
strcpy(s2,"Alex") ;
for(int i=0; s2[i]; s2[i]=toupper(s2[i]),i++);
strcat(s1,s2);
cout<<s1<<endl;
return 0 ;
}
Результатом выполнения э той программы является строка
My name is ALEX
Сначала с помощью функции strcpy () записываются значения в массивы s1 и s2, после чего в
строке s2 все символы меняются на прописные (в операторе цикла использована функция toupper
() ), строка s2 добавляется командой strcat (s1, s2) в конец строки s1, и результат выводится
на экран.
Строчные литералы
Как уже отмечалось, строчные литералы в C++ сохраняются в виде символьного массива, причем
на этот литерал автоматически создается ссылка.
Это немаловажное обстоятельство существенно упрощает работу с литералами текстового типа.
//Работа с литералами
# include <iostream>
using namespace std;
intt main ()
{
char *p,*q;
p="Hello, World'";
q="Hello, World!"+7;
cout<<p<<endl;
cout<<q<<endl;
cout<<*p<<endl;
p++;
cout<<*p<<endl;
return 0 ;
}