§3 Символьный тип данных. C-строка

  • Символьный тип данных
  • В C++ символьный тип данных char относится к целым типам, так как в переменной типа char скрывается, на самом деле, код символа в кодовой таблице (ASCII). Размер памяти отводимой на хранение объекта типа char – 1 байт. Напомним, что это позволяет хранить значения в диапазоне от 0 до 255. Этого достаточно, чтобы закодировать все символы ASCII (“аски”). Вывод символов по их кодам можно осуществить так:
    Программа 9.1

    #include <iostream>
    using namespace std;
    
    int main() {
    	for(int i = 33; i <= 127; i++)
            cout << i << '\t' << char(i) << endl;
    	return 0;
    }
    

    В программе используется явное преобразование типов: int → char.
    Объявление и инициализация переменной типа char:

    char c = 'A';
    

    Символьным литералом является один или два символа заключённые в одинарные кавычки (апострофы). Например: 'q', 'Я', '\n', '\t'.

  • Управляющие (Escape) последовательности
  • Управляющие последовательности используются для описания определённых специальных символов внутри строковых литералов.
    Некоторые управляющие последовательности:

    \'	одинарная кавычка
    \"	двойная кавычка
    \?	вопросительный знак
    \\	обратный слеш
    \0	нулевой символ
    \n	перевод строки - новая строка
    \t	горизонтальная табуляция
    \v	вертикальная табуляция
    

    Мы уже применяли символ '\n' для перевода на новую строку при выводе прямоугольных таблиц, например, матриц.
    Манипулятор endl, также осуществляет перевод на новую строку, но, в тоже время, производит сброс буфера вывода (а следовательно и всех форматов при использовании манипуляторов). Поэтому, для сохранения формата, там где нужно производить переход на новую строку, можно использовать '\n'.

  • Что такое строка?
  • Строка в С++ – это массив символов, в котором последний элемент имеет значение '\0' (нулевой символ). Это значение является признаком конца строки. Символьный массив не является строкой если он не заканчивается нулевым символом.

  • Инициализация строки
  • Способ инициализации строки, как массива не является удобным:

    char str1[] {'Э', 'т', 'о', ' ', 'с', 'т', 'р', 'о', 'к', 'а', '!', '\0'};
    

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

    char str2[] = "Это тоже строка!";
    

    В этом случае добавлять нулевой символ не нужно. При вводе символьного массива (далее символьной строки) с клавиатуры нулевой символ также будет добавлен автоматически.
    Использование потока cin для инициализации символьной строки:

    const int buf = 80;
    char myStr[buf];
    cout << "Введите строку: ";
    cin >> myStr;
    

    В этом фрагменте константой buf определяется размер массива. Необходимо помнить, что в С++ отсутствует контроль выхода за границы массива. Также необходимо помнить о том, что размер массива должен быть достаточен для включения нулевого символа. Существует возможность ограничить количество вводимых символов с помощью манипулятора setw():

    cin >> setw(buf) >> myStr;
    

    Если будет введена строка, содержащая пробелы, то первый же пробел оператор извлечения (>>) будет считать нулевым символом и отправит в массив только символы предшествующие пробелу, а все остальное будет оставлено на очереди в потоке (который, следовательно, потребуется очистить).
    Программа 9.2.

    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    int main() {
    	const int buf = 80;
    	char myStr[buf];
    	cout << "Введите строку: ";
    	cin >> setw(buf) >> myStr;
    	cout << "Вы ввели строку: "
    	     << endl
    	     << myStr
    	     << endl;
    	return 0;
    }
    
    Введите строку: Это моя первая строка
    Вы ввели строку: 
    Это
    

    Для чтения строки, имеющей символы пробела, необходимо использовать функцию get(). Эта функция является методом класса istream, поэтому вызывается как функция-член этого класса: cin.get(). Исправим программу 9.2:

    const int buf = 80;
    char myStr[buf];
    cout << "Введите строку: ";
    cin.get(str, buf);
    cout << "Вы ввели строку: "
         << endl
         << myStr
         << endl;
    
  • Функции get() и getline()
  • 1. Функция get()

    cin.get()
    cin.get(str, buff)
    

    Функция get() считывает символы в массив, но оставляет нулевой символ в потоке ввода. Функция get() имеет два аргумента: имя символьного массива и его размер. Если функция используется без аргументов, то произойдет считывание символа и удаление его из потока. Обычно функция get() используется без аргументов, если необходимо удалить в очереди потока нулевой символ (программа 9.3. стр. 10 и 13).
    Программа 9.3.

    #include <iostream>
    using namespace std;
    
    int main() {
    	const int buf = 80;
    	char myStr1[buf];
    	char myStr2[buf];
    	cout << "Введите первую строку: ";
    	cin.get(myStr1, buf);
    	cin.get();
    	cout << "Введите вторую строку: ";
    	cin.get(myStr2, buf);
    	cin.get(); // В данной программе можно опустить
    	cout << "Первая строка:\n"
    		 << myStr1
    		 << endl;
    	cout << "Вторая строка:\n"
    		 << myStr2
    		 << endl;
    	return 0;
    }
    
    Введите первую строку: Это первая строка
    Введите вторую строку: Это вторая строка
    Первая строка:
    Это первая строка
    Вторая строка:
    Это вторая строка
    

    2. Функция getline()

    getline(str, buff, char_delim);
    

    Функция имеет три аргумента. Два обязательных: имя массива и размер передаваемого массива с учетом символа конца строки. Третий аргумент (не обязательно) используется для указания завершающего символа. Если третьего аргумента нет, то предполагается, что завершающий символ — "\0". Функция считывает все символы (с учетом символа "\0") пока не встретит завершающий символ (или "\0", если завершающий символ не указан в качестве третьего аргумента). Функция считывает завершающий символ, но в символьный массив его не включает и в потоке ввода его не оставляет.
    При выводе символьного массива не забывайте завершать его endl или '\n'.
    При использовании оператора вставки "<<" и имени массива он выводится одной строкой, так, как если бы мы использовали переменную строки.

  • Функции для работы с C-строкой
  • Стандартная библиотека языка C++ предоставляет набор функций для работы со строками в стиле С.
    Заголовочный файл cctype
    isalnum проверяет, является ли символ буквенно-цифровым
    isalpha проверяет, является ли символ буквенным
    isdigit проверяет, является ли символ цифрой
    isspace проверяет, является ли символ символом пробела
    islower проверяет, является ли символ символом в нижнем регистре
    isupper проверяет, является ли символ символом прописной буквы
    ispunct проверяет, является ли символ символом пунктуации
    tolower преобразует символ в нижний регистр
    toupper преобразует символ в верхний регистр
    Все функции имеют следующий формат:

    int имя_функции(int код_символа);
    

    Следовательно, может потребоваться преобразования int → char или наоборот, например:

    s[i] = char(tolower(int(s[i])));
    

    понизит регистр символов.
    Пример. Дана строка подсчитать в ней количество букв, пробелов и цифровых символов.
    Программа 9.4.

    #include <iostream>
    #include <cctype>
    #include <cstring>
    using namespace std;
    
    int main() {
    	int k = 0, l = 0, m = 0;
    	const int buf = 80;
    	char myStr[buf];
    	cout << "Введите строку:\n";
    	cin.getline(myStr, buf);
    	for (auto i = 0; i < strlen(myStr); i++) {
    		if (isalpha(myStr[i])) k++;
    		if (isspace(myStr[i])) l++;
    		if (isdigit(myStr[i])) m++;
    	}
    	cout << "Всего в строке:"
    		 << endl
    		 << "Букв - "
    		 << k
    		 << endl
    		 << "Пробелов - "
    		 << l
    		 << endl
    		 << "Цифр - "
    		 << m
    		 << endl;
    	return 0;
    }
    
    Введите строку:
    dddddddd 234 5 E ## %%ffff
    Всего в строке:
    Букв - 13
    Пробелов - 5
    Цифр - 4
    

    Заголовочный файл cstdlib
    atof преобразует строку в значение с плавающей точкой
    atoi, atol, atoll преобразуют строку в целое число
    strtol, strtoll преобразуют строку в целое число
    strtoul, strtoull преобразуют строку в целое число без знака
    strtof, strtod, strtold преобразуют строку в значение с плавающей точкой

    Заголовочный файл cstring
    strcpy(dst, src) копирует строку src в строку dst
    Пример. Скопировать в строку s1 начиная с пятой позиции, символы строки s2 начиная с третьей позиции (отсчет позиции с 0)
    Программа 9.5.

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int main() {
        int buf = 80;
        char s1[buf];
        char s2[buf];
        cout << "Введите строку s1:" << endl;
        cin.getline(s1, buf);
        cout << "Введите строку s2:" << endl;
        cin.getline(s2, buf);
        strcpy(s1 + 5, s2 + 3); 
        // равносильно strcpy(&s1[5], &s2[3]);
        cout << s1 << endl;
        return 0;
    }
    
    Введите строку s1:
    1234567890
    Введите строку s2:
    1234567890
    123454567890
    

    strncpy(dst, src, len) копирует len символов строки (без учета нуля) src в строку dst; третий аргумент не обязательный.
    strcat(dst, src, len) дописывает len символов (без учета нуля) строки src в конец dest; третий аргумент не обязательный.
    strlen(str) возвращает длину заданной строки (см. программу 9.4)
    strcmp сравнивает две строки: возвращает 0, если строки одинаковые, 1, если первая строка больше, и -1, если меньше
    strstr(dest, src) находит первое вхождение подстроки src в строке dest.
    Программа 9.6.

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int main() {
    	const int buf = 80;
    	char myStr1[buf];
    	char myStr2[buf];
    	cout << "Введите строку:\n";
    	cin.getline(myStr1, buf);
    	cout << "Введите подстроку для поиска:\n";
    	cin.getline(myStr2, buf);
    	if (strstr(myStr1, myStr2))
    		cout << "Подстрока найдена!" << endl;
    	else
    		cout << "Подстрока не найдена!" << endl;
    	return 0;
    }
    

    Примечание. Функция strstr возвращает, на самом деле, указатель на первый символ подстроки, найденной в dest, или NULL, если такой символ не найден. Таким образом, в программе 9.6 выражение условия (strstr(myStr1, myStr2)) возвращающее указатель (не нулевое значение), будет расцениваться как true.
    Все функции можно посмотреть здесь

  • Вопросы
  • 1. Какие выражения правильные, а какие нет?

    '\n\n'
    "\n\n"
    cout << endl;
    cout << "\n";
    cout << \n;
    cout << \n
    

    2. Для чего используется символ '\0'?
    3. В чем отличие функции getline от функции get?

  • Практические задания
  • 1. Дан символ C. Вывести два символа, первый из которых предшествует символу C в кодовой таблице, а второй следует за символом C.
    2. Дано целое число N (1 ≤ N ≤ 26). Вывести N первых прописных (то есть заглавных) букв латинского алфавита.


Print Friendly, PDF & Email

Добавить комментарий