Разница между строками и типами char [] в С++

Я знаю немного C, и теперь я смотрю на С++. Я привык к массивам char для работы со строками C, но пока я смотрю на код С++, я вижу, что есть примеры, использующие как строковый тип, так и char массивы:

#include <iostream>
#include <string>
using namespace std;

int main () {
  string mystr;
  cout << "What your name? ";
  getline (cin, mystr);
  cout << "Hello " << mystr << ".\n";
  cout << "What is your favorite team? ";
  getline (cin, mystr);
  cout << "I like " << mystr << " too!\n";
  return 0;
}

и

#include <iostream>
using namespace std;

int main () {
  char name[256], title[256];

  cout << "Enter your name: ";
  cin.getline (name,256);

  cout << "Enter your favourite movie: ";
  cin.getline (title,256);

  cout << name << " favourite movie is " << title;

  return 0;
}

(оба примера из http://www.cplusplus.com)

Я предполагаю, что это широко заданный и ответивший (очевидный?) вопрос, но было бы неплохо, если бы кто-нибудь мог сказать мне, какая именно разница между этими двумя способами для работы со строками на С++ (производительность, интеграция API, способ каждый лучше,...).

Спасибо.

Ответ 1

A char массив - это просто массив массивов символов:

  • Если выделено в стеке (например, в вашем примере), оно всегда будет занимать, например. 256 байтов независимо от того, как долго он содержит текст
  • Если выделено в куче (используя malloc() или новый char []), вы ответственны за освобождение памяти после этого, и вы всегда будете иметь накладные расходы на распределение кучи.
  • Если вы скопируете в массив массив из более чем 256 символов, это может привести к сбою, созданию уродливых сообщений об утверждении или вызвать необъяснимое (неправильное) поведение в другом месте вашей программы.
  • Чтобы определить длину текста, массив должен быть отсканирован, символ по символу, для символа \0.

Строка - это класс, который содержит массив char, но автоматически управляет им для вас. Большинство строковых реализаций имеют встроенный массив из 16 символов (поэтому короткие строки не фрагментируют кучу) и используют кучу для более длинных строк.

Вы можете получить доступ к массиву char следующим образом:

std::string myString = "Hello World";
const char *myStringChars = myString.c_str();

Строки С++ могут содержать вложенные символы \0, знать их длину без учета, быстрее, чем массивы с массивом char для коротких текстов и защищают вас от переполнения буфера. Кроме того, они более читабельны и удобны в использовании.

-

Однако строки С++ не подходят (очень) для использования через границы DLL, потому что для этого потребуется любой пользователь такой DLL-функции, чтобы убедиться, что он использует ту же самую реализацию компилятора и С++, чтобы он не рискнул своим строковым классом по-разному.

Как правило, класс string также выводит свою кучную память в кучу вызова, поэтому он сможет снова освободить память, если вы используете общую (.dll или .so) версию среды выполнения.

Вкратце: используйте строки С++ во всех своих внутренних функциях и методах. Если вы когда-либо писали .dll или .so, используйте строки C в своих общедоступных функциях (dll/so-protected).

Ответ 2

Ну, тип строки - это полностью управляемый класс для символьных строк, а char [] все еще тот, что был в C, массив байтов, представляющий вам строку символов.

В терминах API и стандартной библиотеки все реализовано в терминах строк, а не char [], но все еще есть много функций из libc, которые получают char [], поэтому вам может понадобиться использовать его для те, кроме этого, я всегда использовал бы std::string.

С точки зрения эффективности, конечно, необработанный буфер неуправляемой памяти почти всегда будет быстрее для многих вещей, но при учете сравнения строк, например, std::string всегда имеет размер, чтобы сначала проверить его, а с char [] вам нужно сравнить символ по символу.

Ответ 3

Arkaitz правильно, что string - управляемый тип. Это означает, что вам никогда не придется беспокоиться о том, как долго длится строка, и вам не нужно беспокоиться о освобождении или перераспределении памяти строки.

С другой стороны, обозначение char[] в приведенном выше случае ограничило буфер символов ровно 256 символами. Если вы попытаетесь записать более 256 символов в этот буфер, в лучшем случае вы перезапишете другую память, которую ваша программа "владеет". В худшем случае вы попытаетесь перезаписать память, которой у вас нет, и ваша ОС будет убивать вашу программу на месте.

Нижняя линия? Строки гораздо более дружелюбны программистам, char [] s намного эффективнее для компьютера.

Ответ 4

Я лично не вижу причин, по которым хотелось бы использовать char * или char [], за исключением совместимости со старым кодом. std::string не медленнее, чем использование c-строки, за исключением того, что он будет обрабатывать перераспределение для вас. Вы можете установить его размер при его создании и, таким образом, избежать перераспределения, если хотите. Оператор индексирования ([]) обеспечивает постоянный доступ времени (и во всех смыслах слова то же самое, что и с помощью индексатора c-строк). Использование метода at дает вам также проверенную безопасность, что-то, что вы не получаете с c-строками, если вы не напишете его. Ваш компилятор будет чаще всего оптимизировать использование индексатора в режиме выпуска. Легко повесить с c-струнами; такие как delete vs delete [], безопасность исключений, даже как перераспределить c-строку.

И когда вам приходится иметь дело с передовыми концепциями, такими как строки COW и не-COW для MT и т.д., вам понадобится std::string.

Если вы беспокоитесь о копиях, если вы используете ссылки и ссылаетесь на ссылки, где бы вы ни находились, у вас не будет накладных расходов из-за копий, и это то же самое, что вы делали бы с c-строкой.

Ответ 5

Строки имеют вспомогательные функции и автоматически управляют массивами char. Вы можете конкатенировать строки, для массива char вам нужно будет скопировать его в новый массив, строки могут изменить их длину во время выполнения. Массив char сложнее управлять, чем строка, и некоторые функции могут принимать только строку в качестве входных данных, требуя, чтобы вы преобразовали массив в строку. Лучше использовать строки, они были сделаны так, что вам не нужно использовать массивы. Если бы массивы были объективно лучшими, у нас не было бы строк.

Ответ 6

Вспомните (char *) как string.begin(). Существенное отличие состоит в том, что (char *) является итератором, а std::string - контейнером. Если вы придерживаетесь основных строк, то (char *) даст вам то, что делает std::string:: iterator. Вы можете использовать (char *), когда хотите использовать итератор, а также совместимость с C, но это исключение, а не правило. Как всегда, будьте осторожны с недействительностью итератора. Когда люди говорят (char *) небезопасно, это то, что они означают. Это безопасно, как и любой другой итератор С++.

Ответ 7

Одно из отличий - Null term (\ 0).

В C и С++ char * или char [] будет указывать указатель на один char в качестве параметра и будет отслеживать по памяти до достижения значения 0 памяти (часто называемого нулевым терминатором).

Строки С++ могут содержать встроенные символы \0, знать их длину без учета.

#include<stdio.h>
#include<string.h>
#include<iostream>

using namespace std;

void NullTerminatedString(string str){
   int NUll_term = 3;
   str[NUll_term] = '\0';       // specific character is kept as NULL in string
   cout << str << endl <<endl <<endl;
}

void NullTerminatedChar(char *str){
   int NUll_term = 3;
   str[NUll_term] = 0;     // from specific, all the character are removed 
   cout << str << endl;
}

int main(){
  string str = "Feels Happy";
  printf("string = %s\n", str.c_str());
  printf("strlen = %d\n", strlen(str.c_str()));  
  printf("size = %d\n", str.size());  
  printf("sizeof = %d\n", sizeof(str)); // sizeof std::string class  and compiler dependent
  NullTerminatedString(str);


  char str1[12] = "Feels Happy";
  printf("char[] = %s\n", str1);
  printf("strlen = %d\n", strlen(str1));
  printf("sizeof = %d\n", sizeof(str1));    // sizeof char array
  NullTerminatedChar(str1);
  return 0;
}

Вывод:

strlen = 11
size = 11
sizeof = 32  
Fee s Happy


strlen = 11
sizeof = 12
Fee