C ++: "мой текст" - это std :: string, * char или c-string? - PullRequest
7 голосов
/ 21 августа 2010

Я только что сделал то, что кажется распространенной ошибкой новичка :

Сначала мы прочитали один из многих учебников , который выглядит так:

 #include <fstream>
 int main() {
      using namespace std;
      ifstream inf("file.txt");
      // (...)
 }  

Во-вторых, мы пытаемся использовать нечто похожее в нашем коде, которое выглядит примерно так:

#include <fstream>
int main() {
    using namespace std;
    std::string file = "file.txt"; // Or get the name of the file 
                                   // from a function that returns std::string.
    ifstream inf(file);
    // (...)
}

В-третьих, новичок-разработчик озадачен каким-то загадочным сообщением об ошибке компилятора.

Проблема в том, что ifstream принимает const * char в качестве аргумента конструктора.

Решение заключается в преобразовании std :: string в const * char .

Теперь реальная проблема заключается в том, что для новичка"file.txt" или подобные примеры, приведенные почти во всех уроках, очень похожи на std :: string.

Итак, "мой текст" это std :: string, c-string или * char или это зависит от контекста?

Можете ли вы привести примеры того, как «мой текст» будет интерпретироваться по-разному в зависимости от контекста?

[Edit: я думал, что приведенный выше пример сделал бы это очевидным, но я должен был быть более явным, тем не менее: я имею в виду тип любой строки, заключенной в двойные кавычки, то есть «myfilename.txt»,не значение слова «строка».]

Спасибо.

Ответы [ 8 ]

10 голосов
/ 21 августа 2010

Итак, является ли "строка" std :: string, c-string или * char или это зависит от контекста?

  • Ни C, ни C ++ не имеют встроенного строкового типа данных, поэтому любые строки в вашем коде в двойных кавычках по существу const char * (или, точнее, const char []).«C string» обычно относится к этому, в частности, к массиву символов с нулевым терминатором.
  • В C ++ std::string - это вспомогательный класс, который оборачивает необработанную строку в объект.Используя это, вы можете избежать (беспорядочной) арифметики указателей и перераспределения памяти самостоятельно.
  • Большинство стандартных библиотечных функций по-прежнему принимают только char * (или const char *) параметры.
  • Вы можете неявно преобразовать char * в std::string, потому что последний имеет конструктор для этого.
  • Вы должны явно преобразовать std::string в const char * с помощью метода c_str().

Спасибо Кларку Гебелю за то, что он указал const ness, и Джальфу и GMan за упоминание, что это на самом деле массив.

7 голосов
/ 21 августа 2010

"myString" является строковым литералом и имеет тип const char[9], массив из 9 констант char.Обратите внимание, что на нем достаточно места для нулевого терминатора.Итак, "Hi" - это const char[3] и т. Д.

Это в значительной степени всегда верно, без двусмысленности.Однако, когда это необходимо, const char[9] будет распадаться на const char*, который указывает на его первый элемент.И std::string имеет неявный конструктор, который принимает const char*.Поэтому, хотя он всегда начинается как массив символов char, он может стать другими типами, если вам это необходимо.

Обратите внимание, что строковые литералы имеют уникальное свойство, которое const char[N] также может переходить в char*, ноэто поведение не рекомендуется.Если вы попытаетесь изменить базовую строку таким образом, вы получите неопределенное поведение.Это просто не очень хорошая идея.

3 голосов
/ 21 августа 2010
std::string file = "file.txt"; 

Правая часть = содержит (необработанный) строковый литерал (то есть байтовую строку с нулевым символом в конце). Его эффективный тип array of const char.

= - хитрый пони: назначения не происходит. Класс std::string имеет конструктор, который принимает указатель на char в качестве аргумента, и он вызывается для создания временного std::string, и он используется для копирования-конструирования (используя ctor копирования std::string) объекта file типа std::string.

Хотя компилятор может удалить копию ctor и непосредственно создать экземпляр файла.

Однако обратите внимание, что std:string - это не то же самое, что строка с нулевым символом в конце в стиле C. Он даже не должен заканчиваться нулем.

ifstream inf("file.txt");

Класс std::ifstream имеет ctor, который принимает const char *, и переданный ему строковый литерал затухает до указателя на первый элемент строки.

Следует помнить следующее: std::string обеспечивает (почти бесшовное) преобразование из строк в стиле C. Вы должны найти сигнатуру функции, чтобы увидеть, передаете ли вы const char * или std::string (последний из-за неявных преобразований).

2 голосов
/ 21 августа 2010

Итак, является ли "строка" std::string, c-строкой или char* или это зависит от контекста?

Это полностью зависит от контекста. :-) Добро пожаловать в C ++.

Строка C - это строка с нулевым символом в конце, которая почти всегда совпадает с char*.

В зависимости от используемых вами платформ и платформ, может быть даже больше значения слова «строка» (например, оно также используется для ссылки на QString в Qt или CString в MFC).

1 голос
/ 06 апреля 2015

Ни C, ни C ++ не имеют встроенного строкового типа данных.

Когда компилятор обнаруживает, что во время компиляции неявно ссылаются строки с двойными кавычками (см. Код ниже), сама строка сохраняется в программном коде / тексте и генерирует код длясоздать массив четных символов:

  • Массив создается в статическом хранилище, потому что он должен сохраняться для последующего обращения к нему.
  • Массив устанавливается в константу, поскольку он всегда должен содержать исходные данные(Привет).

Итак, наконец, у вас есть const char * к этому константному статическому массиву символов.

const char* v()
{
    char* text = “Hello”;
    return text;
    // Above code can be reduced to:
    // return “Hello”;
}

Во время выполнения программыкогда элемент управления находит открывающую скобку, он создает «текст», указатель char * в стеке и постоянный массив из 6 элементов (включая нулевой терминатор «\ 0» в конце) в области статической памяти.Когда элемент управления находит следующую строку (char * text = «Hello»;), начальный адрес массива из 6 элементов присваивается «text».В следующей строке (вернуть текст;) возвращается «текст».С закрывающей скобкой «текст» исчезнет из стека, но массив все еще находится в области статической памяти.

Вам не нужно указывать тип возврата const.Но если вы попытаетесь изменить значение в статическом массиве, используя неконстантный символ *, это все равно даст вам ошибку во время выполнения, потому что массив является постоянным.Поэтому всегда полезно сделать возвращаемую константу постоянной, чтобы убедиться, что на нее нельзя ссылаться с помощью неконстантного указателя.

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

const char* v()
{
    char text[] = “Hello”;
    return text;
}

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

Во время выполнения программы с открытой скобкой в ​​стеке создается массив «text []» с 6 элементами.Но без инициализации.Когда код находит (char text [] = «Hello»;), массив инициализируется (с текстом в скомпилированном коде).Итак, массив теперь в стеке.Когда компилятор находит (возвращает текст;), он возвращает начальный адрес массива «текст».Когда компилятор находит закрывающую скобку, массив исчезает из стека.Поэтому нет возможности ссылаться на него по указателю возврата.

Большинство стандартных функций библиотеки по-прежнему принимают только параметры char * (или const char *).

Стандартная библиотека C ++ имеет мощный класс, называемый stringдля манипулирования текстом.Внутренняя структура данных для строки - это символьные массивы.Стандартный строковый класс C ++ разработан для того, чтобы позаботиться (и скрыть) все низкоуровневые манипуляции с массивами символов, которые ранее требовались программисту на Си.Обратите внимание, что std :: string является классом:

  • . Вы можете неявно преобразовать char * в std :: string, потому что последний имеет конструктор для этого.
  • Вы можете явно преобразовать std :: string в const char *, используя метод c_str ().
1 голос
/ 21 августа 2010

Стандартная библиотека C ++ предоставляет класс std :: string для управления и представления последовательностей символов. Он инкапсулирует управление памятью и большую часть времени реализован в виде C-строки; но это деталь реализации. Он также предоставляет процедуры манипуляции для общих задач.

Тип std :: string всегда будет таким (например, у него нет оператора преобразования в char *, поэтому у вас есть метод c_str ()), но он может быть инициализирован или назначен с помощью C -строка (символ *).

С другой стороны, если у вас есть функция, которая принимает в качестве параметра std :: string или const std :: string &, вы можете передать c-строку (char *) этой функции, и компилятор создаст std :: string на месте для вас. Это будет другая интерпретация в зависимости от контекста, как вы говорите.

0 голосов
/ 21 августа 2010

Чтобы использовать правильную формулировку (как указано в стандарте языка C ++) string является одной из разновидностей std :: basic_string (включая std :: string) из главы 21.3 «Классы String» в C ++ 0x N3092), в то время как аргумент конструктора ifstream NTBS (байтовая последовательность с нулевым символом в конце)

Цитировать, C ++ 0x N3092 27.9.1.4/2.

basic_filebuf * open (const char * s, ios_base :: openmode mode);

...

открывает файл, если это возможно, имя которого NTBS s

0 голосов
/ 21 августа 2010

Как можно чаще это должно означать std::string (или альтернативу, такую ​​как wxString, QString и т. Д., Если вы используете платформу, которая предоставляет такие. Иногда у вас нет другого выбора, кроме как последовательность байтов, заканчивающаяся NUL, но вы, как правило, хотите избегать ее, когда это возможно.

В конечном счете, просто нет четкой, однозначной терминологии. Такова жизнь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...