Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.64/114: Рейтинг темы: голосов - 114, средняя оценка - 4.64
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
1

std::string в char*

11.06.2012, 14:13. Показов 22322. Ответов 40
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Можно ли привести std::string к указателю на нуль-терминальную строку? Как?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.06.2012, 14:13
Ответы с готовыми решениями:

ошибка error: cannot convert 'std::string {aka std::basic_string<char>}' to 'std::string* {aka std::basic_stri
на вод поступают 2 строки типа string. определить количество вхождений строки 2 в строку 1 ошибка...

ошибка в программе (cannot convert 'std::string {aka std::basic_string<char>}' to 'const char*')
int main() { string fileName, currWord, currMax = &quot;&quot;; cin&gt;&gt;fileName; ...

Странная ошибка: [Error] no match for call to '(std::string {aka std::basic_string<char>}) (int&)'
У меня появляется проблема при компиляции сей программы: #include &lt;iostream&gt; #include &lt;string&gt;...

(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&
astxx::manager::connection::connection(std::basic_string&lt;char, std::char_traits&lt;char&gt;,...

40
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
11.06.2012, 18:30 21
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от Bers Посмотреть сообщение
Есть предположение, что:
Я тоже так думаю. Хотя возможно где то хранятся эти самые строковые литералы. Нужно попробовать проверить со строкой, вводимой пользователем.
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
11.06.2012, 18:34 22
Bers, что вкладывается в понятие мёртвая память и почему она мёртвая в том примере?
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
11.06.2012, 18:34 23
Цитата Сообщение от Bers Посмотреть сообщение
то было бы странным создавать новый блок...
Если и правда терзают сомнения, то достаточно сделать ДВА вызова c_str и сравнить эти указатели. Если они разные, то возвращается копия (но это не так, разумеется). А если одинаковые, то на внутренний буфер.
И я не знаю, как работает codepad, но в MSVC в данной программе вообще std::sting str может быть удалён оптимизирующим компилятором, как ненужный объект. Этим можно было бы объяснить неожиданное поведение программы.
0
Заблокирован
11.06.2012, 19:16 24
Цитата Сообщение от grizlik78 Посмотреть сообщение
Bers, что вкладывается в понятие мёртвая память и почему она мёртвая в том примере?
C++
1
2
3
4
5
char* str = new char[100500];
str[0] = '1';
str[1]= '\0'
delete [] str;
std::cout<<str<<std::endl;
Память сдохла. Но какое то время теоретически может хранить якобы актуальное значение

Добавлено через 2 минуты
Цитата Сообщение от Deviaphan Посмотреть сообщение
но это не так, разумеется
Ни разу не сталкивался с ситуациями, где это было бы так. Однако, в книжке по STL Джосаттис об этом предупреждает. Он говорит - стандарт не гарантирует, и полагаться на это нельзя.
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
11.06.2012, 19:18 25
Ясно. Но непонятно из-за чего такие подозрения в том коде. Вывод строки работает с константной ссылкой на строку и не может вызывать неконстантные функции. А раз так, то указатель остаётся валидным.
0
Заблокирован
11.06.2012, 19:24 26
C++
1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
       std::string str = "12345";
       const char *cstr1 = str.c_str(),   //смотрит на 12345
       cstr2 = 0;
       std::cout << str << '\n' << cstr1 << std::endl;
       str = "qwerty";        //внутреннее хранилище изменилось
       cstr2 = str.c_str();
       std::cout << '\n' << str << '\n' << cstr1 //по прежнему смотрит на 12345
                 << '\n' << cstr2 << std::endl;
       return 0;
}
Строка изменилась. И как бы ей и не нужны старые данные, но старый указатель об этом не знает.
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
11.06.2012, 19:30 27
Ах, да, присваивание я пропустил. Что ж, там что угодно может быть, согласен.
0
Заблокирован
11.06.2012, 19:54 28
Цитата Сообщение от grizlik78 Посмотреть сообщение
Ах, да, присваивание я пропустил. Что ж, там что угодно может быть, согласен.
Просто в студии, когда внутренее хранилище меняется, то и старые указатели смотрят на это новое внутренее хранилище (иногда). А иногда уже не смотрят (когда реалок памяти стринга).

Как бы.. выдавая наружу си-строку, стринг нарушает инвариант своего класса. Это опасная процедура. И нужна лишь для совместимости с старым си-кодом. Лучше это избегать.

Я пользую сие только для сишных конструкций, и никогда при этом стринг не изменяю. Итак проблем хватает.
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
11.06.2012, 19:57 29
Цитата Сообщение от Bers Посмотреть сообщение
Ни разу не сталкивался с ситуациями, где это было бы так.
В вышеприведённом коде в кодепаде всё выглядит так, будто возвращалась копия.
ТУт ещё такая фишка есть, что строки до 16 символов хранятся в объекте std::string в массиве фиксированного размера (в стеке) и только для бОльших строк выделяется память из кучи. С этим могло быть предыдущее поведение связанно.
0
59 / 6 / 1
Регистрация: 09.09.2011
Сообщений: 12
16.06.2012, 13:26 30
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <string>
 
int main()
{
   std::string str = "12345";
   
   const char *cstr1 = str.c_str(),
              *cstr2 = 0;
   
   std::cout << str << '\n' << cstr1 << std::endl;
   
   str = "qwert";//уменьшен до 5 символов
   
   cstr2 = str.c_str();
   
   std::cout << '\n' << str << '\n' << cstr1 << '\n' << cstr2 << std::endl;
   
   return 0;
}
данный код выводит(не происходит повторного выделения):
12345
12345

qwert
qwert
qwert
так что, скорее всего c_str возвращает ссылку на оригинал.
0
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
16.06.2012, 13:41 31
Она не может возвращать ссылку на оригинал, сама строка может хранится в контейнере std::string блоками в разных участках памяти, что и писали выше. std::string::c_str() лишь генерирует Си строку, указателем на которую можно безопасно пользоваться до любого изменения строки. Вот тот при мер кода, который я так же приводил в пример на 2 странице:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <string>
 
int main()
{
   std::string str = "12345";
   
   const char *cstr1 = str.c_str(),
              *cstr2 = 0;
   
   std::cout << str << '\n' << cstr1 << std::endl;
   
   str = "qwerty";
   
   cstr2 = str.c_str();
   
   std::cout << '\n' << str << '\n' << cstr1 << '\n' << cstr2 << std::endl;
   
   return 0;
}
Вот вывод.
0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.06.2012, 15:00  [ТС] 32
Цитата Сообщение от Toshkarik Посмотреть сообщение
Она не может возвращать ссылку на оригинал, сама строка может хранится в контейнере std::string блоками в разных участках памяти, что и писали выше.
И что?
Цитата Сообщение от Toshkarik Посмотреть сообщение
std::string::c_str() лишь генерирует Си строку, указателем на которую можно безопасно пользоваться до любого изменения строки.
си строка есть строка символов, хранимых подряд в одном месте и с терминальным нолём. Возвращается не список, не дерево, не массив и не иной контейнер си строк а сама строка. Значит после std::string::c_str() такая строка существует. Почему бы теперь ни назначить внутренний указатель на строку уже на неё? Раз уж память выделена. То есть сначала меняем размещение оригинал и ставим терминальный ноль, а потом уже возвращаем указатель. При этом длина строки продолжает храниться в готовом виде. С другой стороны, можно вернуть копию и при этом указатель на неё запомнить внутри, а при повторном std::string::c_str() верунть второй раз ту же копию. Я свой кривостринг сделала сначала с возвратом оригинала, причём, данные всегда хранились в виде комбинации динамической си строки (с терминальным нолём), её длины в отдельном поле.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class TSting
{
 protected:
  char *data; // нуль-терминальная строка
  unsigned long int count; // длина строки
 public:
  TString ();
  TString (TString &s);
  TString (char *s);
 ~TString ();
 TString operator +=(TString &s);
 TString operator +=(char *s);
 TString operator +=(char c);
 TString operator +(TString &s);
 TString operator +(char *s);
 TString operator +(char c);
 TString operator =(TString &s);
 TString operator =(char *s);
 TString operator =(char c);
 char &operator [] (unsigned long int number); // номирация с ноля
 unsigned long int Length();
 operator  unsigned long int (); //Тоже возвращает длину строки
};
при запросе длины строки, она возвращается из поля count. При любой операции строки, которая может изменить её длину, count обновляется. Если к строке TString добавляется си строка, то сначала в цикле считается её длина, потом выделяется память, потом count увеличивается на длину слагаемого оператором += и только потом происходит копирование из обеих строк, сначала из старого TString. Если строка TString созданётся на основе си строки, или ей присваивается си строка, то сначала счёт символов в цикле, потом выделение памяти, потом копирование, потом присваивание длины. В остальных случаях сразу выделение памяти, потом копирование, потом += для увеличения count. Потом переписал на возврат копии, за удаление которой отвечала вызывающая функция. Каждый раз возвращалась новая копия, но данные всё равно хранились подряд и с теримнальным нолём на конце. И покажи ка цитату из стандарта, гарантирующую, что символы стринга хранятся в разрозненных кусках. Если нет гарантии обратного, то это ещё ничего не значит.
0
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
16.06.2012, 15:07 33
Вы покажите цитату где я утверждал, что он всегда будет хранится в разных местах памяти? Ваш пост если честно ни о чем. Ваша реализация кого то там класса, это Ваша реализация, и я почти уверен, что она отличается от всех тех, что используют существующие компиляторы. Я могу привести другую цитату:
Generates a null-terminated sequence of characters (c-string) with the same content as the string object and returns it as a pointer to an array of characters.
0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.06.2012, 15:24  [ТС] 34
Цитата Сообщение от Toshkarik Посмотреть сообщение
Вы покажите цитату где я утверждал, что он всегда будет хранится в разных местах памяти?
Читай:
Цитата Сообщение от Toshkarik Посмотреть сообщение
на не может возвращать ссылку на оригинал, сама строка может хранится в контейнере std::string блоками в разных участках памяти,
Если не может вернуть из-за размещения, значит оно всегда такое. Иначе можно привести к подходящему размещению и потом вернуть указатель на внутренние данные.

Добавлено через 2 минуты
Цитата Сообщение от Toshkarik Посмотреть сообщение
и я почти уверен, что она отличается от всех тех, что используют существующие компиляторы.
Я сам в этом уверен. Но тем не менее, отдельные аспекты класса могли придти в голову не только мне. На свой класс я ссылаюсь только как пример принципиальной возможности возвращать указатель хоть на оригинал, хоть на копию. И при возврате указателя на оригинал разработчики класса могут специально позаботиться обо всех особенностях размещения, чтоб они этот фокус позволяли. Мораль проста: если указатель на оригинал смог вернуть даже я всего через 3 месяца от начала изучения языка, то уж тем более это мог сделать, например, Страуструп, если бы счёл это целесообразным.
0
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
16.06.2012, 15:26 35
Цитата Сообщение от taras atavin Посмотреть сообщение
сама строка может хранится в контейнере std::string блоками в разных участках памяти,
Что не понятного из этой фразы? Или Вы считаете, что должна быть проверка, находится ли строка в одном месте или кусками, и на основании этого возвращать указатель? И опять же:
Цитата Сообщение от Toshkarik Посмотреть сообщение
Generates a null-terminated sequence of characters (c-string) with the same content as the string object and returns it as a pointer to an array of characters.
Функция генерирует си-строку...
0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.06.2012, 15:44  [ТС] 36
Цитата Сообщение от Toshkarik Посмотреть сообщение
Что не понятного из этой фразы?
"Может хранить" не значит, что именно так она и хранит, фраза лишь утверждает, что нет гарантии обратного. Но обратное всё же возможно. И если оно для его то нудно разработчикам класса, то именно так и будет сделано. Можно даже сделать так, что по дефолту строка разрорвана на фрагменты, а sts::string::c_str() сначала собирает их в один во внутреннем представлении (ему же всё равно сначала надо собрать их в один), а только потом возвращает указатель и после него до следующего изменения строка уже хранится единым блоком до следующего своего изменения. Как вариант - можно хранить список нультерминальных массивов символов с индивидуальными полями длины и ещё общим полем длины, а по sts::string::c_str() приводить его к одному нультерминальному массиву символов через двойной указатель с дублированным полем полной длины.

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

Добавлено через 2 минуты
Цитата Сообщение от Toshkarik Посмотреть сообщение
Функция генерирует си-строку...
Эйси. Но "генерирует копию данных в виде си строки" и "генерирует си строку и заменяет ею текущее внутреннее представление" - далеко не одно и тоже, но то и то будет "генерирует си строку".
0
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
16.06.2012, 15:52 37
Да о чем Вы вообще? Куда Вас понесло?
Цитата Сообщение от taras atavin Посмотреть сообщение
не значит, что именно так она и хранится,
Я и написал, что МОЖЕТ хранить, и не писал обратного, не нужно пожалуйста осознанно коверкать смысл фразы.
Цитата Сообщение от taras atavin Посмотреть сообщение
И если оно для его то нудно разработчикам класса
Вы сами эту фразу поняли?

Все выше Вами описанное c_str() не обязана делать, в ее задачу лишь входит генерация Си-строки, и возвращение указателя на нее, ни слова о том, что она должна как то объединять внутреннее представление строки, или вообще делать что то еще с объектом. Так зачем же разработчикам усложнять себе жизнь?
Цитата Сообщение от taras atavin Посмотреть сообщение
Но "генерирует копию данных в виде си строки" и "генерирует си строку и заменяет ею текущее внутреннее представление" - далеко не одно и тоже, но то и то будет "генерирует си строку".
Вы хоть читали полностью эту цитату? Покажу 3 раз:
Generates a null-terminated sequence of characters (c-string) with the same content as the string object and returns it as a pointer to an array of characters.

Добавлено через 3 минуты
PS: синоним слова генерировать - создавать. Функция создает массив символов, ограниченный ноль-символом, и по содержанию идентичный строке-объекту.
0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.06.2012, 15:59  [ТС] 38
Цитата Сообщение от Toshkarik Посмотреть сообщение
Все выше Вами описанное c_str() не обязана делать, в ее задачу лишь входит генерация Си-строки, и возвращение указателя на нее, ни слова о том, что она должна как то объединять внутреннее представление строки, или вообще делать что то еще с объектом. Так зачем же разработчикам усложнять себе жизнь?
Ну она же всё равно должна объединить данные объекта.

Добавлено через 1 минуту
Цитата Сообщение от Toshkarik Посмотреть сообщение
PS: синоним слова генерировать - создавать.
Думаешь, я этого не понимаю?

Добавлено через 51 секунду
Модераторы, прикройте эту тему с хвостом ни о чём, а то она давно в офтоп свалилась.
0
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
16.06.2012, 16:00 39
Она не должна ничего объединять. Она должна создать массив символов ( Си-строку ), идентичный по содержанию string-объекту.
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
16.06.2012, 17:05 40
5 The char-like objects in a basic_string object shall be stored contiguously. That is, for any basic_string
object s, the identity &*(s.begin() + n) == &*s.begin() + n shall hold for all values of n such that 0
<= n < s.size().
Итого - по кускам строка хранится НЕ может. Она обязана хранится в непрерывной области памяти.

6 References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated
by the following uses of that basic_string object:
— as an argument to any standard library function taking a reference to non-const basic_string as an
argument.234
— Calling non-const member functions, except operator[], at, front, back, begin, rbegin, end, and
rend.
Итого при вызове не константных функций, за исключением некоторых - итераторы, указатели могут стать не валидными.

const charT* c_str() const noexcept;
const charT* data() const noexcept;
1 Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].
2 Complexity: constant time.
3 Requires: The program shall not alter any of the values stored in the character array.
Итого - не генерируется никакой новой строки.

Что, в стандарт сложно заглянуть?

Добавлено через 26 минут
Хотя все понятно. В стандарте С++98 ничего такого не описано.
2
16.06.2012, 17:05
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
16.06.2012, 17:05
Помогаю со студенческими работами здесь

Где и почему используют ту или иную строку std::string, char[], System::String^ ?
Где и почему используют ту или иную строку std::string, char, System::String^ ? Объясните...

char* vs std::string
При чтении чужих сорцов, обратил внимание, что в роли аргументов для функций/методов, как правило...

std::string и/или char*
Здравствуйте. пишу метод построчной обработки данных из файла Вот он: bool...

Преобразование std::string в char*
Несомненно, работать с определенным в STL классом string работать в разы приятнее, чем с обычным...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru