Основы программирования на С++ для начинающих

Строки в C++ и символьные массивы

Со строками мы с вами работали практически в каждой нашей программе и до этого урока. Точнее со строковыми константами – последовательностью символов в двойных кавычках. Нам часто приходилось выводить на экран ту или иную  информацию. Например:

строки в С++

Текст в кавычках и есть строковая константа.  Кавычки используются для определения начала и конца строковой константы и её частью не являются.

Достаточно часто  необходимо не только печатать какие-то короткие сообщения по ходу программы, а и работать с определённым текстом, хранить его где-то, обращаться к нему и редактировать, по необходимости. К строковой константе, рассмотренной выше, мы не сможем обратиться в программе, например для того, чтобы перезаписать её (мы не знаем ни ее имени ни адреса в памяти).  Сейчас вы узнаете об одном из способов работы со строками в C++. Позже мы познакомимся ещё с одним способом –   использованием класса string.

Итак о первом: в C++ для хранения строк  используют символьные массивы. Это такие же массивы, как мы с вами уже рассматривали в статье о массивах в С++, но хранят они не числовые данные, а символьные. Можно представить символы такого массива расположенными последовательно в соседних ячейках памяти – в каждой ячейке хранится один символ и занимает один байт. Один байт потому, что каждый элемент символьного массива имеет тип  char. Последним символом каждой такой строки является символ \0 (нулевой символ). Например:

строки в С++, символьные массивы в С++

Сам текст, включая пробел, состоит из 11-ти символов. Если бы  в последней ячейке находилась например . (точка), а не нулевой символ \0 – для компилятора это уже не строка. И работать с таким набором символов надо было бы, как с обычным массивом – записывать данные в каждую ячейку отдельно и выводить на экран посимвольно (при помощи цикла):

строки в С++, символьные массивы в С++

К счастью в C++ есть куда более удобный способ инициализации и обращения к символьным массивам –  строкам. Для этого последним символом такого массива обязательно должен быть нулевой символ \0. Именно он делает набор символов строкой, работать с которой, гораздо легче, чем с массивом символов.

Объявляется строка таким образом – создаем массив типа char, размер в квадратных скобках указывать не обязательно (его подсчитает компилятор), оператор = и в двойных кавычках пишем необходимый текст. То есть инициализируем массив строковой константой:

Прописывать нулевой символ не надо. Он присутствует неявно и добавляется в каждую такую строковую константу автоматически. Таким образом, при том что мы видим 11 символов в строке, размер массива будет 12, так как \0 тоже символ и занимает один байт памяти. Займет он последнюю ячейку этого символьного массива.  

Как видите, для вывода строки на экран, достаточно обратиться к ней по имени: cout << str << endl; cout будет выводить на экран символ за символом, пока не встретит в одной из ячеек массива символ конца строки \0 и вывод прервется. Такое обращение для обычного символьного массива (массива без \0) недопустимо. 

Так как компилятор выводил бы символы на экран даже выйдя за рамки массива, пока не встретил бы в какой-то ячейке памяти символ \0. Можете попробовать подставить в первый пример вместо цикла оператор cout << str << endl;  и увидите, что получится. У меня показало вот так:

строки в С++, символьные массивы в С++

Хочу обратить ваше внимание на отличие символьной константы (в одинарных кавычках – 'f', '@' ) от строковой константы (в двойных кавычках "f", "@" ). Для первой, компилятором C++ выделяется один байт для хранения в памяти. Для символа записанного в двойных кавычках, будет выделено два байта памяти – для самого символа и для нулевого (добавляемого компилятором).

Что если  строку должен будет ввести пользователь с клавиатуры? В этом случае необходимо объявить массив типа char с указанием его размера достаточного для хранения вводимых символов, включая \0.  Не забывайте об этом нулевом символе. Если вам надо хранить 3 символа в массиве, его размер должен быть на единицу больше – то есть 4. 

строки в С++, символьные массивы в С++

