Стефан Дэвис - С++ для чайников .
- Название:С++ для чайников .
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс. Компьютерное издательство Диалектика
- Год:2007
- Город:Москва
- ISBN:0-7645-6852-3, 978-5-8459-0723-3
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стефан Дэвис - С++ для чайников . краткое содержание
1
empty-line
4
С++ для чайников . - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Но, к счастью для нас, выражение вида array + n будет всегда указывать на элемент array[ n ] , независимо от размера элемента, поскольку в таком выражении С++ самостоятельно учитывает длину элемента.
И вновь обратимся за аналогией к моему дому. Третий дом от 123 Main Street будет иметь адрес 126 Main Street , независимо от размеров стоящих на Main Street домов.
Отличия между указателями и массивами...122
В использовании массива и указателя есть несколько отличий. Во-первых, объявление массива вызывает выделение памяти для всего массива, тогда как объявление указателя не требует выделения памяти для массива.
void arrayPointer( )
{
/* Выделение памяти для 128 символов */
char charArray[ 128 ] ;
/* Выделение памяти для указателя, но не для объекта, на который он указывает */
char* pArray ;
}
_________________
122 стр. Часть 2. Становимся функциональными программистами
В этом примере для charArray выделяется 128 байт, а для pArray — четыре, ровно столько, сколько необходимо для хранения указателя. Приведённая ниже функция работать не будет.
void arrayVsPointer( )
{
/* Этот фрагмент будет работать нормально */
char charArray[ 128 ] ;
charArray[ 10 ] = '0' ;
*( charArray + 10 ) = '0' ;
/* Этот фрагмент не будет работать так, как надо */
char* pArray ;
pArray[ 10 ] = '0' ;
*( pArray + 10 ) = '0' ;
}
Выражения charArray[ 10 ] и *( charArray + 10 ) с позиции компилятора эквивалентны и вполне законны. Те же выражения с использованием pArray являются бессмысленными. Несмотря на то что для С++ они являются законными, pArray не инициализирован как указатель на массив, а значит, память была выделена только для указателя. Таким образом, рАггау[ 10 ] и *( рАггау + 10 ) указывают на неизвестные и непредсказуемые значения.
«Неправильно инициализированные указатели обычно вызывают ошибкунарушения сегмента (segment violation ). Эту ошибку вы иногда встречаете в повседневной работе со своими любимыми приложениями в своей любимой ( а может, и не очень ) операционной системе.»
[ Советы ]
Второе отличие между указателями и индексами массива состоит в том, что charArray — константа, тогда как pArray — нет. Приведённый ниже цикл for , который должен инициализировать значения элементов массива, тоже не будет работать.
void arrayVsPointer( )
{
char charArray[ 10 ] ;
for ( int i = 0 ; i < 10 ; i++ )
{
*charArray = '\0' ; /* Эта строка имеет смысл... */
charArray++ ; /* ... а эта нет */
}
}
Выражение charArray++ имеет не больше смысла, чем 10++. Правильно следует написать так:
void arrayVsPointer( )
{
char charArray[ 10 ] ;
char* pArray = charArray ;
for ( int i = 0 ; i < 10 ; i++ )
{
*pArray = '\0' ; /* Этот вариант будет работать так, как надо */
pArray++ ;
}
}
_________________
123 стр. Глава 9. Второе знакомство с указателями
►Объявление и использование массивов указателей...124
Если есть указатели на массивы, можно предположить, что существуют и массивы указателей. Именно их мы сейчас и рассмотрим.
Поскольку массив может содержать данные любого типа, он может состоять и из указателей. Массив указателей объявляется так:
int* pInts[ 10 ] ;
Таким образом, элемент pInts[ 0 ] является указателем на переменную типа int . Следовательно, приведённый ниже код корректен:
void fn( )
{
int n1 ;
int* pInts[ 3 ] ;
pInts[ 0 ] = & n1 ;
*pInts[ 0 ] = 1 ;
}
Как и этот:
void fn( )
{
int n1 , n2 , n3 ;
int* pInts[ 3 ] = { & n1 , & n2 , & n3 } ;
for ( int i = 0 ; i < 3 ; i++ )
{
*pInts[ i ] = 0 ;
}
}
И даже этот:
void fn( )
{
int n1 , n2 , n3 ;
int* pInts[ 3 ] = { ( new int ) ,
( new int ) ,
( new int ) } ;
for ( int i = 0 ; i < 3 ; i++ )
{
*pInts[ i ] = 0 ;
}
}
В последнем варианте память под переменные выделяется из кучи.
Массивы указателей чаще всего используются для работы с массивами строк. Приведённые далее примеры показывают, почему это удобно.
Использование массивов строк...124
Допустим, мне понадобилась функция, возвращающая название месяца по его номеру. Например, если этой функции передать число 1, она вернёт название первого месяца — "Январь". Номер месяца будет считаться неправильным, если он окажется меньше 1 или больше 12.
_________________
124 стр. Часть 2. Становимся функциональными программистами
Эту функцию можно написать следующим образом:
/* int2month( ) — возвращает название месяца */
char* int2month( int nMonth )
{
char* pszReturnValue ;
switch( nMonth )
{
case 1 : pszReturnValue = "Январь" ;
break ;
case 2 : pszReturnValue = "Февраль" ;
break ;
case 3 : pszReturnValue = "Март" ;
break ;
/* и так далее... */
default : pszReturnValue = "Неверный номер месяца"
}
return pszReturnValue ;
}
«Операторswitch( ) действует так же, как совокупность операторовif .»
[ Помни! ]
Эту задачу можно решить более элегантно, использовав номер месяца как индекс в массиве указателей, представляющих названия месяцев. Тогда программа приобретёт такой вид:
/* int2month( ) — возвращает название месяца */
char* int2month( int nMonth )
{
/* проверка правильности номера месяца */
if ( nMonth < 1 || nMonth > 12 )
{
return "invalid" ;
}
/* nMonth имеет корректное значение */
/* Вернём имя месяца */
char* pszMonths[ ] = { "Ошибка" ,
"Январь" ,
"Февраль" ,
"Март" ,
"Апрель" ,
"Май" ,
"Июнь" ,
"Июль" ,
"Август" ,
"Сентябрь" ,
"Октябрь" ,
"Ноябрь" ,
"Декабрь" } ;
return pszMonths[ nMonth ] ;
}
Сначала в этой программе проверяется корректность аргумента nMonth , т.е. что его значение лежит в диапазоне между 1 и 12 включительно ( в предыдущей программе проверка производилась, по сути, оператором default ). Если значение nMonth правильное, оно используется как смещение внутри массива, содержащего названия месяцев.
_________________
125 стр. Глава 9. Второе знакомство с указателями
«Такой способ обращения к строкам по индексу особенно полезен при написании программы, работающей на разных языках. Например, массив названий месяцев может инициализироваться во время работы с названиями на разных языках, так чтоptrMonth[ 1 ] всегда будет указывать на январь независимо от используемого языка.»
Читать дальшеИнтервал:
Закладка: