Читать интересную книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 296 297 298 299 300 301 302 303 304 ... 337
прежнем участке, а может и перенести его содержимое во вновь выделенную область памяти. Даже не думайте применять функцию realloc() к области памяти, выделенной с помощью оператора new.

Используя стандартную библиотеку языка C++, этот код можно переписать примерно так:

vector<char> buf;

char c;

while (cin.get(c)) buf.push_back(c);

Более подробное обсуждение стратегий ввода и распределения памяти можно найти в статье “Learning Standard C++ as a New Language” (см. список библиографических ссылок в конце раздела 27.1).

27.5. Строки в стиле языка С

Строка в языке C (в литературе, посвященной языку С++, ее часто называют С-строкой (C-string), или строкой в стиле языка С (C-style)) — это массив символов, завершающийся нулем. Рассмотрим пример.

char* p = "asdf";

char s[ ] = "asdf";

В языке C нет функций-членов, невозможно перегружать функции и нельзя определить оператор (такой как ==) для структур. Вследствие этого для манипулирования строками в стиле языка С необходим набор специальных функций (не членов класса). В стандартных библиотеках языков C и C++ такие функции определены в заголовочном файле <string.h>.

size_t strlen(const char* s); /* определяет количество символов */

char* strcat(char* s1, const char* s2);     /* копирует s2 в конец s1 */

int strcmp(const char* s1, const char* s2); /* лексикографическое сравнение */

char* strcpy(char* s1,const char* s2);           /* копирует s2 в s1 */

char* strchr(const char *s, int c);              /* копирует c в s */

char* strstr(const char *s1, const char *s2);    /* находит s2 в s1 */

char* strncpy(char*, const char*, size_t n);     /* сравнивает n символов */

char* strncat(char*, const char, size_t n);      /* strcat с n символами */

int strncmp(const char*, const char*, size_t n); /* strcmp с n символами */

Это не полный список функций для работы со строками, но он содержит самые полезные и широко используемые функции. Кратко проиллюстрируем их применение.

 

 Мы можем сравнивать строки. Оператор проверки равенства (==) сравнивает значения указателей; стандартная библиотечная функция strcmp() сравнивает значения C-строк.

const char* s1 = "asdf";

const char* s2 = "asdf";

if (s1==s2) { /* ссылаются ли указатели s1 и s2 на один и тот же

                 массив? */

              /* (обычно это нежелательно) */

}

if (strcmp(s1,s2)==0) { /* хранят ли строки s1 и s2 одни и те же

                           символы? */

}

Функция strcmp() может дать три разных ответа. При заданных выше значениях s1 и s2 функция strcmp(s1,s2) вернет нуль, что означает полное совпадение. Если строка s1 предшествует строке s2 в соответствии с лексикографическим порядком, то она вернет отрицательное число, и если строка s1 следует за строкой s2 в лексикографическом порядке, то она вернет положительное число. Термин лексикографический (lexicographical) означает “как в словаре.” Рассмотрим пример.

strcmp("dog","dog")==0

strcmp("ape","dodo")<0 /* "ape" предшествует "dodo" в словаре */

strcmp("pig","cow")>0 /* "pig" следует после "cow" в словаре */

Результат сравнения указателей s1==s2 не обязательно равен 0 (false). Механизм реализации языка может использовать для хранения всех строковых литералов одну и ту же область памяти, поэтому можем получить ответ 1 (true). Обычно функция strcmp() хорошо справляется со сравнением С-строк.

Длину С-строки можно найти с помощью функции strlen().

int lgt = strlen(s1);

Обратите внимание на то, что функция strlen() подсчитывает символы, не учитывая завершающий нуль. В данном случае strlen(s1)==4, а строка "asdf" занимает в памяти пять байтов. Эта небольшая разница является источником многих ошибок при подсчетах.

Мы можем копировать одну С-строку (включая завершающий нуль) в другую.

strcpy(s1,s2); /* копируем символы из s2 в s1 */

Программист должен сам гарантировать, что целевая строка (массив) имеет достаточный размер, чтобы в ней поместились символы исходной строки.

Функции strncpy(), strncat() и strncmp() являются версиями функций strcpy(), strcat() и strcmp(), учитывающими не больше n символов, где параметр n задается как третий аргумент. Обратите внимание на то, что если в исходной строке больше n символов, то функция strncpy() не будет копировать завершающий нуль, поэтому результат копирования не будет корректной С-строкой. Функции strchr() и strstr() находят свой второй аргумент в строке, являющейся их первым аргументом, и возвращают указатель на первый символ совпадения. Как и функция find(), они выполняют поиск символа в строке слева направо. Удивительно, как много можно сделать с этими простыми функциями и как легко при этом допустить незаметные ошибки. Рассмотрим простую задачу: конкатенировать имя пользователя с его адресом, поместив между ними символ @. С помощью класса std::string это можно сделать так:

string s = id + '@' + addr;

С помощью стандартных функций для работы с С-строками этот код можно написать следующим образом:

char* cat(const char* id, const char* addr)

{

  int sz = strlen(id)+strlen(addr)+2;

  char* res = (char*) malloc(sz);

  strcpy(res,id);

  res[strlen(id)+1] = '@';

  strcpy(res+strlen(id)+2,addr);

  res[sz–1]=0;

  return res;

}

Правильный ли ответ мы получили? Кто вызовет функцию free() для строки, которую вернула функция cat()?

ПОПРОБУЙТЕ

Протестируйте функцию cat(). Почему в первой инструкции мы добавляем число 2? Мы сделали глупую ошибку в функции cat(), найдите и устраните ее. Мы “забыли” прокомментировать код. Добавьте соответствующие комментарии, предполагая, что читатель знает стандартные функции для работы с С-строками.

27.5.1. Строки в стиле языка С и ключевое слово const

Рассмотрим следующий пример:

char* p = "asdf";

p[2] = 'x';

 

 В языке С так писать можно, а в языке С++ — нет. В языке C++ строковый литерал является константой, т.е. неизменяемой величиной, поэтому оператор p[2]='x' (который пытается превратить исходную строку в строку "asxf") является недопустимым. К сожалению, некоторые компиляторы пропускают присваивание указателю p, что приводит к проблемам. Если вам повезет, то произойдет ошибка на этапе выполнения программы, но
1 ... 296 297 298 299 300 301 302 303 304 ... 337
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп.
Книги, аналогичгные Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Оставить комментарий