Используя пустые кавычки при инициализации, мы присваиваем каждому элементу массива значение \0. Таким образом строка будет очищена от “мусора” других программ. Даже если пользователь введет название содержащее меньшее количество символов, следующий за названием будет символ \0. Это позволит избежать нежелательных ошибок. В памяти эта строка будет выглядеть так:

строки в С++, символьные массивы в С++

Кстати, если допустим перезаписать 11-ю ячейку этого массива –  str[11] = '\0';

строки в С++, символьные массивы в С++

и отобразить массив на экране, то увидим только purecodecpp  не смотря на то, что в ячейках 12, 13, 14 остались храниться символы. Нулевой символ сыграет свою главную роль при выводе на экран и всё, что находится за ним не будет показано.

Поговорим о вводе строк с клавиатуры подробней. Дело в том, что существуют определённые проблемы о которых надо знать и которые необходимо научиться решать. В следующей программе при вводе строки не всё будет так гладко, как нам хочется:

строки в С++, символьные массивы в С++

Не заморачивайтесь пока над тем, что ввод через cin необходимо производить латиницей. О том как корректно ввести кириллицу будет рассказано в отдельной статье. Тут вы видите, что цитату мы ввели, но при выводе на экран, видим только первое слово. Это связано с тем, что мы не можем ввести нулевой символ с клавиатуры, а cin воспринимает пробел, символ новой строки и табуляцию, как конец строки. То есть в нашем случае cin прочитал только первое слово, запятую и автоматически добавил знак конца строки. Остальные введенные данные поместил во входную очередь.

Решается эта проблема просто. В C++ есть функции get() и getline() , которые мы можем использовать вместе с cin. Они похожи, но чаще используется getline(). В этой статье мы не будем рассматривать их отличие. Допишем в нашу программу ввод с getline ():

строки в С++, символьные массивы в С++

Вы видите, что в скобках мы указали для функции два аргумента – в какой массив считать символы (имя массива) и размер этого массива – строка 11. Результат нам подходит  – всё отобразилось правильно.  cin.getline() считывает в массив всю строку включая пробелы и табуляции, пока не произойдет нажатие Enter или пока не будет превышен размер массива. Символ новой строки в массиве не сохранится, а заменится на нулевой символ.

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

Делитесь нашими статьями с друзьями в социальных сетях – это лучшая благодарность. А при возникновении вопросов и предложений – оставляйте комментарии.

Дополнительно к прочитанному рекомендую посмотреть видео-урок:

