C++: контейнеры с переменными типа string

Модератор: Модераторы разделов

Аватара пользователя
ArkanJR
Сообщения: 1117
ОС: MS Windows, МСВС

C++: контейнеры с переменными типа string

Сообщение ArkanJR »

В "Самоучителе C++" Крупника приводится пример контейнера с целочисленными переменными:

Код: Выделить всё

#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> s;
for(int i = 0; i < 10; i++)
s.push_back(i);
for(int i = 0; i < s.size(); i++)
cout << s[i] << endl;
}

В данном опусе отмечается, что в контейнере могут храниться и другие объекты, в том числе и строки.

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

Поэтому образовался вопрос: каким образом можно создать контейнер со строковыми данными, выводимыми по очереди на экран:
рабочий телефон: 11-11

Сотрудники:

Иванов
Петров
Сидоров

?
— Да, это была ошибка, Кемп, огромная ошибка, что я взялся один за это дело. Напрасно потрачены силы, время, возможности. Один… Удивительно, как беспомощен человек, когда он один! Мелкая кража, потасовка — и всё.

© Г. Уэллс "Человек-невидимка"
Спасибо сказали:

NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: C++: контейнеры с переменными типа string

Сообщение NickLion »

С++98/03:

Код: Выделить всё

#include <iostream>
#include <vector>
#include <string>

int main(int argc, const char *argv[])
{
    std::vector<std::string> a;
    a.push_back("phone: 11-11");
    a.push_back(std::string());
    a.push_back("Employees");
    a.push_back(std::string());
    a.push_back("Ivanoff");
    a.push_back("Petroff");
    a.push_back("Sidoroff");
    for (std::vector<std::string>::iterator it = a.begin(); it != a.end(); ++it) {
        std::cout << *it << std::endl;
    }
    return 0;
}


C++11:

Код: Выделить всё

#include <iostream>
#include <vector>
#include <string>

int main(int argc, const char *argv[])
{
    std::vector<std::string> a {
        "phone: 11-11",
        std::string(),
        "Employees",
        std::string(),
        "Ivanoff",
        "Petroff",
        "Sidoroff",
    };
    for (std::string& s : a) {
        std::cout << s << std::endl;
    }
    return 0;
}
Спасибо сказали:

Аватара пользователя
Stauffenberg
Сообщения: 2023
Статус: ☮ PEACE ☮
ОС: открытая и свободная

Re: C++: контейнеры с переменными типа string

Сообщение Stauffenberg »

ArkanJR писал(а):
10.11.2014 20:35
В "Самоучителе C++" Крупника приводится пример контейнера с целочисленными переменными:

ИМХО конечно, но если Вы хотите разобраться в С++, я советую Вам забыть об этой книге.
Labor omnia vincit

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” (Brian Kernighan)
Спасибо сказали:

Аватара пользователя
ArkanJR
Сообщения: 1117
ОС: MS Windows, МСВС

Re: C++: контейнеры с переменными типа string

Сообщение ArkanJR »

Stauffenberg писал(а):
11.11.2014 00:43
ИМХО конечно, но если Вы хотите разобраться в С++, я советую Вам забыть об этой книге.

1. почему?

2. какую посоветуете взамен?
— Да, это была ошибка, Кемп, огромная ошибка, что я взялся один за это дело. Напрасно потрачены силы, время, возможности. Один… Удивительно, как беспомощен человек, когда он один! Мелкая кража, потасовка — и всё.

© Г. Уэллс "Человек-невидимка"
Спасибо сказали:

Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: C++: контейнеры с переменными типа string

Сообщение drBatty »

ArkanJR писал(а):
10.11.2014 20:35
Но как создать контейнер со строками

string это сам по себе, по вашей терминологии, "контейнер".
ArkanJR писал(а):
11.11.2014 17:31
почему?

потому,что в этой книжонке даже не объяснено, что такое STL. Ну или вы её с конца читаете.

У вас не получилось потому, что вы пытались сделать шаблон в шаблоне. А его просто так в обычном C++ не объявить. Да и ещё большой вопрос, а нужно-ли объявлять? Для ваших целей лучше либо массив, либо структуру ИМХО.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:

NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: C++: контейнеры с переменными типа string

Сообщение NickLion »

drBatty писал(а):
12.11.2014 09:39
потому,что в этой книжонке даже не объяснено, что такое STL

Занудное замечание. И в стандарте не объяснено, что такое STL. STL — это было давно (когда ещё HP и SGI, и всего этого не было в стандарте).
Спасибо сказали:

Аватара пользователя
Bizdelnick
Модератор
Сообщения: 16818
Статус: grammatikführer
ОС: Debian GNU/Linux

Re: C++: контейнеры с переменными типа string

Сообщение Bizdelnick »

NickLion писал(а):
12.11.2014 10:57
И в стандарте не объяснено, что такое STL.

Стандарт, в отличие от самоучителя, вообще не обязан ничего объяснять. Он просто описывает, как всё должно работать, но не почему оно должно работать именно так, а не иначе. Самоучитель, по идее, должен чему-то учить, а это без объяснения базовых принципов невозможно. Упоминается ли при этом сама аббревиатура STL - конечно, дело десятое.
Пишите правильно:
в консоли
вкупе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:

NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: C++: контейнеры с переменными типа string

Сообщение NickLion »

Bizdelnick
Я к тому, что вообще-то STL — это библиотека, которая разрабатывалась HP, а после и SGI. Когда данная библиотека вошла в стандарт, она потеряла своё название STL и стала просто часть стандартной библиотеки языка C++ (также, как и части boost, вошедшие в C++11 стали просто частью стандартной библиотеки). Многие по инерции продолжают называть данную часть STL, но это, строго говоря, не правильно.
Спасибо сказали:

Аватара пользователя
ArkanJR
Сообщения: 1117
ОС: MS Windows, МСВС

Re: C++: контейнеры с переменными типа string

Сообщение ArkanJR »

Столкнулся с таким явлением при сортировке слов по алфавиту:

Если скомпилировать код:

Код: Выделить всё

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
    vector<string> a;
    a.push_back("пистолет");
    a.push_back("автомат");
    a.push_back("винтовка");
    a.push_back("пулемёт");
    a.push_back("гранатомёт");
    sort(a.begin(), a.end());
    for(vector<string>::iterator at = a.begin(); at != a.end(); ++at)
    {
    sort(a.begin(), a.end());
    cout << *at << endl;
    }
    return 0;
}

и запустить полученный бинарник, то в результате получим:
автомат
винтовка
гранатомёт
пистолет
пулемёт


Если же скомпилировать такой код:

Код: Выделить всё

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
    vector<string> a;
    a.push_back("пистолет");
    a.push_back("автомат");
    a.push_back("винтовка");
    a.push_back("пулемёт");
    a.push_back("гранатомёт");
    string::iterator at;
    sort(a.begin(), a.end());
    cout << *at;
    return 0;
}

То программа скомпилируется, но при запуске бинарника будет выдано сообщение:
Ошибка сегментирования


Кто-нибудь может подсказать, с чем связан результат, полученный во втором случае?
— Да, это была ошибка, Кемп, огромная ошибка, что я взялся один за это дело. Напрасно потрачены силы, время, возможности. Один… Удивительно, как беспомощен человек, когда он один! Мелкая кража, потасовка — и всё.

© Г. Уэллс "Человек-невидимка"
Спасибо сказали:

yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: C++: контейнеры с переменными типа string

Сообщение yoshakar »

ArkanJR писал(а):
24.04.2016 11:35
Кто-нибудь может подсказать, с чем связан результат, полученный во втором случае?
А какой результат вы в этом случае ожидаете?
Спасибо сказали:

Аватара пользователя
Bizdelnick
Модератор
Сообщения: 16818
Статус: grammatikführer
ОС: Debian GNU/Linux

Re: C++: контейнеры с переменными типа string

Сообщение Bizdelnick »

Вы пытаетесь разыменовать неинициализированный указатель (хотя, строго говоря, итератор — это абстракция над указателем, но в конечном итоге происходит именно это). Было бы в высшей степени удивительно, если бы Вы получили другой результат.
Для отлавливания многих глупых ошибок можно использовать cppcheck:

Shell

% cppcheck test.cpp Checking test.cpp... [test.cpp:15]: (error) Invalid iterator 'at' used. %

Пишите правильно:
в консоли
вкупе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:

Аватара пользователя
ArkanJR
Сообщения: 1117
ОС: MS Windows, МСВС

Re: C++: контейнеры с переменными типа string

Сообщение ArkanJR »

yoshakar писал(а):
24.04.2016 11:42
А какой результат вы в этом случае ожидаете?

Предупреждение компилятора, например.
— Да, это была ошибка, Кемп, огромная ошибка, что я взялся один за это дело. Напрасно потрачены силы, время, возможности. Один… Удивительно, как беспомощен человек, когда он один! Мелкая кража, потасовка — и всё.

© Г. Уэллс "Человек-невидимка"
Спасибо сказали:

Аватара пользователя
Bizdelnick
Модератор
Сообщения: 16818
Статус: grammatikführer
ОС: Debian GNU/Linux

Re: C++: контейнеры с переменными типа string

Сообщение Bizdelnick »

Компилятор выдал бы предупреждение, если бы это был просто указатель. Но это не указатель, а итератор, и операция * для него перегружена, а оттуда, где таки происходит разыменование указателя, не видно, был ли он инициализирован... В общем, в этом вашем C++ даже сам компилятор разобраться толком не может. ☺
Пишите правильно:
в консоли
вкупе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:

yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: C++: контейнеры с переменными типа string

Сообщение yoshakar »

ArkanJR писал(а):
24.04.2016 17:44
Предупреждение компилятора, например.
К сожалению, в используемой вами (на самом деле всеми) реализации стандартной библиотеки у string::iterator есть бессмысленный дефолтный конструктор, использование которого приводит к вот такому странному поведению. Если бы его не было (так можно было бы сделать, во всяком случае я не вижу проблем с этим), то была бы даже ошибка, а не предупреждение. То есть это недоработка конкретной реализации стандартной библиотеки.

P. S. Кажется я понял, почему нельзя избавиться от дефолтного конструктора: тогда нельзя было бы писать

Код: Выделить всё

string::iterator at = a.begin();
так как подобная запись означает создание дефолтного итератора и затем копирование в него a.begin(). Без дефолтного конструктора пришлось бы писать

Код: Выделить всё

string::iterator at(a.begin());
что, конечно, лучше, но исторические причины и т. п. требуют первого варианта.
Спасибо сказали:

Аватара пользователя
ArkanJR
Сообщения: 1117
ОС: MS Windows, МСВС

Re: C++: контейнеры с переменными типа string

Сообщение ArkanJR »

Доработал программу, чтобы результат выводился в файл, а не на экран:

Код: Выделить всё

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>
using namespace std;
int main()
{
    vector<string> a;
    a.push_back("пистолет");
    a.push_back("автомат");
    a.push_back("винтовка");
    a.push_back("пулемёт");
    a.push_back("гранатомёт");
    sort(a.begin(), a.end());
    for(vector<string>::iterator at = a.begin(); at != a.end(); ++at)
    {
    sort(a.begin(), a.end());
    ofstream out("list.txt");
    out << *at << endl;
    out.close();
    }
    return 0;
}

Но в результате в файле list.txt остаётся только слово "пулемёт". Как добиться, чтобы последующее записываемое слово не затирало предыдущее?
— Да, это была ошибка, Кемп, огромная ошибка, что я взялся один за это дело. Напрасно потрачены силы, время, возможности. Один… Удивительно, как беспомощен человек, когда он один! Мелкая кража, потасовка — и всё.

© Г. Уэллс "Человек-невидимка"
Спасибо сказали:

yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: C++: контейнеры с переменными типа string

Сообщение yoshakar »

ArkanJR, все команды внутри блока for выполняются для каждого значения итератора at, В частности, команда sort(a.begin((), a,end()); вызывается столько раз, сколько слов в массиве, что весьма бессмысленно, не правда ли? То же самое с командой ofstream out("list.txt"), создающей пустой файл list.txt, — то есть перед записью каждого очередного слова вы сначала сортируете свой вектор (бессмысленно, он и так уже отсортирован), а затем стираете то, что записали в прошлый раз (а это, как я понял, не то, чего вы хотите).
Спасибо сказали:

NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: C++: контейнеры с переменными типа string

Сообщение NickLion »

yoshakar писал(а):
24.04.2016 18:19
P. S. Кажется я понял, почему нельзя избавиться от дефолтного конструктора: тогда нельзя было бы писать

Код: Выделить всё

string::iterator at = a.begin();
так как подобная запись означает создание дефолтного итератора и затем копирование в него a.begin(). Без дефолтного конструктора пришлось бы писать

Код: Выделить всё

string::iterator at(a.begin());
что, конечно, лучше, но исторические причины и т. п. требуют первого варианта.

Вы неправы. Запись

Код: Выделить всё

string::iterator at = a.begin();

эквивалентна

Код: Выделить всё

string::iterator at(a.begin());

В стандарте оговорено, что в случае инициализации вызывается конструктор копирования, а не пустой конструктор, а затем оператор присваивания.

А вот запись

Код: Выделить всё

string::iterator at;
at = a.begin();

Была бы невозможна без дефолтного конструктора.
Спасибо сказали:

Аватара пользователя
ArkanJR
Сообщения: 1117
ОС: MS Windows, МСВС

Re: C++: контейнеры с переменными типа string

Сообщение ArkanJR »

yoshakar писал(а):
24.04.2016 18:39
ArkanJR, все команды внутри блока for выполняются для каждого значения итератора at, В частности, команда sort(a.begin((), a,end()); вызывается столько раз, сколько слов в массиве, что весьма бессмысленно, не правда ли? То же самое с командой ofstream out("list.txt"), создающей пустой файл list.txt, — то есть перед записью каждого очередного слова вы сначала сортируете свой вектор (бессмысленно, он и так уже отсортирован), а затем стираете то, что записали в прошлый раз (а это, как я понял, не то, чего вы хотите).

О, спасибо, что носом ткнули! :) Исправил:

Код: Выделить всё

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>
using namespace std;
int main()
{
    vector<string> a;
    a.push_back("пистолет");
    a.push_back("автомат");
    a.push_back("винтовка");
    a.push_back("пулемёт");
    a.push_back("гранатомёт");
    sort(a.begin(), a.end());
    ofstream out("list.txt");
    for(vector<string>::iterator at = a.begin(); at != a.end(); ++at)
    {
    sort(a.begin(), a.end());
    out << *at << endl;
    }
    out.close();
    return 0;
}
— Да, это была ошибка, Кемп, огромная ошибка, что я взялся один за это дело. Напрасно потрачены силы, время, возможности. Один… Удивительно, как беспомощен человек, когда он один! Мелкая кража, потасовка — и всё.

© Г. Уэллс "Человек-невидимка"
Спасибо сказали:

yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: C++: контейнеры с переменными типа string

Сообщение yoshakar »

NickLion писал(а):
24.04.2016 19:05
Вы неправы.
Спасибо за своевременное замечание, вы, конечно, правы. Ну, а без возможности использовать неинициализированный итератор как раз можно быо бы отлично обойтись.
Спасибо сказали:

NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: C++: контейнеры с переменными типа string

Сообщение NickLion »

yoshakar писал(а):
24.04.2016 18:39
то есть перед записью каждого очередного слова вы сначала сортируете свой вектор (бессмысленно, он и так уже отсортирован)

Я бы добавил, что не только бессмысленно, но и опасно, при изменении контейнера может произойти инвалидация итераторов.
Спасибо сказали:

Аватара пользователя
Bizdelnick
Модератор
Сообщения: 16818
Статус: grammatikführer
ОС: Debian GNU/Linux

Re: C++: контейнеры с переменными типа string

Сообщение Bizdelnick »

ArkanJR писал(а):
24.04.2016 19:08
Исправил

sort() из цикла выкинуть забыли.
Пишите правильно:
в консоли
вкупе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:

Аватара пользователя
ArkanJR
Сообщения: 1117
ОС: MS Windows, МСВС

Re: C++: контейнеры с переменными типа string

Сообщение ArkanJR »

Bizdelnick писал(а):
24.04.2016 19:30
sort() из цикла выкинуть забыли.

Достаточно на сегодня, а то внимание уже притупилось и глаза замылились.
— Да, это была ошибка, Кемп, огромная ошибка, что я взялся один за это дело. Напрасно потрачены силы, время, возможности. Один… Удивительно, как беспомощен человек, когда он один! Мелкая кража, потасовка — и всё.

© Г. Уэллс "Человек-невидимка"
Спасибо сказали:

Аватара пользователя
Olej
Сообщения: 659
ОС: Fedora, Mint, Debian, QNX

Re: C++: контейнеры с переменными типа string

Сообщение Olej »

NickLion писал(а):
12.11.2014 13:55
Я к тому, что вообще-то STL — это библиотека, которая разрабатывалась HP, а после и SGI. Когда данная библиотека вошла в стандарт, она потеряла своё название STL и стала просто часть стандартной библиотеки языка C++ (также, как и части boost, вошедшие в C++11 стали просто частью стандартной библиотеки). Многие по инерции продолжают называть данную часть STL, но это, строго говоря, не правильно.

Правильно-неправильно - это всё дело вкуса ...

to Т.С.: вот здесь есть 2 десятка коротких заметок, объясняющих контейнеры STL, но там не столько текст объяснений, сколько примеры в коде, которые можно просто брать и использовать в своём коде: Начала STL и контейнры C++
Спасибо сказали:

Аватара пользователя
Olej
Сообщения: 659
ОС: Fedora, Mint, Debian, QNX

Re: C++: контейнеры с переменными типа string

Сообщение Olej »

Olej писал(а):
30.04.2016 17:17
to Т.С.: вот здесь есть 2 десятка коротких заметок, объясняющих контейнеры STL, но там не столько текст объяснений, сколько примеры в коде, которые можно просто брать и использовать в своём коде

Теперь эти разрознённые заметки собраны в единый связный текст: Начала STL и контейнеры C++
Там есть варианты и обсуждаемых вопросов, много примеров кода... который писался, во многом, для проверки "симбиоза" STL с новыми синтаксическими конструкциями C++11 и C++14.
Спасибо сказали: