Работа со строками и преобразование данных |
Строковые переменныеВстроенный тип данных «строка» в C/C++ отсутствует. С точки зрения компилятора и стандартной библиотеки, строка — это массив элементов типа char, последним элементом которого является двоичный ноль (то есть символ, код которого равен нулю). Допускается присваивание таким массивам так называемых строковых литералов — последовательностей символов, заключенных в двойные кавычки. В конец каждого такого литерала компилятор автоматически добавляет символ с кодом 0. Рассмотрим небольшой пример:
Все три объявления в приведенном выше примере абсолютно равнозначны; заметим, что в случае «формальной» инициализации (переменная str2) требуется явное указание завершающего нулевого символа. В соответствии с тем, что компилятор C/C++ воспринимает имя массива как адрес его первого элемента, синтаксически допустимым и правильным является объявление переменной str3 как указателя. Именно эта форма и используется чаще всего; более того, все функции стандартной библиотеки, предназначенные для работы со строками, используют именно формальный тип «указатель на char». Необходимо отметить, что компилятор от Microsoft помещает строковые литералы в область, доступную только для чтения, поэтому выполнение следующего примера завершается с ошибкой «access violation»:
Чтобы иметь возможность модифицировать содержимое строки, соответствующую переменную необходимо формально объявлять как массив:
В этом случае, содержимое строкового литерала будет скопировано в стек и изменение этой копии не вызовет никаких нареканий со стороны операционной системы. Управляющие последовательностиДля вставки в строку «непечатных» (с кодами меньше 32) или имеющих в C/C++ специальное значение символов, необходимо использовать так называемые управляющие последовательности, начинающиеся с символа «обратный слэш»:
\a — звонок; Кроме того, в строку можно вставить любой символ, указав его восьмеричный или шестнадцатеричный код:
\ooo
— символ с восьмеричным кодом ooo; Следующие две строки эквивалентны:
Функции обработки строк
Еще раз подчеркнем, что все функции обработки строк, предоставляемые стандартной библиотекой, считают признаком конца строки первый символ с кодом 0, который присутствует в этой строке. Таким образом, при выполнении любых действий над строковой переменной, объявленной как
слово «City» будет игнорироваться. Рассмотрим основные функции обработки строк. strcpychar* strcpy( char* dest, const char* src ); Копирует строку src в dest и возвращает dest. Пример использования:
strcatchar* strcat( char* dest, const char* src ); «Дописывает» строку src в конец строки dest и возвращает dest. Пример использования:
strlenint strlen( const char* src ); Возвращает длину строки src, то есть количество символов до завершающего нуля. Пример использования:
strchrchar* strchr( const char* src, char chr ); Ищет первое вхождение символа chr в строку src и возвращает указатель на часть строки, начинающуюся с искомого символа. Если символ chr отсутствует в строке src, функция возвращает NULL. Пример использования:
strrchrchar* strrchr( const char* src, char chr ); Ищет последнее вхождение символа chr в строку src и возвращает указатель на часть строки, начинающуюся с искомого символа. Если символ chr отсутствует в строке src, функция возвращает NULL. Пример использования:
strstrchar* strstr( const char* str, const char* substr ); Ищет первое вхождение строки substr в строку str и возвращает указатель на часть строки, начинающуюся с искомой подстроки. Если строка substr отсутствует в строке str, функция возвращает NULL. Пример использования:
strcmpint strcmp( const char* str1, const char* str2 ); Сравнивает строки str1 и str2. Если эти строки эквивалентны, функция возвращает 0; в противном случае, возвращается отрицательное значение, если строка str1 «меньше» строки str2, или положительное значение, если строка str1 «больше» строки str2. «Меньше» и «больше» в данном случае определяется разницей кодов первых несовпадающих символов. Пример использования:
_stricmpint _stricmp( const char* str1, const char* str2 ); Сравнивает строки str1 и str2 аналогично функции strcmp, но без учета регистра символов. Данная функция не входит в стандарт ANSI и относится к категории «Microsoft specific». Пример использования:
strtokchar* strtok( char* src, const char* seps ); Последовательно разбивает строку src на лексемы (токены), считая разделителями все символы строки seps. При каждом вызове возвращается указатель на очередную найденную лексему или NULL, если достигнут конец строки src. Отметим, что данная функция модифицирует исходную строку. Пример использования:
Обратите внимание, что указатель на исходную строку передается только при первом вызове функции; при последующих вызовах для работы с этой же строкой необходимо в качестве ее адреса передавать значение NULL. Естественно, что в реальных случаях обработка лексем выполняется в цикле, завершающемся при достижении конца исходной строки:
Текстовый ввод/вывод
Поскольку нашей основной целью является создание Windows-приложений, взаимодействующих с пользователем посредством GUI, мы рассмотрим только две функции стандартной библиотеки, предназначенные для текстового ввода/вывода. putsint puts( const char* src ); Выводит на экран строку src, переводит курсор в начало следующей строки экрана и возвращает количество выведенных символов. getschar* gets( char* dest ); Записывает в dest введенную с клавиатуры строку и возвращает dest. Признаком конца ввода является символ перевода строки, генерируемый при нажатии пользователя на клавишу Enter. Заметим, что сам этот символ не копируется в dest. Функции преобразования данных
Поскольку Windows-приложения имеют возможность обмениваться с пользователем только текстовой информацией, периодически возникает необходимость преобразования чисел в их строковое представление и обратно — для обработки в программе уже двоичных данных. Ниже мы рассмотрим функции, предназначенные для выполнения таких преобразований. atoiint atoi( const char* str ); Преобразует строковое представление целого числа str в двоичное и возвращает его. Преобразование прекращается на первом недопустимом символе; если такой символ окажется самым первым в строке, функция вернет значение 0. Пример использования:
atollong atol( const char* str ); Под Win32 эта функция полностью аналогична atoi. strtolПри необходимости более гибко обрабатывать ошибки преобразования, можно воспользоваться функцией long strtol( const char* str, char** end_ptr, int radix ); которая преобразует строковое представление целого числа str в системе счисления с основанием radix в двоичное и возвращает его. При этом, в переменную по адресу end_ptr будет записан указатель на символ, который прервал обработку строки str. Пример использования:
atofdouble atof( const char* str ); Преобразует строковое представление дробного числа str в двоичное и возвращает его. Преобразование прекращается на первом недопустимом символе; если такой символ окажется самым первым в строке, функция вернет значение 0.0. Заметим, что исходная строка может содержать как десятичное, так и экспоненциальное представление дробного числа. strtodПри необходимости более гибко обрабатывать ошибки преобразования, можно воспользоваться функцией double strtod( const char* str, char** end_ptr ); которая преобразует строковое представление дробного числа str в двоичное и возвращает его, записывая по адресу end_ptr указатель на символ, который прервал обработку строки str. Использование этой функции аналогично strtol. _itoachar* _itoa( int number, char* dest, int radix ); Записывает по адресу dest строковое представление целого числа number по основанию radix и возвращает dest. Пример использования:
_ltoachar* _ltoa( long number, char* dest, int radix ); Под Win32 эта функция полностью аналогична _itoa. _ultoachar* _ultoa( unsigned long number, char* dest, int radix ); Аналогична функции _ltoa, но предназначена для преобразования беззнаковых целых чисел. _gcvtchar* _gcvt( double number, int num_dig, char* dest ); Записывает по адресу dest строковое представление дробного числа number и возвращает dest. Через параметр num_dig необходимо передать требуемое число знаков строкового представления. Заметим, что если данная функция не сможет представить исходное число в десятичной форме с требуемым количеством знаков, то будет выбрана экспоненциальная форма. При преобразовании в десятичную форму, функция отбрасывает незначащие нули. _fcvtchar* _fcvt( double number, int num_dec, int* dec_pos, int* has_sign ); Возвращает адрес буфера, содержащего строковое представление дробного числа number в десятичной форме; заметим, что этот буфер перезаписывается при каждом вызове функции. Через параметр num_dec необходимо передать требуемое количество десятичных знаков; при необходимости исходное число будет округлено или дополнено нулями. В переменную по адресу dec_pos будет записана требуемая позиция десятичной точки в возвращенной строке; при этом, если целая часть числа равна 0, то по этому адресу будет записано отрицательное или нулевое значение. В переменную по адресу has_sign записывается ненулевое значение для отрицательного исходного числа и 0 — в противном случае. Таким образом, возвращаемая данной функцией строка не содержит ни знака, ни десятичной точки; ниже рассматривается несколько примеров:
_ecvtchar* _ecvt( double number, int num_dec, int* dec_pos, int* has_sign ); Данная функция полностью аналогична _fcvt, за исключением того, что исходное число представляется в экспоненциальной форме. Заметим, что эта функция использует тот же буфер, что и _fcvt. sprintfint sprintf( char* dest, const char* fmt, ... ); Записывает в буфер по адресу dest строку, сформированную на основании форматирующей строки fmt и произвольного количества необязательных аргументов. Строка fmt, помимо обычных символов, может содержать так называемые форматирующие последовательности. Каждая такая последовательность соответствует одному необязательному аргументу; она начинается с символа «%» и имеет в общем случае форму %fw.pst Здесь t — это один символ, определяющий тип аргумента, строковое представление которого должно быть подставлено на место данной форматирующей последовательности, и вид выполняемого преобразования. Это обязательная составляющая форматирующей последовательности; допустимо использование следующих символов:
Необязательная часть f форматирующей последовательности определяет выравнивание преобразованного аргумента, необходимость отображения его знака, etc, и может состоять из одного или нескольких символов, перечисленных ниже:
Необязательная составляющая w задает требуемую минимальную ширину преобразованного аргумента; заметим, что аргумент будет выведен полностью, даже если заданное значение окажется недостаточным. Необязательная составляющая p определяет точность представления аргумента; ее интерпретация зависит от типа этого аргумента:
Необязательная составляющая s «уточняет» размер целочисленного аргумента и может быть одним из следующих символов:
Если в формируемую строку необходимо вставить символ «%», то его следует написать два раза подряд. Ниже приведен пример использования функции sprintf:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||