Функции 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(), найдите и устраните ее. Мы “забыли” прокомментировать код. Добавьте соответствующие комментарии, предполагая, что читатель знает стандартные функции для работы с С-строками.

<p id="AutBody_Root552"><strong>27.5.1. Строки в стиле языка С и ключевое слово const</strong></p>

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

char* p = "asdf";

p[2] = 'x';

  В языке С так писать можно, а в языке С++ — нет. В языке C++ строковый литерал является константой, т.е. неизменяемой величиной, поэтому оператор p[2]='x' (который пытается превратить исходную строку в строку "asxf") является недопустимым. К сожалению, некоторые компиляторы пропускают присваивание указателю p, что приводит к проблемам. Если вам повезет, то произойдет ошибка на этапе выполнения программы, но рассчитывать на это не стоит. Вместо этого следует писать так:

const char* p = "asdf"; // теперь вы не сможете записать символ

                        // в строку "asdf" с помощью указателя p

Эта рекомендация относится как к языку C, так и к языку C++.

Функция strchr() из языка C порождает аналогичную, но более трудноуловимую проблему. Рассмотрим пример.

char* strchr(const char* s,int c); /* найти c в константной строке s

                                      (не C++) */

const char aa[] = "asdf";  /* aa — массив констант */

char* q = strchr(aa,'d');  /* находит символ 'd' */

*q = 'x';                  /* изменяет символ 'd' в строке aa на 'x' */

  Опять-таки, этот код является недопустимым ни в языке С, ни в языке С++, но компиляторы языка C не могут найти ошибку. Иногда это явление называют трансмутацией (transmutation): функция превращает константы в не константы, нарушая разумные предположения о коде.

В языке C++ эта проблема решается с помощью немного измененного объявления стандартной библиотечной функции strchr().

char const* strchr(const char* s, int c); // найти символ c

                                          // в константной строке s

char* strchr(char* s, int c);             // найти символ c в строке s

Аналогично объявляется функция strstr().

<p id="AutBody_Root553"><strong>27.5.2. Операции над байтами</strong></p>

В далеком средневековье (в начале 1980-х годов), еще до изобретения указателя void*, программисты, работавшие на языках C (и C++), для манипуляции байтами использовали строки. В настоящее время основные стандартные библиотечные функции для работы с памятью имеют параметры типа void* и возвращают указатели типа void*, чтобы предупредить пользователей о непосредственной работе с памятью без контроля типов.

/* копирует n байтов из строки s2 в строку s1 (как функция strcpy): */

void* memcpy(void* s1, const void* s2, size_t n);

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже