Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект_лек-3_на рус языке.doc
Скачиваний:
1
Добавлен:
01.04.2025
Размер:
298 Кб
Скачать
☆

Внимание!

Если переменная-указатель выходит за области своего действия, отведённая под неё память освобождается. Следовательно, динамическая переменная, на которую ссылался указатель, становится недоступной. При этом память из-под самой динамической переменной не освобождается. Другой случай появления «мусора» - когда инициализированному указателю присваивается значение другого указателя. При этом старое значение бесследно теряется.

С помощью комбинаций звёздочек, круглых и квадратных скобок можно описывать составные типы и указатели на составные типы, например, в операторе

int *(*p[10])();

Объявляется массив из 10 указателей на функции без параметров, возвращающих указатели на int.

По умолчанию квадратные и круглые скобки имеют одинаковый приоритет, больший, чем звёздочка, и рассматриваются слева на право. Для изменения порядка рассмотрения используются круглые скобки.

При интерпретации сложных описаний необходимо придерживаться правила «изнутри наружу»:

  1. если справа от имени имеются квадратные скобки, это массив, если скобки круглые – это функция;

  2. если слева есть звёздочка, это указатель на проинтерпретированную ранее конструкцию;

  3. если справа встречается закрывающая скобка, необходимо применить приведённые выше правила внутри скобок, а затем переходить наружу;

  4. в последнюю очередь интерпретируется спецификатор типа.

Для приведённого выше описания порядок интерпретации указан цифрами:

int *(*p[10]) ();

5 4 2 1 3 //порядок интерпретации описания

Раздел 5. Строки. Работа со строковыми данными

Строка представляет собой массив символов, заканчивающийся нуль-символом. Нуль-символ — это символ с кодом, равным 0, что записывается в виде управ­ляющей последовательности '\0'. По положению нуль-символа определяется фактическая длина строки. Строку можно инициализировать строковым литера­лом:

char str[10] = "Vasla";

// выделено 10 элементов с номерами от 0 до 9

// первые элементы - 'V. 'a', 's'. 'i'. 'а', '\0'

В этом примере под строку выделяется 10 байт, 5 из которых занято под символы строки, а шестой — под нуль-символ. Если строка при определении инициализи­руется, ее размерность можно опускать (компилятор сам выделит соответствую­щее количество байт):

char str[] = "Vasla"; // выделено и заполнено 6 байт

Оператор

char *str = "Vasla";

создает не строковую переменную, а указатель на строковую константу, изме­нить которую невозможно (к примеру, оператор str[l]='o' не допускается). Знак равенства перед строковым литералом означает инициализацию, а не присваива­ние. Операция присваивания одной строки другой не определена (поскольку строка является массивом) и может выполняться с помощью цикла или функций стандартной библиотеки. Библиотека предоставляет возможности копирования, сравнения, объединения строк, поиска подстроки, определения длины строки и т. д. (возможности библиотеки описаны в разделе «Функции работы со строка­ми и символами», с. 91, и в приложении 6), а также содержит специальные функ­ции ввода строк и отдельных символов с клавиатуры и из файла.

Пример. Программа запрашивает пароль не более трех раз.

#include <stdio.h>

# include <string.h>

int main(){

char s[80], passw[] = "kuku"; // passw - эталонный пароль.

// Можно описать как *passw = "kuku";

Int i . k = 0;

for (1 = 0; !k && i<3; i++){

printf("\nвведите пароль :\n");

gets(s); // функция ввода строки

if (strstr(s,passw))k = 1; // функция сравнения строк

}

if (k) printf("\nпароль принят");

else printf("\nпароль не принят");

return 0:

}

При работе со строками часто используются указатели.

ВНИМАНИЕ Распространенные ошибки при работе со строками — отсутствие нуль-символа и выход указателя при просмотре строки за ее пределы.

Рассмотрим процесс копирования строки src в строку dest. Очевидный алгоритм имеет вид:

char src[10], dest [10];

…

for (int i = 0; i<=strlen(src); i++) dest[i] = src[i];

Длина строки определяется с помощью функции strlen, которая вычисляет длину, выполняя поиск нуль-символа. Таким образом, строка фактически про­сматривается дважды. Более эффективным будет использовать проверку на нуль-символ непосредственно в программе. Увеличение индекса можно заме­нить инкрементом указателей (для этого память под строку src должна выде­ляться динамически, а также требуется определить дополнительный указатель и инициализировать его адресом начала строки dest):

#indude <iostream.h>

int main(){

char *src = new char [10];

char *dest = new char [10], *d = dest;

cin » src:

while ( *src != 0) *d++ = *src++;

*d = 0; // завершающий нуль

cout « dest:

return 0;

}

В цикле производится посимвольное присваивание элементов строк с одновре­менной инкрементацией указателей. Результат операции присваивания — пере­даваемое значение, которое, собственно, и проверяется в условии цикла, поэтому можно поставить присваивание на место условия, а проверку на неравенство нулю опустить (при этом завершающий нуль копируется в цикле, и отдельного оператора для его присваивания не требуется). В результате цикл копирования строки принимает вид:

while ( *d++ = *src++);

Оба способа работы со строками (через массивы или указатели) приемлемы и имеют свои плюсы и минусы, но в общем случае лучше не изобретать велосипед, а пользоваться функциями библиотеки или определенным в стандартной биб­лиотеке C++ классом string, который обеспечивает индексацию, присваивание, сравнение, добавление, объединение строк и поиск подстрок, а также преобразо­вание из С-строк, то есть массивов типа char, в string, и наоборот.

ПРИМЕЧАНИЕ -

Строки string не обязательно должны состоять из символов типа char. Это позволяет ис­пользовать любой набор символов (не только ASCII), но для произвольного набора следу­ет определить собственную операцию копирования, что может снизить эффективность работы.