29 thoughts on “Строки в C++ и символьные массивы

  1. У меня вопрос. Как я могу перебрать массив, найти в нём символ и дописать возле него такой же. Например пользователь вводит D:\myfolder\ а на выходе должно быть D:\\myfolder\\

    1. Посмотрите видео. Там есть инф, что если для массива выбрали авт определение размера array[], то есть функция sizeof, при помощи кот можно в for перебрать все элементы. for ( int i=0; i<sizeof(array); i++). Дойдете до нужного и вставите. Я думаю, так.

      1. Это неверно:
        1. sizeof() возвращает занимаемое место массивом в байтах, для 10 элементного массива char это будет 10, а для такого же массива int это будет 40.
        2. Размер массива можно определить как sizeof( array ) / sizeof( array[ 0 ] ). Но и это – только в области определения массива (до передачи его куда-то в функцию).
        3. В массив нельзя “вставить” элемент, можно только если поштучно раздвинуть по очереди все последующие на 1 вправо, но это сильно накладно.
        4. В string, в отличие от массива, вставить элемент можно.

  2. Добрый день. Я так и поняла вопрос, что в строку надо добавить символ. (тема урока ведь строки)
    #include
    using namespace std;
    int main()
    {
    char a[]={"abcefghi"};
    // переменная b - искомая точка в строке, начиная с которой делаем сдвиг
    // переменная с - добавляемый символ
    // переменная f - просто вспомогательная
    // sory за названия переменных нет времени возиться
    char b('c'), c('d'), f(' ');
    cout << a << endl;
    for ( int i=0; i<sizeof(a); i++)
    {
    if (a[i]==b)
    {
    b=c;
    f=a[i+1];
    a[i+1]=c;
    c=f;
    }
    }
    cout << a << endl;

    return 0;
    }

  3. почему-то не работает. ФИО первого студента записывает в переменную, а фио второго даже ввести не дает (сразу перескакивает на № группы)
    Подскажите, что я делаю не так)


    #include
    #include

    using namespace std;

    struct Student
    {
    char fio[80];
    int number_group;
    int ball[5];
    };

    int main(int argc, char *argv[])
    {

    int count_students = 2;
    Student *stud = new Student[count_students];
    for (int i = 0; i < count_students; i++)
    {

    cout << endl << "Введите фамилию студента #" << i + 1 << ": ";
    cin.getline (stud[i].fio,80);
    cout << endl << "Введите номер группы студента #" << i + 1 <> stud[i].number_group;
    cout << endl << "Введите оценки студента #" << i + 1 << ": ";
    for (int j = 0; j > stud[i].ball[j];
    }
    }
    cout << endl;


      1. #include
        #include
        #include
        #include

        using namespace std;

        struct Student
        {
        char fio[80] = "";
        int number_group;
        int ball[5];
        };

        int main(int argc, char *argv[])
        {

        int count_students = 2;
        Student *stud = new Student[count_students];

        for (int i = 0; i < count_students; i++)
        {

        cout << endl << "Введите фамилию студента " << i + 1 << ": ";
        cin.getline (stud[i].fio,80);
        cout << endl << "Введите номер группы студента " << i + 1 <> stud[i].number_group;
        cout << endl << "Введите оценки (не более 5,через пробел) студента " << i + 1 << ": ";

        for (int j = 0; j > stud[i].ball[j];
        }

        }
        cout << endl;

        int count = 0;
        ofstream myfile;
        myfile.open ("C:/example.txt");
        for (int i = 0; i < count_students; i++)
        {

        for (int j = 0; j < 5;j++)
        {
        if ((stud[i].ball[j])== 2)
        {
        cout << stud[i].fio << " " << stud[i].number_group;

        myfile << stud[i].fio << " " << stud[i].number_group << "\t";

        cout << endl;
        count++;
        break;
        }
        }
        }
        myfile.close();
        if (count == 0)
        {
        cout << "Двоечников нет!";
        myfile.open ("C:/example.txt");
        myfile << "Двоечников нет!" << endl;
        myfile.close();
        }
        return 0;
        }

    1. Дело в том, что после ввода данных в последнее поле структуры stud[i].ball[j] в потоке cin остаётся символ ‘\n’. Именно его и считывает метод getline(), не приостанавливая программу, ожидая ввод.
      Нужно добавить cin.get() последней командой во внешнем цикле.

      Дмитрий Белик

    1. Совершенно дикое намерение!
      А что бы вы сами хотели получить в результате?: ‘A’*7 – это сколько?

  4. Найти произведение и минимальную четную цифру, составляющую неко-
    торое число Х как решить эту задачу?

    1. Прежде всего, в вашей задаче формулировка не корректная!
      Что значит “составляющую число”? В математике нет понятия составляюшее.

      Как вы сами, для примера, представляете как должно выглядеть решение для конкретного значения X, скажем, X=113? Напишите.

      1. То тогда вывести на экран, что нет четного минимального числа в введеном числе

  5. Подскажите, не пойму почему пропускается 2й запрос на ввод слов?

    в консоли выводится следующее:

    Enter some words : word
    word
    Default char is: Y
    Enter new char: w
    Новый символ: w
    Thats It!!!
    2 Enter some words :
    3 Enter some words : word
    word
    Для продолжения нажмите любую клавишу . . .

  6. как значение переменной 32 разряда Превратить в строку, для того, чтобы потом её разделить на 4 байта?

    1. Как-то так (в деталях отладите сами):

      int32_t val = ...;
      char str[ 33 ] = " ", // 0 в позиции [32]
      hex[] = "0123456789ABCDEF"; // 16-тиричные символы
      for( int i = 0; i >= 4
      }
      cout << "строка: " << str << endl;

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *