Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.138.105.124] |
|
Сообщ.
#1
,
|
|
|
Часто приходится работать с массивами строк. Тот, кто поизучал С++ сразу же знает ответ:
"нужно сделать указатель на указатель - что то вроде вот такого - char **mStings;". "ладно", скажу я, "ответ правильный". Но не до конца. Такой способ можно использовать, когда речь идет о простом хранении такого массива. А если захотим поманипулировать? Представим ситуацию: нужно добавить несколько строк куда нибудь в середину. Потом отсортировать по алфавиту то что получилось. И уж напоследок убить несколько записей середины списка... ну как, есть идеи на тему, "как бы это такое сделать и при этом закончить желательно до отпуска, который начнется в июле?" Если сразу рваться в бой, то закончить можно как раз к отпуску. Вечные проблемы с переаллоцированием, чуть зазевался и перепутал индекс - и пожалуйста - получите Аксесс Виолейшн и распишитесь... А если чуть чуть подумать, то ясно лучше воспользоваться обертками. Первый вариант (MFC): использовать CStringArray или CListString. Вариант вполне достойный, если вы пишете с использование MFC. Однако ради одних массивов строк зависеть от каких то внешних dll-ек.. нелогично. Ради них же линковать MFC статически нелогично вдвойне. А еще бывают платформы, до которых MS еще просто не добрался! Второй вариант (STL): vector <string> vStrings или list <string> lStrings. в STL много приятных фишечек, помогающих работать со строками и массивами. Над переаллоциро- ванием парится уже не програмер, а STL, справляется кстати неплохо. наслаждейтесь. STL добрался до всех современных платформ, где есть C++. Не встречал я его только в DOS-овых версих: Borland C++ (3.1 например), так же нет уверености по поводу ранних версий VC. (самая старшая, которую видел я - 4.2, и там он уже был). Код, который демонстрирует, как из такого массива удалять строки по условию: #include <vector> #include <string> #include <algorithm> //эта функция определяет условие по которому будет проводится удаление bool Conditions(std::string x) { return (x == "235315"); } ....... std::vector<std::string> sIn; int i = 0; std::vector<std::string>::iterator new_end; sIn.push_back("235315"); sIn.push_back("235315"); sIn.push_back("235315"); sIn.push_back("asdg5"); sIn.push_back("235315"); sIn.push_back("fb346346"); sIn.push_back("235315"); for(i = 0; i< sIn.size(); i++) { printf("%s\n", sIn.at(i).c_str()); } printf("\n\n"); new_end = std::remove_if(sIn.begin(), sIn.end(), Conditions); sIn.erase(new_end, sIn.end()); for(i = 0; i< sIn.size(); i++) { printf("%s\n", sIn.at(i).c_str()); } Условие Conditions() можно делать любым, по вашему желанию. например: таким bool Conditions(std::string x) { return (x.at(0) == '2'); } удаляет все строки, которые начинаются на символ '2' Сортировка std::sort(sIn.begin(), sIn.end(), Conditions2); по алфавиту: bool Conditions2(std::string x, std::string y) { return (strcmp(x.c_str(), y.c_str()) < 0); } супротив алфавита: bool Conditions2(std::string x, std::string y) { return (strcmp(x.c_str(), y.c_str()) > 0); } по длине строки: bool Conditions2(std::string x, std::string y) { return (x.size() < y.size()); } to be continued... (мужики, предлагайте что ещё добавить можно, а то у меня дистрофия фантазии развивается) |
Сообщ.
#2
,
|
|
|
Иногда нужно использовать разбор строк. Вот пример часто используемых методов класса string.
Использовать можно в любом компиляторе. string str("arg1 arg2 arg3"); int i; while ( (i = str.find(" ")) != -1 ) { string temp = str.substr (0, i); str.erase (0, i+1); temp += strimg (" tail"); printf ( "%s\n", str.c_str() ); } |
Сообщ.
#3
,
|
|
|
эта такая реклама stl? не спорю, вещь полезная, но бесполезная (вернее недоступная) когда имеешь дело с простым С. сейчас пишу одну либину для палма, там по определенным причинам нельзя подключить stl и другие либы для работы со строками и массивами. парилки хватае (мягко говоря). пока что придумал тока такой вариант (благо, что массивы строк заранее известны).
char* arrStrings[] = { "aaa", "bbb", "ccc" }; в таком случае еще более менее удобно работать со строками (индексировать, манипулировать и так далее). а вообче то сложно конечно. |
Сообщ.
#4
,
|
|
|
Реклама, или не реклама, но 90 процентов нужд перекрывает.
И 99 процентов вопросов в форуме на эту тему. |
Сообщ.
#5
,
|
|
|
Какая-то куцая статейка Может действительно расскажете несколько примеров использования CStringArray и string. Даже не несколько примеров, а вообще рассказать побольше о них. Но начало положено отличное молодец AQL
|
Сообщ.
#6
,
|
|
|
А у меня вопрос .а как насчёт фришного QT версии так скажем 2.3.0
Динамическая библиотека весит 2700 кило Либа - 3200 Ну плюс ещё мок на 200 килобайт :-)))) ну уж и плюс qtmain.lib & qtutil.lib на 50 кб :-))) Вот мне например очень этот вариант понравился, когда я выбирал на чём писать курсовую... Я тут сначала попросту забыл написать о главном: это класс QStringList построенная на шаблоне QValueList + адаптированная именно длля работы со строками добавлением соответствующих методов: sort grep split join |
Сообщ.
#7
,
|
|
|
Цитата Leprecon @ 17.03.04, 21:30 Какая-то куцая статейка Может действительно расскажете несколько примеров использования CStringArray и string. Даже не несколько примеров, а вообще рассказать побольше о них. Но начало положено отличное молодец AQL Хоккей, доделаю. (статейка на редкость куцая) |
Сообщ.
#8
,
|
|
|
Обещаное продолжение
Код, который демонстрирует, как из такого массива удалять строки по условию: #include <vector> #include <string> #include <algorithm> //эта функция определяет условие по которому будет проводится удаление bool Conditions(std::string x) { return (x == "235315"); } ....... std::vector<std::string> sIn; int i = 0; std::vector<std::string>::iterator new_end; sIn.push_back("235315"); sIn.push_back("235315"); sIn.push_back("235315"); sIn.push_back("asdg5"); sIn.push_back("235315"); sIn.push_back("fb346346"); sIn.push_back("235315"); for(i = 0; i< sIn.size(); i++) { printf("%s\n", sIn.at(i).c_str()); } printf("\n\n"); new_end = std::remove_if(sIn.begin(), sIn.end(), Conditions); sIn.erase(new_end, sIn.end()); for(i = 0; i< sIn.size(); i++) { printf("%s\n", sIn.at(i).c_str()); } Условие Conditions() можно делать любым, по вашему желанию. например: таким bool Conditions(std::string x) { return (x.at(0) == '2'); } удаляет все строки, которые начинаются на символ '2' Сортировка std::sort(sIn.begin(), sIn.end(), Conditions2); по алфавиту: bool Conditions2(std::string x, std::string y) { return (strcmp(x.c_str(), y.c_str()) < 0); } супротив алфавита: bool Conditions2(std::string x, std::string y) { return (strcmp(x.c_str(), y.c_str()) > 0); } по длине строки: bool Conditions2(std::string x, std::string y) { return (x.size() < y.size()); } to be continued... (мужики, предлагайте что ещё добавить можно, а то у меня дистрофия фантазии развивается) |
Сообщ.
#9
,
|
|
|
Загрузка строк из потока
std::ifstream is("some_file.txt"); // вообще is может быть любым потоком, например cin std::vector<std::string> strings; std::copy(std::istream_iterator<std::string>(is), std::istream_iterator<std::string>(), std::back_inserter(strings)); Сохранение строк в поток std::vector<std::string> strings; // как-то заполняем strings std::ofstream os("some_file.txt"); // вообще os может быть любым потоком, например cout std::copy(strings.begin(), strings.end(), std::ostream_iterator<std::string>(os, "\n")); |
Сообщ.
#10
,
|
|
|
Цитата Allender @ 18.03.04, 13:32 А у меня вопрос .а как насчёт фришного QT версии так скажем 2.3.0 Динамическая библиотека весит 2700 кило Либа - 3200 Ну плюс ещё мок на 200 килобайт :-)))) ну уж и плюс qtmain.lib & qtutil.lib на 50 кб :-))) Вот мне например очень этот вариант понравился, когда я выбирал на чём писать курсовую... Я тут сначала попросту забыл написать о главном: это класс QStringList построенная на шаблоне QValueList + адаптированная именно длля работы со строками добавлением соответствующих методов: sort grep split join Что можно делать с QStringList: QStringList::sort() -сортировка в порядке возрастания, если нужна другая другая сортировка, то можно написать в ручную, дабы алгоритмы всем известны используя функции для работы со списком, о которых будет сказано позжее. QString QStringList::join ( const QString & sep ) const -Объединяет весь список в одну строку QStringList QStringList::split( const QRegExp & sep или const QString & sep или const QChar & sep, const QString & str, bool allowEmptyEntries = FALSE ) [static] -позволяет с помощью какого либо сепаратора (регулярное выражение, строка или символ)разделить одну единую строку на список (очень удобно для парсинга) QStringList QStringList::grep ( const QString & str, bool cs = TRUE ) const //или QStringList QStringList::grep ( const QRegExp & expr ) const -позволяет получить новый список строк, каждая строка которого будет содержать строку str либо удовлетворять регулярному выражению expr Теперь, что позволяет деалть QStringList за счёт методов класса QValueList, от которого он отнаследован. Во-первых поддерживается механизм итераторов для более удобной и безопасной навигации QValueList<T> & operator= ( const QValueList<T> & l ) QValueList<T> & operator= ( const std::list<T> & l ) bool operator== ( const std::list<T> & l ) const bool operator== ( const QValueList<T> & l ) const bool operator!= ( const QValueList<T> & l ) const -как видите поддерживается и обычный std::list<T> terator begin () const_iterator begin () const iterator end () const_iterator end () const iterator insert ( iterator it, const T & x ) uint remove ( const T & x ) void clear () iterator erase ( iterator it ) iterator erase ( iterator first, iterator last ) - элементарная работа с итераторами T & operator[] ( size_type i ) const T & operator[] ( size_type i ) const iterator at ( size_type i ) const_iterator at ( size_type i ) const iterator find ( const T & x ) const_iterator find ( const T & x ) const iterator find ( iterator it, const T & x ) const_iterator find ( const_iterator it, const T & x ) const int findIndex ( const T & x ) const size_type contains ( const T & x ) const size_type count () const QValueList<T> & operator+= ( const T & x ) - а также ещё немного методов. которые облегчают интерфейс пользования этим самым QStringList |
Сообщ.
#11
,
|
|
|
А как std::string конвертировать в int, double, float и обратно?
С Уважением, dangee |
Сообщ.
#12
,
|
|
|
Цитата dangee @ 31.03.04, 08:50 А как std::string конвертировать в int, double, float и обратно? С Уважением, dangee Извини конечно за навязчивость, но вот есть и такая алтернатива :-)))) Правда это всё для класса QString... short toShort ( bool * ok = 0, int base = 10 ) const ushort toUShort ( bool * ok = 0, int base = 10 ) const int toInt ( bool * ok = 0, int base = 10 ) const uint toUInt ( bool * ok = 0, int base = 10 ) const long toLong ( bool * ok = 0, int base = 10 ) const ulong toULong ( bool * ok = 0, int base = 10 ) const float toFloat ( bool * ok = 0 ) const double toDouble ( bool * ok = 0 ) const QString & setNum ( short n, int base = 10 ) QString & setNum ( ushort n, int base = 10 ) QString & setNum ( int n, int base = 10 ) QString & setNum ( uint n, int base = 10 ) QString & setNum ( long n, int base = 10 ) QString & setNum ( ulong n, int base = 10 ) QString & setNum ( float n, char f = 'g', int prec = 6 ) QString & setNum ( double n, char f = 'g', int prec = 6 ) |
Сообщ.
#13
,
|
|
|
Спасибо!
Но как это сделать в классике ( )? ЗЫ. Почему я всегда выбираю трудный путь? |
Сообщ.
#14
,
|
|
|
Цитата dangee, 31.03.04, 08:50 А как std::string конвертировать в int, double, float и обратно? А про это вот здесь написано. |
Сообщ.
#15
,
|
|
|
AQL, Allender, может как-нить скооперируетесь, чтобы скомпоновать окончательную версию и поместить ее в первое сообщение этого топика?
|
Сообщ.
#16
,
|
|
|
массив строк:
#define MAX_SIZE 20000 char *str[MAX_SIZE] недостаток - заранее нужно указывать максимальный размер |
Сообщ.
#17
,
|
|
|
Дядя Банзай, Ваш способ работы со строками хороший, быстрый.. до тех пор, пока нам не придётся сильно манипулировать с ними .
|
Сообщ.
#18
,
|
|
|
У меня вопрос к автору топика.
Не кажется ли Вам, что смешивание стилей в учебном материале (как я понял цель топика - просвещение), это плохой пример для новичков? Почему бы не использовать std::cout, если уж начали переход от С к С++? Аналогично при сортировке. Для класса определены operator>, operator< и метод compare. Использование c_str() в данном случае не просто не имеет смысла, но и приводит, как понимаю, лишний раз к выделению памяти, т.к. стандартом не оговаривается, что данные в std::sting должны быть расположены линейно, как в std::vector. Цитата dangee, 31.03.04, 08:50, 328276 А как std::string конвертировать в int, double, float и обратно? Можно использовать вот такие два шаблонных класса: template <typename T> std::string toString(T val) { std::ostringstream oss; oss<< val; return oss.str(); } template<typename T> T fromString(const std::string& s) { std::istringstream iss(s); T res; iss >> res; return res; } Пример использования: int iVal; std::string strInt = toString(iVal); iVal = fromString<int>(strInt); float fVal; std::string strFloat = toString(fVal); fVal = fromString<float>(strFloat); |
Сообщ.
#19
,
|
|
|
Внесу-ка я свою лепту
#include <stdlib.h> #include <string.h> #include <stdio.h> #define ST_SUCCESS 0 #define ST_NO_MEM 0 #define ST_INDEX_MAX 64000 #define ST_INDEX_OVER 64001 class stringlist; struct string_s { string_s* next; string_s* prev; char* data; }; string_s* null_pointer = NULL; class stringlist { protected: string_s* first; //pointer to first entry string_s* end; //pointer to last entry public: stringlist(); ~stringlist(); string_s* operator [](unsigned int index); unsigned int find(const char* s); int add(string_s** pointer, const char* data); int create(const char* data, string_s** pointer_recurce); int append(char* data); string_s* delete_entry(string_s* pointer); int set(string_s* pointer, const char* data); char* get(string_s* pointer, char* s1); string_s* walk(unsigned int number); }; int stringlist::add(string_s** pointer1, const char* data) { int result = ST_SUCCESS; string_s *pointer = *pointer1; string_s *newitem = (string_s*) malloc(sizeof (string_s)); if(newitem!=NULL) { newitem->data = (char*) malloc(strlen(data)+1); if(newitem->data!=NULL) { strcpy(newitem->data, data); if(NULL != pointer) { newitem->next = pointer->next; pointer->next = newitem; } else { pointer=newitem; newitem->next=NULL; first=newitem; } newitem->prev=pointer; } else { free(newitem); result = ST_NO_MEM; } } else { result = ST_NO_MEM; } *pointer1 = pointer; return result; } int stringlist::create(const char* data, string_s** pointer_recurse=&null_pointer) { int result = ST_SUCCESS; string_s* pointer = *pointer_recurse; string_s* pointer_first = first; if(NULL == first) { //if first entry not created :) result = add(&pointer, data); if(result == ST_SUCCESS) { pointer->next = NULL; first = pointer; } } else { first=NULL; result = create(data, &pointer); if(result == ST_SUCCESS) { pointer->next = pointer_first; } } pointer->prev=NULL; *pointer_recurse = pointer; return result; } int stringlist::append(char* data) { return add(&end, data); } string_s* stringlist::delete_entry(string_s* pointer) { string_s* pointer_next = pointer->next; string_s* pointer_prev = pointer->prev; if(pointer!=NULL) { if(pointer==end) { end = pointer_prev; } if(pointer->data != NULL) { free(pointer->data); } free(pointer); } if(pointer_prev!=NULL) pointer_prev->next = pointer_next; return pointer_prev; } char* stringlist::get(string_s* pointer, char* s1) { if(pointer!=NULL) return strcpy(s1, pointer->data); else return NULL; } int stringlist::set(string_s* pointer, const char* data) { if(pointer!=NULL) { strcpy(pointer->data, data); return ST_SUCCESS; } else return 1; } string_s* stringlist::walk(unsigned int number) { unsigned int walker = number % 4; unsigned int walkersteps = ((unsigned int) number / 4 ); string_s* pointer = first; for(unsigned int i=0; i<walkersteps ;i++) { pointer = pointer->next->next->next->next; } switch(walker) { case 1: pointer=pointer->next; break; case 2: pointer=pointer->next->next; break; case 3: pointer=pointer->next->next->next; break; } return pointer; } unsigned int stringlist::find(const char* s) { string_s* pointer = first; unsigned int i; for(i=0; ;i++) { if(*pointer->data == *s) { if(0==strcmp(pointer->data, s)) { return i; } } pointer = pointer->next; } return ST_INDEX_OVER; } string_s* stringlist::operator[](unsigned int index) { return walk(index); } stringlist::stringlist() { first = NULL; end=NULL; create("\0"); end=first; } stringlist::~stringlist() { while(delete_entry(end)!=NULL); } int main() { char s[32]; stringlist list; list.create("test string"); string_s* first_element = list[1]; list.get(first_element, s); printf("%s\n",s); getc(stdin); return EXIT_SUCCESS; } |
Сообщ.
#20
,
|
|
|
Интересный... велосипед...
А чем стандартный std::list не подошел? А почему malloc, а не new? А почему string_s - глобальная структура, её ещё где-то можно использовать? А почему класс stringlist распоряжается памятью для string_s? А что это за макросы ST_INDEX_OVER и т.п.? Без них нельзя? А как мне изменить строку в этом списке, например, прибавить к ней еще пару символов? А что за глобальная переменная null_pointer? |
Сообщ.
#21
,
|
|
|
Цитата BioUnit, 5.12.04, 20:56, 533584 А что это за макросы ST_INDEX_OVER и т.п.? Без них нельзя? Коды ошибок Цитата BioUnit, 5.12.04, 20:56, 533584 А как мне изменить строку в этом списке, например, прибавить к ней еще пару символов? stringlist::set Цитата BioUnit, 5.12.04, 20:56, 533584 А что за глобальная переменная null_pointer? НЕ помню |
Сообщ.
#22
,
|
|
|
Мяут, объясни мне, плз, одну вещь: а нафига?
Такой свой велосипед написать может практически каждый. При этом из минусов можно сразу отметить ошибки(без них редко обходятся даже такие простые классы), отсутствие документации. Часто страдает эффективность. Еще интересный вопрос - обработка ошибок. Это же тоже надо все описывать, когда что возвращается/какое исключение кидается. Как я понимаю, цель данной статьи заключается в том, чтобы помочь выбрать из уже существующего огромного количества библиотек нужную или их эффективную комбинацию. Влезая со своим очередным классом, ты вносишь еще больше путаницы, которой и так достаточно. |
Сообщ.
#23
,
|
|
|
M Прошу обратить внимание на Правила раздела (вверху страницы) и впредь придерживаться их |
Сообщ.
#24
,
|
|
|
byte, я тренировался односвязные списки писать
|