web-dev-qa-db-ja.com

C ++のstring型とchar []型の違い

私は少しのCを知っていて、今はC++を調べています。私はC文字列を扱うためにchar配列に慣れていますが、C++コードを見ていると、文字列型とchar配列の両方を使用する例があります。

#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++で文字列を処理する2つの方法(パフォーマンス、API統合、それぞれの方法の違い)より良い、...)。

ありがとうございました。

115
ramosg

文字配列はまさにそれです-文字の配列:

  • スタックに割り当てられた場合(例のように)、常に占有します。含まれるテキストの長さに関係なく256バイト
  • (malloc()またはnew char []を使用して)ヒープに割り当てられた場合、後でメモリを解放する責任があり、常にヒープ割り当てのオーバーヘッドが発生します。
  • 256文字を超えるテキストを配列にコピーすると、クラッシュしたり、見苦しいアサーションメッセージが生成されたり、プログラムの他の場所で説明できない(誤った)動作が発生したりする可能性があります。
  • テキストの長さを判断するには、\ 0文字の配列を文字ごとにスキャンする必要があります。

文字列は、char配列を含むクラスですが、自動的に管理されます。ほとんどの文字列実装には、16文字の組み込み配列があり(したがって、短い文字列はヒープを断片化しない)、長い文字列にはヒープを使用します。

次のように文字列のchar配列にアクセスできます。

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

C++文字列には埋め込み\ 0文字を含めることができ、カウントせずにその長さを把握し、短いテキスト用のヒープ割り当て文字配列よりも高速であり、バッファオーバーランから保護します。さらに、読みやすく、使いやすくなっています。

-

ただし、C++文字列は、DLL境界を越えた使用には(非常に)適していません。これは、そのようなDLL関数のユーザーが、まったく同じコンパイラとC++実行時の実装。文字列クラスが異なる動作をするリスクを回避するため。

通常、文字列クラスは呼び出し元ヒープのヒープメモリも解放するため、ランタイムの共有(.dllまたは.so)バージョンを使用している場合にのみ、メモリを再び解放できます。

つまり、すべての内部関数とメソッドでC++文字列を使用します。 .dllまたは.soを記述する場合は、パブリック(dll/so-exposed)関数でC文字列を使用します。

166
Cygon

Arkaitzは、stringがマネージタイプであることを認識しています。これがyoの意味するところは、文字列の長さを心配する必要がなく、文字列のメモリの解放や再割り当てを心配する必要もないということです。

一方、上記の場合のchar[]表記は、文字バッファーを正確に256文字に制限しています。 256を超える文字をそのバッファに書き込もうとした場合、せいぜいプログラムが「所有」している他のメモリを上書きします。最悪の場合、所有していないメモリを上書きしようとすると、OSはその場でプログラムを強制終了します。

一番下の行?文字列はプログラマにとって使いやすく、char []はコンピュータにとってはるかに効率的です。

11
Mark Rushakoff

さて、文字列型は文字列の完全に管理されたクラスですが、char []は、文字列を表すバイト配列であるCの文字列のままです。

APIと標準ライブラリの点では、すべてがchar []ではなく文字列の観点から実装されていますが、libcにはchar []を受け取る関数がまだたくさんあるので、それらに使用する必要があるかもしれません。常にstd :: stringを使用します。

もちろん、効率の観点から、アンマネージメモリの生バッファは、多くの場合に常に高速になりますが、たとえば文字列の比較を考慮すると、std :: stringは常に最初にチェックするサイズを持ち、char []では文字ごとに比較する必要があります。

6
Arkaitz Jimenez

個人的には、古いコードとの互換性を除いて、char *またはchar []を使用したい理由はわかりません。 std :: stringは、再割り当てを処理することを除いて、c-stringを使用するよりも遅くありません。作成時にサイズを設定できるため、必要に応じて再割り当てを回避できます。インデックス演算子([])は、一定時間のアクセスを提供します(Wordのあらゆる意味で、C文字列インデクサーを使用するのとまったく同じことです)。 atメソッドを使用すると、c-stringsで得られないものを作成しない限り、境界チェックされた安全性も得られます。コンパイラは、ほとんどの場合、リリースモードでのインデクサーの使用を最適化します。 C文字列をいじるのは簡単です。 delete vs delete []、例外の安全性、c-stringの再割り当て方法など。

また、COW文字列やMTなどの非COWなどの高度な概念に対処する必要がある場合は、std :: stringが必要になります。

参照を使用し、可能な限りconst参照を使用している限り、コピーが心配な場合は、コピーによるオーバーヘッドは発生しません。これはc-stringを使用する場合と同じです。

5
Abhay

文字列にはヘルパー関数があり、char配列を自動的に管理します。文字列を連結することができます。新しい配列にコピーする必要があるchar配列の場合、文字列は実行時に長さを変更できます。文字配列は文字列より管理が難しく、特定の関数は入力として文字列のみを受け入れる場合があり、配列を文字列に変換する必要があります。配列を使用する必要がないように作成された文字列を使用することをお勧めします。配列が客観的に優れている場合、文字列はありません。

1
user6244076

違いの1つは、ヌル終端(\ 0)です。

CおよびC++では、char *または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
Eswaran Pandi

(char *)をstring.begin()と考えてください。本質的な違いは、(char *)がイテレータであり、std :: stringがコンテナであることです。基本的な文字列に固執する場合、(char *)はstd :: string :: iteratorの機能を提供します。イテレータの利点とCとの互換性が必要な場合は(char *)を使用できますが、それは例外であり、規則ではありません。いつものように、イテレータの無効化には注意してください。 (char *)が安全でないと人々が言うとき、これは彼らが意味するものです。他のC++イテレータと同じくらい安全です。

0