Введение в языки программирования C и C++

Системные данные текстового типа

Показывать лекцию целиком

Числовая информация – не единственный тип данных, обрабатываемых с помощью ЭВМ. Очень большой пласт прикладных задач связан с обработкой текстовой информации. К ним относятся текстовые редакторы, всевозможные переводчики, компиляторы алгоритмических языков, информационно-справочные системы, системы обработки экономических данных и многие другие.

Языки C, C++ разделяют текстовые данные на примитивы, значением которых являются одиночные символы ( символьные данные ) и последовательности примитивов в виде цепочек символов, завершающихся установленным признаком конца ( строковые данные ). Символьные данные могут быть представлены как скалярными величинами (символьные константы, символьные переменные), так и массивами таких данных. Строковые данные наряду с константами и скалярными переменными тоже могут быть организованы в массивы, напоминающие привычные текстовые документы.

В ранних версиях систем программирования для кодировки символьных данных использовались так называемые кодовые страницы ( code page ). С одной из таких кодовых страниц в свое время выступила фирма IBM, предложившая в качестве стандарта 7-битовую кодировку управляющих и отображаемых символов на компьютерах серии IBM/360. Однако с развитием средств обработки символьной информации 128 различных кодов оказалось недостаточно, и для подключения кодов с символами национальных алфавитов производители средств вычислительной техники соответствующих стран начали подключать к стандарту IBM дополнительные наборы символов. Для кодировки новых расширений потребовался еще один двоичный разряд, и так возникли сменные наборы, дополнявшие устоявшуюся таблицу IBM. Каждая страна или группа стран построила свой уникальный набор из 256 символов, получивший название кодовой страницы. Чтобы отличать эти страницы друг от друга, им присвоили номера. Пользователям нашей страны досталась кодовая страница с номером 866. Довольно много хлопот разнообразие этих страниц вызывало у производителей программных продуктов, учитывающих специфику национальных алфавитов. Трудно приходилось и производителям устройств вывода (принтеры, плоттеры), т.к. в их конструкциях предусматривались аппаратно зашитые таблицы шрифтов.

В новых программных системах и аппаратных средствах планируется переход от так называемой 8-битной кодировки ASCII (American Standard Code for Information Interchange – американский стандартный код для обмена информацией) к 16-битной кодировке Unicode. В рамках этой кодировки станет возможным оперировать с 65536 различными символами, которых должно хватить на все страны мира. Многие современные операционные системы и программные продукты уже поддерживают стандарт Unicode.

Системы программирования BC 3.1 и BCB ориентированы на однобайтовую кодировку символьных данных на базе кодовых страниц ASCII. Сложность заключается в том, что под управлением MS-DOS в нашей стране используется кодовая страница с номером 866, а в операционных системах Windows 98/NT/2000/XP отечественная кодовая страница имеет номер 1251. У обеих кодовых страниц первые половины идентичны стандарту IBM. Здесь находятся коды управляющих символов (группа кодов от 0x00 до 0x1F ), различные разделители (точки, запятые, скобки и т.п.) и знаки операций, большие и малые буквы латинского алфавита. А вот вторые половины этих кодовых страниц устроены по-разному и из-за этого тексты на русском языке, подготовленные в среде Windows, отображаются консольными приложениями BCB в виде некоторой абракадабры. Это явление не наблюдалось в среде BC 3.1, т.к. там и набор программы и ее выполнение происходят в рамках одной и той же кодовой страницы.

4.1. Символьные данные и их представление в памяти ЭВМ

Одиночным символьным данным (константам и переменным) в оперативной памяти ЭВМ выделяется по одному байту, в которых хранятся соответствующие значения – числовые коды конкретных символов в соответствии с их кодировкой в той или иной странице.

Чтобы познакомиться с 866-й кодовой страницей предлагается выполнить следующую программу:

#include <stdio.h>
#include <conio.h>
void main()
{
  int i,j;
  gotoxy(37,1);
  printf("ASCII");
  for (i=32; i<=52; i++)
    {  gotoxy(1,i-29);
       for (j=i; j<=255; j+=21)
         printf("%c %3d  ",j,j);
    }
  getch();
}

Результат ее работы приведен на рис. 4.1.

(рис 4.1) Состав отображаемых символов ASCII (code page 866)

Отображаемые символы в таблице ASCII начинаются с кода 32 ( 0x20 ), которому соответствует символ "пробел". Коды больших русских букв начинаются с кода 128 ( 0x80 ), однако буква ' Ё ' расположена не на своем месте. Наблюдается разрыв в числовой последовательности кодов малых букв – после буквы ' п ' расположена группа кодов псевдографики. С их помощью в текстовом режиме работы дисплея строятся одинарные и двойные контуры таблиц. Малая буква ' ё ' также расположена не в алфавитном порядке. Все эти нюансы приходится учитывать при построении программы перекодировки русских текстов из кодовой страницы 1251 (т.е. из кодировки Windows) в кодировку MS-DOS. С такой операцией приходится сталкиваться при необходимости включения русских текстов в консольное приложение BCB.

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

'F', '%', '$', 'ы', '5', '+', '"', 'q', 'Я', ' '

Последняя константа в приведенном перечислении соответствует пробелу. Сам символ апострофа таким образом "закодировать" нельзя.

Второй способ заключается в записи шестнадцатеричного кода символа после знака "обратный слэш":

'\x27' 		(код символа "апостроф", 39)
'\x5C' 		(код символа \, 92)

Обратите внимание на то, что шестнадцатеричный код записывается без лидирующего нуля (в отличие от записи числовых шестнадцатеричных констант). Так можно записать любой управляющий код, расположенный в начале таблицы ASCII. Однако в языках C, C++ чаще используются Escape-последовательности, о которых речь шла при управлении выводом (см. табл. 3.6). Вот несколько примеров:

'\'' – символ "апостроф"
'\\' – символ "обратный слэш"

Третий способ заключается в записи восьмеричного кода символа после знака "обратный слэш":

'\47' 		(код символа "апостроф", 39)
'\134' 		(код символа \, 92)

Обратите внимание на то, что восьмеричный код записывается без лидирующего нуля (в отличие от записи числовых восьмеричных констант) и должен принадлежать диапазону [0, 377].

Символьные переменные объявляются с помощью спецификаторов char или unsigned char. Одновременно их можно проинициализировать тем или иным способом:

char ch1='Я',ch2='\x9F',ch3='\237',ch4=0x9F,ch5=0237,ch6=159;

Числовой способ инициализации гарантирует правильность вывода как в DOS-приложении, так и в консольном приложении Windows. Символьной инициализацией в консольных приложениях Windows можно пользоваться без проблем только для символов из первой половины таблицы ASCII.

4.2. Строковые данные и их представление в памяти ЭВМ

В языке C среди базовых типов данных строк как таковых не оказалось. Вместо этого язык C предлагает использовать одномерные символьные массивы, в которых хранятся те же строки в виде последовательности однобайтовых символов, завершающихся байтом с нулевым кодом. Для этого признака конца строки в состав Escape- последовательностей включен специальный код '\0', хотя можно было бы воспользоваться и другой комбинацией – '\x0'.

В языке C++ появился гораздо более удобный класс строковых данных string. Но знакомство с этим классом мы отложим на более поздний срок.

Значения строковых констант или начальные значения строковых "переменных" в отличие от символьных данных заключаются в двойные кавычки:

const char c1[]="ABCDEFGH";
  char str1[]="1234";
  char letter[]="a";
  char symbol='a';

Байт с нулевым кодом система автоматически добавляет вслед за последним символом строки. Поэтому для символьного массива c1 будет выделено 9 байтов, а для символьного массива str1 – 5 байтов. Обратите внимание на то, что массив letter занимает в памяти 2 байта, тогда как символьная переменная symbol – 1 байт. Так как строка представлена одномерным массивом символов, то доступ к каждому ее символу осуществляется самым обычным способом:

c1[3] – четвертый символ в массиве c1 (т.е. буква 'D')
  str1[0] – первый символ в массиве str1 (т.е. цифра '1')

Значение любого символа в строковой "переменной" можно изменить во время работы программы:

str1[3]='L';

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

str1[4]=5; //Байт с признаком конца строки испорчен
  str1[5]=6; //Испорчен байт с какими-то данными

4.3. Ввод текстовых данных во время работы программы

4.3.1. Форматный ввод

Список форматных указателей функции scanf предусматривает возможность ввода значений односимвольных ( %c ) и многосимвольных ( %s ) переменных:

#include <stdio.h>
void main()
{ char ch1,ch2;
  char str1[10];
  scanf("%c %c",ch1,ch2);
  scanf("%s",str1);
....................

Обратите внимание на то, что для ввода данных в скалярные переменные ch1 и ch2 в списке ввода необходимо указывать их адреса ( ch1, ch2 ), а при вводе в массив str1 – достаточно написать его имя. Дело в том, что имя массива одновременно выполняет роль адреса своего первого элемента. Поэтому str1 и str1[0] указывают на один и тот же адрес.

Ввод значений символьных переменных ch1 и ch2 можно организовать одним из двух способов. Во-первых, в строке ввода можно набрать два требуемых символа либо слитно, либо разделяя их хотя бы одним пробелом и нажать клавишу Enter. Во-вторых, можно набрать первый символ, предназначенный для переменной ch1, и нажать клавишу Enter. Затем повторить аналогичным образом ввод следующего символа.

Значение, предназначенное для строковой "переменной" str1, не должно содержать более 9 символов (признак конца строки система добавляет автоматически) и среди них не должен присутствовать пробел. Дело в том, что пробел при форматном вводе воспринимается как разделитель данных. Это не означает, что среди символов строки пробел вообще не допустим, просто для организации ввода в строку нескольких слов надо использовать другие средства.

Довольно неожиданно, но с помощью задания ширины поля ввода и одного форматного указателя можно за один прием ввести несколько символов в элементы символьного массива:

char q[20];
............
scanf("%20c",q); //ввод 20 символов в массив q

В отличие от ввода по форматному указателю %s в массив q здесь не записывается признак конца строки – вводятся только запрашиваемые символы, которые набираются в одной строке с последующим нажатием клавиши Enter.

Функция scanf предусматривает еще два интересных форматных указателя, которые обеспечивают ввод либо тех символов, которые указаны в заданном множестве, либо всех символов, которые не принадлежат заданному множеству. Например, для ввода цифр из диапазона от 0 до 9 такой указатель имеет вид %[0-9], а для ввода символов, не являющихся цифрами – %[^0-9]. Рассмотрим следующий пример, который не только демонстрирует ввод по таким форматным указателям, но и содержит непредвиденный пассаж, связанный с использованием "грязного" буфера ввода.

#include <stdio.h>
#include <conio.h>

void main()
{ char str[10];
  int j;
  printf("Enter 123ABC\n");
  scanf("%[0-9]",str);
  printf("str=%s\n",str);
  for(j=0; j<10; j++)
    printf("%3x",str[j]);
  printf("\nEnter DEF123\n");
  scanf("%[^0-9]",str);
  printf("str=%s\n",str);
  for(j=0; j<10; j++)
    printf("%3x",str[j]);
  getch();
}
//=== Результат работы ===
Enter 123ABC
str=123
 31 32 33  0  0  1  0  0  1  0
Enter DEF123
str=ABC 
DEF
 41 42 43  a 44 45 46  0  1  0

После ввода первой строки программе были переданы символы '123', вслед за которыми в массив str был записан нулевой байт – признак конца строки. Однако в буфере ввода остались невостребованными символы 'ABC' и код клавиши Enter (код 0xa ). После набора второй строки к содержимому буфера ввода добавились еще три символа 'DEF' и т.к. все семь первых символов не являются кодами цифр, то все они были переданы в массив str. При выводе первые три отобразились в одной строке, затем сработал управляющий код 0xa и три следующие символа были выведены в следующей строке. Для наглядности содержимое массива после каждого вывода по формату %s отображалось еще и в шестнадцатеричном формате. Значения байтов, начиная с str[4], объясняются тем, что массив str является локальным, и под него выделяется "грязная память". Если его описание вынести за пределы main, то он станет глобальным и будет расписан нулями.

Чтобы не пострадать от непредвиденного ввода символов, задержавшихся в буфере ввода, рекомендуется после обращения к функции scanf чистить буфер ввода с помощью функции fflush(stdin). Если бы мы включили в предыдущий пример обращение к функции fflush, то после ввода второй строки в массиве str оказались бы только символы 'DEF'.

4.3.2. Потоковый ввод

Потоковый ввод в символьные и "строковые" переменные организуется следующим образом:

#include <iostream.h>
void main()
{ char ch1,ch2;
  char str1[10];
  cin >> ch1 >> ch2;
  cin >> str1;
....................

Набор вводимой информации на клавиатуре осуществляется точно таким же образом, как и при форматном вводе.

4.3.3. Специальные функции ввода текстовых данных

Специальные функции ввода символьных данных getch() и getche() упрощают их набор (не приходится дополнительно нажимать клавишу Enter) и предоставляют дополнительные возможности. Ниже приводится программа и результат ее работы после нажатия на цифровую клавишу 5.

#include <stdio.h>
#include <conio.h>

void main()
{ char ch[4]={'1','2','3'};
  ch[1]=getch();
  printf("ch[0]=%c ch[1]=%c ch[2]=%c",ch[0],ch[1],ch[2]);
  getch();
  return;
}
//=== Результат работы ===
ch[0]=1 ch[1]=2 ch[2]=3

Функция getch (от get character – дай символ) организует ввод кода символа без эхо-сигнала, т.е. без отображения на экране знака, соответствующего нажатой клавише. Такая возможность может оказаться полезной при вводе секретных данных (пароль) или в ситуации, когда отображение символа нажатой клавиши может повредить текущее содержимое экрана. Очень часто эту функцию используют в качестве задержки работы программы до нажатия какой-либо клавиши.

Функция getche обеспечивает ввод символа, соответствующего нажатой клавише с выдачей эхо-сигнала.

Обе функции обращаются к буферу клавиатуры. Если к этому моменту буфер пуст, то происходит ожидание нажатия клавиши. Считанный символ из буфера клавиатуры выталкивается. Однако клавиши на клавиатуре разные. Большая их часть связана с отображаемыми символами – буквами, цифрами, знаками препинания и т.п. После их нажатия обращение к функциям getch/getche приводит к считыванию соответствующего кода ASCII. В частности, к "отображаемым" клавишам относятся клавиши Esc (код 27), Enter (код 13), комбинация Ctrl+Z (код 26 – признак конца файла). Но на клавиатуре присутствует ряд клавиш, с которыми ассоциируются управляющие символы, не представленные в таблице ASCII. К ним, в частности, относятся функциональные клавиши F1, F2, ..., стрелки управления курсором, клавиши Insert и Delete и др. От их нажатия в буфер клавиатуры поступает двухбайтовый код, содержащий в старшем байте 0, а в младшем байте так называемый scan-код (некий порядковый код, приписанный каждой клавише). В этом случае первое обращение к функциям getch/getche приводит к считыванию нулевого кода, а повторное обращение возвращает scan-код ранее нажатой клавиши. Таким образом, для анализа кода нажатой управляющей клавиши к функциям getch/getche приходится обращаться дважды (предварительно следует убедиться в том, что первое обращение возвратило 0).

Функция gets (от get string – дай строку) позволяет ввести в символьный массив текстовое значение, содержащее пробелы:

#include <stdio.h>
#include <conio.h>
void main()
{ char str[80];
  gets(str);
  printf("\nstr=%s",str);
  getch();
}

При потоковом вводе со стандартного устройства stdin можно запросить заданное количество k символов, среди которых может встретиться и пробел:

cin.getline(str,k);

При этом можно ввести не более чем k-1 символ, т.к. нужно помнить о резервном байте для признака окончания строки. Если строка, набираемая пользователем, содержит более чем k-1 символ, то продолжение строки будет проигнорировано. И даже последующий оператор ввода не сможет им воспользоваться. Если строка ввода содержит меньше, чем k-1 символ, то она будет введена целиком. Более того, с помощью еще одного параметра, – символа завершения операции, можно досрочно прекратить ввод:

cin.getline(str,k,'Q');

Если в строке ввода будет досрочно обнаружен символ 'Q', то он уже не вводится.

Следует упомянуть еще одну функцию форматного ввода cscanf, ориентированную на работу с конкретным устройством – клавиатурой. Обращаются к ней точно так же как и к функции scanf, но они не дублируют друг друга. И вот почему. Дело в том, что стандартные устройства ввода ( stdin ) и вывода ( stdout ) могут быть подменены другими носителями информации (например, файлами или принтером). А ввод с клавиатуры и вывод на экран дисплея, образующих в совокупности консоль (пульт) оператора, переназначить нельзя.

4.4. Вывод текстовых данных

При выводе текстовых данных особые проблемы возникают только в том случае, когда сообщения, содержащие русские буквы, готовятся в среде Windows (кодовая страница 1251), а выводятся консольным приложением в 866-й кодовой странице. В этом случае можно написать сравнительно несложную функцию конвертирования текстов из одной кодировки в другую. В кодовой странице 1251 буквы русского алфавита кодируются подряд, начиная с кода 192 (большая буква 'А' ) до кода 255 (малая буква 'я' ). Буквы 'Ё' и 'ё' имеют коды 164 и 184 соответственно. Поэтому при перекодировке необходимо:

  • коды букв, принадлежащие интервалу [192, 239] уменьшить на 64, чтобы вогнать их в интервал [128, 174];
  • коды букв, принадлежащие интервалу [240, 255] уменьшить на 16, чтобы вогнать их в интервал [224, 239];
  • коды букв Ё и ё заменить на 240 и 241 соответственно.
  • #include <stdio.h>
    #include <iostream.h>
    #include <conio.h>
    #include <string.h>
    
    char *to_866(unsigned char *s)
    { static unsigned char str[80];
      int j=0;
      while (s[j]!='\0')
      { str[j]=s[j];
        if(s[j]>=192  s[j]<=239) str[j]-=64;
        if(s[j]>=240  s[j]<=255) str[j]-=16;
        if(s[j]==164) str[j]=240;
        if(s[j]==184) str[j]=241;
        j++;
      }
      str[j]='\0';
      return str;
    }
    
    void main()
    { char s[]="Привет";
      cout << s << endl;
      cout <<to_866(s) << endl;
      getch();
    }
    
    //=== Результат работы ===

    В первой строке вывод реализован без перекодировки, а во второй – с перекодировкой.

    4.4.1. Форматный вывод

    Для форматного вывода символьных значений в функции printf используется форматный указатель %c, а для вывода строк – форматный указатель %s. При создании консольных приложений Windows можно воспользоваться программой перекодировки, аналогичной функции to_866.

    #include <stdio.h>
    #include <conio.h>
    void main()
    {
      char ch1='F';
      unsigned char ch2='5';
      char ch3[]="ABCD";
      printf("%c %c %s",ch1,ch2,ch3);
      getch();
    }
    //=== Результат работы ===
    F 5 ABCD

    4.4.2. Потоковый вывод

    В потоковом выводе единственная проблема может возникнуть в связи с перекодировкой русских сообщений в консольном приложении Windows.

    #include <iostream.h>
    #include <conio.h>
    void main()
    {
      char ch1='F';
      unsigned char ch2='5';
      char ch3[]="ABCD";
      cout<<ch1<<' '<<ch2<<' '<<ch3;
      getch();
    }
    //=== Результат работы ===
    F 5 ABCD

    4.4.3. Специальные функции вывода текстовой информации

    К дополнительным средствам вывода следует отнести функцию puts ( str ), передающую строку str на стандартное устройство stdout, и вывод на дисплей с помощью функции cprintf. Обращение к последней не отличается от обращения к функции printf, но дисплей не допускает переназначения потока вывода. Кроме того, при выводе на дисплей имеется возможность окрасить текст в тот или иной цвет.

    4.5. Операции над текстовыми данными

    4.5.1. Операции над символьными данными

    Значения символьных данных эквивалентны однобайтовым целым числам. Поэтому им можно присваивать целочисленные значения, равные соответствующим кодам таблицы ASCII, сравнивать на принадлежность тем или иным интервалам. Подобного рода операции упрощаются, если прибегнуть к группе специальных функций, прототипы которых сосредоточены в файле ctype.h. Все эти функции организованы по единому шаблону – их единственным аргументом является числовой код анализируемого символа. Возвращаемое каждой функцией значение либо равно 0, если соответствующая проверка дала отрицательный результат, либо отлично от нуля в случае истинности проверяемого условия. Перечень этих функций приведен в табл. 4.1.

    Функция Проверяемое условие
    isalnum(ch) Является ли ch цифрой или буквой латинского алфавита
    isalpha(ch) Является ли ch буквой латинского алфавита
    isascii(ch) Принадлежит ли ch первой половине таблицы ASCII
    iscntrl(ch) Принадлежит ли ch группе управляющих символов ( ch<0x20 )
    isdigit(ch) Является ли ch цифрой
    isgraph(ch) Является ли ch отображаемым символом ( 0x21<=ch<=0x7E )
    islower(ch) Является ли ch малой буквой латинского алфавита
    isprint(ch) Является ли ch отображаемым символом (0x20 $$\le$$ ch $$\le$$ 0x7E)
    ispunct(ch) Является ли ch символом-разделителем ( iscntrl || isspace )
    isspace(ch) Является ли ch обобщенным пробелом ( 0x20, 0x09,0x0A,0x0D )
    isupper(ch) Является ли ch большой буквой латинского алфавита
    isxdigit(ch) Является ли ch шестнадцатеричной цифрой

    В раздел type.h включены еще три функции преобразования аргумента ch. Результатом преобразования является возвращаемое значение функции:

  • toascii(ch) – возвращает код, образованный 7 младшими битами ch;
  • tolower(ch) – возвращает код строчной буквы, если ch является кодом заглавной буквы;
  • toupper(ch) – возвращает код заглавной буквы, если ch является кодом строчной буквы.
  • 4.5.2. Операции над строковыми данными

    Для обработки строк, представленных одномерными символьными массивами, в библиотеке системных функций предусмотрено довольно много различных операций. Прототипы этих функций сгруппированы в заголовочном файле string.h и большинство их названий начинается с префикса str (от string ). Условимся о некоторых обозначениях аргументов и их типах, чтобы не повторять их в приведенной таблице:

  • S, S1,S2 – указатель на символьный массив (как правило, имя массива);
  • CS – указатель типа const char * (т.е. неизменяемый массив или строковая константа – источник данных);
  • ch – код символа, обычно числовое значение типа int ;
  • k – количество символов.
  • Функция Выполняемое действие
    Определение длины строки
    strlen(CS) Возвращает количество символов в строке S
    Формирование строк
    strdup(CS) Запрашивает память, копирует туда содержимое CS и возвращает указатель типа char* на новую строку
    strcpy(S1,CS2) Копирует содержимое CS2 в S1, возвращает указатель на S1
    strncpy(S1,CS2,k) Копирует первые k символов из CS2 в S1, возвращает указатель на S1
    stpcpy(S1,CS2) Копирует CS2 в S1, возвращает указатель на конец S1
    strset(S,ch) Расписывает строку S символом ch, возвращает указатель на S
    strnset(S,ch,k) Повторяет k раз символ ch в строке S, возвращает указатель на S1
    Конкатенация строк
    strcat(S1,CS2) Приписывает содержимое CS2 в конец S1, возвращает указатель на S1 (длина массива S1 должна предусматривать такое расширение)
    strncat(S1,CS2,k) Присоединяет первые k символов CS2 к содержимому S1, возвращает указатель на S1
    Смена регистра
    strlwr(S) замена символов строки S кодами малых букв, действует только на буквы латинского алфавита
    strupr(S) замена символов строки S кодами больших букв, действует только на буквы латинского алфавита
    Переворот строки
    strrev(S) Перестановка символов строки S в обратном порядке
    Преобразование в числовые данные
    strtol(CS,ptr,r) Число, представленное в символьном виде в CS и записанное в системе счисления с основанием r, преобразуется в машинный формат числа типа long. В указатель ptr заносится адрес символа, прервавшего преобразования. Возвращаемое значение – результат преобразования.
    strtoul(CS,ptr,r) Аналогичное преобразование в длинное целое число без знака
    strtod(CS,ptr) Преобразование вещественного числа из символьного представления в машинный формат числа типа double.
    Сравнение строк
    strcmp(CS1,CS2) Возвращаемое значение равно 0, если CS1=CS2, больше 0, если CS1>CS2, и меньше 0, если CS1<CS2
    strncmp(CS1,CS2,k) Сравниваются только первые k символов строк CS1 и CS2
    stricmp(CS1,CS2) При сравнении игнорируется разница между кодами больших и малых букв
    strcmpi(CS1,CS2) Аналогичная операция, разница только в названии функций
    strnicmp(CS1,CS2,k) Сравнение первых k символов с игнорированием разницы между кодами больших и малых букв
    strncmpi(CS1,CS2,k) Аналогичная операция, разница только в названии функций
    Поиск символа
    strchr(CS,ch) Строка CS сканируется слева направо до обнаружения символа ch. Если он найден, возвращаемый указатель "смотрит" на этот символ в строке CS, если такого символа нет, то возвращаемый указатель равен null (т.е. 0)
    strrchr(CS,ch) Аналогичный поиск с конца строки CS.
    Поиск строки
    strstr(CS1,CS2) Поиск первого вхождения строки CS2 в строку CS1. Если поиск завершен успешно, возвращается указатель на первый символ найденной подстроки. В противном случае возвращается null
    Специальный поиск
    strpbrk(CS1,CS2) В строке CS1 ищется первый символ, содержащийся в CS2. Возвращается указатель на найденный символ или null.
    strspn(CS1,CS2) Определяется длина начального фрагмента CS1, целиком состоящая из символов CS2 (порядок символов роли не играет)
    strcspn(CS1,CS2) Определяется длина начального фрагмента CS1, который не содержит ни одного символа из CS2
    strtok(S1,CS2) Поиск в строке S1 лексем, разделенных символами CS2

    Некоторые из функций, приведенные в табл. 4.2, нуждаются в дополнительных пояснениях.

    В функциях strtol и strtoul, выполняющих преобразование символьного представления числа в соответствующий машинный формат, допускается задание r=0. В этом случае основание системы определяется символьной записью числа. Если строка начинается с символа '0', за которым следуют символы цифр, не превосходящих 7, то число считается восьмеричным. Если строка начинается с комбинации '0x' или '0X', вслед за которой располагаются шестнадцатеричные цифры, то считается, что r=16.

    В функции strtok лексемой считается цепочка символов, завершающаяся одним из предусмотренных символов-разделителей. При первом обращении к этой функции в строке S1 находится начальная лексема и возвращаемое значение является указателем на ее начальный символ. Одновременно в строку S1 на место обнаруженного символа-разделителя заносится нулевой байт. Это позволит в дальнейшем работать с найденной лексемой как со строкой. Для поиска следующих лексем в повторных обращениях к функции strtok вместо первого аргумента нужно задавать нулевой аргумент. Функция будет искать следующую лексему, расположенную правее принудительно вставленного нулевого байта. И так можно последовательно обнаружить все лексемы, содержавшиеся в строке S1. Для пояснения приведем следующий пример:

    #include <stdio.h>
    #include <conio.h>
    #include <string.h>
    void main()
    { char *ptr;
      ptr=strtok("FEB.14,2006",".,-/");
      while(ptr!=NULL)
      { printf("ptr=%s\n",ptr);
        ptr=strtok(NULL, ".,-/");
      }
      getch();
    }
    //=== Результат работы ===
    ptr=FEB
    ptr=14
    ptr=2006

    4.6. Управление дисплеем в текстовом режиме

    При запуске приложения MS-DOS или консольных приложений дисплей работает в текстовом режиме (в Windows такой режим эмулируется), для которого характерно разделение экрана на строки и столбцы (обычно строк 25, а столбцов 80, но существуют и другие текстовые режимы). На каждом пересечении строки и столбца находится условный прямоугольник – знакоместо, в котором размещается отображаемый символ. На экране выделяется текущее знакоместо, помеченное мерцающим курсором (мигающей черточкой или прямоугольником). Именно в этой позиции появляется символ, набираемый пользователем на клавиатуре, или символ, отображаемый программой.

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

    Очистку экрана выполняет функция clrscr(), ее название образовано от сокращения английских слов clear (очистить) и screen (экран).

    Для перемещения курсора в заданную позицию экрана используется функция gotoxy(x,y). Ее аргументы определяют номер столбца x ( 0<=x<80 ) и строки y ( 0<=y<25 ) того знакоместа, которое станет текущим.

    Функция window(x1,y1,x2,y2) позволяет выделить на экране прямоугольную область, в пределах которой будет происходить вывод. По умолчанию областью вывода считается весь экран, его левому верхнему углу соответствуют нулевой столбец и нулевая строка, а правому нижнему углу – 79-й столбец и 24-я строка. Иногда бывает полезно сузить область вывода с тем, чтобы в оставшейся части экрана расположить какую-то заготовку (формуляр бланка, например, или другую пояснительную информацию, не затираемую выводимыми данными и не смещающуюся при выводе). Знакоместо с координатами ( x1,y1 ) задает положение левого верхнего угла окна вывода, а знакоместо с координатами ( x2,y2 ) – положение правого нижнего угла окна вывода.

    Так как почти все современные дисплеи цветные, то текстовый режим предоставляет возможность раскрасить каждый выводимый символ. При этом имеется возможность автономно задать цвет фона знакоместа и цвет контура отображаемого символа. Дело в том, что в текстовом режиме для каждого символа, отображаемого на экране, выделено 2 информационных байта. В первом байте располагается код ASCII символа, а во втором хранятся его цветовые атрибуты (рис. 4.2)

    (рис 4.2) Цветовые атрибуты

    Цвет формируется в результате наложения трех цветовых компонент – красного ( R ), зеленого ( G ) и синего ( B ). Цвет символа может иметь повышенную яркость (признак J=1 ). Для привлечения внимания к сообщению на экране символ можно заставить мерцать (признак M=1 ).

    Для установки цвета символов во всех сообщениях, выдаваемых с помощью функции cprintf, предназначена функция textcolor(fc). Ее аргумент должен принадлежать диапазону [0, 15]. Цвет фона для последующего вывода по cprintf устанавливается с помощью функции textbackground(bc). Имеется возможность произвести установку цветовых атрибутов за один раз, обратившись к функции textattr. Ее единственным аргументом может быть одно из двух следующих выражений:

    (bc<<4)+fc      //цвет фона и цвет символов
    128+(bc<<4)+fc  //мерцание, цвет фона и цвет символов

    В качестве примера вывода разноцветного текста приведем следующую программу:

    #include <conio.h>
    void main()
    { int j;
      textbackground(0);
      clrscr();
      for(j=0; j<24; j++)
      { gotoxy(2*j+1,j+1);
        textcolor(128+j);
        textbackground(j+2);
        cprintf("Color palette");
      } 
      getch();
    }
    Вернуться к учебному плану