2009-08-17 2 views
90

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

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

int main() { 
    string mystr; 
    cout << "What's 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 << "'s favourite movie is " << title; 

    return 0; 
} 

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

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

спасибо.

+0

Это может помочь: [C++ символ * против станд :: строка] (http://stackoverflow.com/questions/801209/c-char-vs-stdstring) –

ответ

140

массив символов - это всего лишь массив символов:

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

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

Вы можете получить доступ к массив символов в строке как это:

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

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

-

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

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

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

+3

Кроме того, строки имеют кучу вспомогательных функций, которые могут быть действительно опрятными. –

+1

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

+1

Пример: вы распространяете исполняемые файлы VC2008SP1 в публичной библиотеке под названием libfoo, которая имеет std :: string & в своем общедоступном API. Теперь кто-то загружает ваш libfoo.dll и выполняет отладочную сборку. Его std :: string вполне может содержать некоторые дополнительные отладочные поля в нем, в результате чего смещение указателя на динамические строки перемещается. – Cygon

6

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

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

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

6

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

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

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

+3

В худшем случае другие люди перезапишут память и запустит вредоносный код на вашем компьютере. См. Также [переполнение буфера] (http://cwe.mitre.org/data/definitions/120.html). –

5

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

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

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

+0

+1 Хотя вы не рассматривали проблемы с реализацией, такие как совместимость с DLL, у вас есть COW. – 2009-08-17 12:35:22

+0

что я знаю, что мой массив char в 12 байтах? Если я создаю строку для этого, это может быть не очень эффективно? –

+0

@ David: Если у вас чрезвычайно чувствительный код, тогда да. Вы можете рассматривать std :: string ctor call как служебные данные в дополнение к инициализации элементов std :: string. Но помните, что преждевременная оптимизация сделала много кодовых баз без необходимости C-стиле, поэтому будьте осторожны. – Abhay

0

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

1

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

0

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

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

C++ строки могут содержать встроенные символы \ 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 
+0

Обратите внимание, что вы отвечаете на вопрос, заданный 8 лет назад. –

+0

@ n.m: Да, я это знаю. когда я прохожу через, большинство из них охвачены этим, и я добавил еще одну точку, которая поможет получить все ответы (максимум) в одном месте. –

Смежные вопросы