Литмир - Электронная Библиотека
A
A

int strlen(const char a[]) // аналогична стандартной

                           // функции strlen()

{

  int count = 0;

  while (a[count]) { ++count; }

  return count;

}

char lots [100000];

void f()

{

 int nchar = strlen(lots);

 // ... 

Наивно (но частично обоснованно) мы могли бы ожидать, что при выполнении этого вызова будут скопированы 100 тыс. символов, заданных как аргумент функции

strlen()
, но этого не происходит. Вместо этого объявление аргумента
char p[]
рассматривается как эквивалент объявления
char* p
, а вызов
strlen(lots)
— как эквивалент вызова
strlen(&lots[0])
. Это предотвращает затратное копирование, но должно вас удивить. Почему вы должны удивиться? Да потому, что в любой другой ситуации при передаче объекта, если вы не потребуете явно, чтобы он передавался по ссылке (см. разделы 8.5.3–8.5.6), этот объект будет скопирован.

Обратите внимание на то, что указатель, образованный из имени массива, установлен на его первый элемент и не является переменной, т.е. ему ничего нельзя присвоить.

char ac[10];

ac = new char [20];     // ошибка: имени массива ничего присвоить нельзя

&ac[0] = new char [20]; // ошибка: значению указателя ничего

                        // присвоить нельзя

И на десерт — проблема, которую компилятор может перехватить!

Вследствие неявного превращения имени массива в указатель мы не можем даже скопировать массивы с помощью оператора присваивания.

int x[100];

int y[100];

// ...

x = y;          // ошибка

int z[100] = y; // ошибка

Это логично, но неудобно. Если необходимо скопировать массив, вы должны написать более сложный код. Рассмотрим пример.

for (int i=0; i<100; ++i) x[i]=y[i]; // копируем 100 чисел типа int

memcpy(x,y,100*sizeof(int)); // копируем 100*sizeof(int) байт

copy(y,y+100, x); // копируем 100 чисел типа int

Поскольку в языке C нет векторов, в нем интенсивно используются массивы. Вследствие этого в огромном количестве программ, написанных на языке C++, используются массивы (подробнее об этом — в разделе 27.1.2). В частности, строки в стиле C (массивы символов, завершаемые нулем; эта тема рассматривается в разделе 27.5) распространены очень широко.

Если хотите копировать, то используйте класс, аналогичный классу

vector
. Код копирования объектов класса
vector
, эквивалентный приведенному выше, можно записать следующим образом:

vector<int> x(100);

vector<int> y(100);

// ...

x = y;    // копируем 100 чисел типа int

18.5.3. Инициализация массива

 Массивы имеют одно значительное преимущество над векторами и другими контейнерами, определенными пользователями: язык С++ предоставляет поддержку для инициализации массивов. Рассмотрим пример.

char ac[] = "Beorn"; // массив из шести символов

Подсчитайте эти символы. Их пять, но

ac
становится массивом из шести символов, потому что компилятор добавляет завершающий нуль в конце строкового литерала.

Программирование. Принципы и практика использования C++ Исправленное издание - _206.png

Строка, завершающаяся нулем, является обычным явлением в языке С и многих системах. Такие массивы символов, завершающиеся нулем, мы называем строками в стиле языка С (C-style string). Все строковые литералы являются строками в стиле языка C. Рассмотрим пример.

char* pc = "Howdy"; // указатель pc ссылается на массив из шести

                    // символов

Графически это можно изобразить следующим образом.

Программирование. Принципы и практика использования C++ Исправленное издание - _207.png

Переменная типа

char
, имеющая числовое значение
0
, — это не символ
'0'
, не буква и не цифра. Цель этого завершающего нуля — помочь функции найти конец строки. Помните: массив не знает своего размера. Полагаясь на использование завершающего нуля, мы можем написать следующий код:

int strlen(const char* p) // похоже на стандартную функцию strlen()

{

  int n = 0;

  while (p[n]) ++n;

  return n;

}

На самом деле мы не обязаны определять функцию

strlen()
, поскольку это уже стандартная библиотечная функция, определенная в заголовочном файле
<string.h>
(разделы 27.5 и Б.10.3). Обратите внимание на то, что функция
strlen()
подсчитывает символы, но игнорирует завершающий нуль; иначе говоря, для хранения
n
символов в строке в стиле языка С необходимо иметь память для хранения n+1 переменной типа
char
.

Только символьные массивы можно инициализировать с помощью литеральных констант, но любой массив можно инициализировать списком значений его элементов соответствующего типа. Рассмотрим пример.

int ai[] = { 1, 2, 3, 4, 5, 6 };        // массив из шести чисел

                                        // типа int

int ai2[100] = { 0,1,2,3,4,5,6,7,8,9 }; // остальные 90 элементов

247
{"b":"847443","o":1}