2016-09-28 8 views
0

C++では、既に初期化された別の文字列(文字列クラス)から文字をインデックスワイズでコピーすることにより、新しい文字列(文字列クラス)を作成しました。C++の文字列は、すでに初期化された他の文字列からインデックス文字をコピーして形成されます。 coutを使って新しく形成された文字列を印刷することができません

しかし、coutを使用してこの新しい文字列を画面に印刷できません。 c_str()を使用して、coutを使用して印刷できます。しかし、printf()を使用する場合にのみ、Cタイプ文字列が必要なので、c_str()は必要ありませんか?

#include <cstring> 
#include <cmath> 
#include <cstdio> 
#include <vector> 
#include <iostream> 
#include <algorithm> 
using namespace std; 

int main() { 
    int i; 
    string a,b; 
    cin>>a; 
    for(i=0;a[i]!='\0';i++){ 
     b[i]=a[i]; 
    } 
    cout<<b; 
    return 0; 
} 

編集:ありがとうございました!しかし私は私の質問ではっきりしていないかもしれないので、これが私が持っている主要な問題です。あなたが私をさらに助けることができるなら、それは素晴らしいでしょう! (また、私はb=a;を割り当てる最も簡単な方法ですが、私は文字列を理解しようとしているので、質問です。)

a)私はcpp文字列がnull終端され、初期化後の文字列は、ループが終了し、文字列aの最後の文字の後で終了したため、NULL終了しました。ループの終了時に、cout<<a[i];の最後の文字が出力されるためです。

b)ループの中で、cout<<b[i];を含めると割り当て後、b [i]に割り当てられたと思われる値が出力されます。ですから、何らかの奇妙な理由のためにb [i]は存在します。

c)forループの外側では、プログラムの最後で、I cout<<b[2];が文字列の3番目の文字を出力します。そして私がcout<<b.c_str();を行うと、文字列全体が表示されます。その唯一の場合私はcout<< b;何も印刷されません。どうしてこれなの?

+0

のstd ::文字列ではありません(!)nullはそれがよいか(でも途中で)「\ 0」を含んでも含まなくても、 –

+0

C-終端文字列...あなたのループが間違っている –

+4

ますミスタイプの 'b = a;'。 – LogicStuff

答えて

1

bは空です。 b[i]に割り当てると、iの任意の値に対して未定義の動作が発生します。

a[i]!='\0'条件は、コンパイラがC++ 11以降をサポートしている場合にのみ有効です。以前はC++ 11 str[str.size()]には未定義の動作がありました。


最初に問題を解決するには、最初にbのサイズを変更します。 C++ 11のサポートがあれば、範囲ベースのループがはるかに簡単になります。あなたがC++ 11を持っていない場合は、次のように有効なオプションです:文字列をコピーするためにループを書く

b.resize(a.size()); 
for(i=0; i < a.size(); i++) 

はいえ少し愚かです。あなたは、単に割り当てを使用することができます。

b = a; 

A)私はそれがないときは、CPPの文字列がnullで終了している時に知らないが、この場合には初期化後の文字列がnullでループため終了しましたループの終了時にcout<<a[i];の最後の文字列が出力されるため、文字列aの最後の文字の後に終了しました。

あなたがお使いのオペレーティングシステム上で、あなたのコンパイラでコンパイルし、その特定の時間にあなたのCPU上でプログラムを実行したときに観察するものであることを起こること(あなたが有効になってC++ 11でコンパイルされていないと仮定)。何らかの要因が変化した場合の動作が同じであるという保証はありません。私はcout<<b[i];を含める割り当てた後、ループ内

b)に、それは我々がちょうどb[i]に割り当てられた期待値をプリントアウトしません。だから、b[i]

いくつかの奇妙な理由のために存在しないことはb[1]が「存在する」という意味ではありません。この動作は未定義です。

c)プログラムの最後で、Icout<<b[2];の文字列の3番目の文字が印刷されます。そして私がcout<<b.c_str();を行うと、文字列全体が表示されます。その唯一の場合私はcout<< b;何も印刷されません。どうしてこれなの?

これは動作が定義されていないためです。

+0

助けてくれてありがとうございますが、編集を確認してください。 – Zag

+0

@Zagあなたの編集に対する私の回答を見てください。 – user2079303

2

b[n]を使用して文字を上書きする前に、bに領域を割り当てる必要があります。だからb.resize(...)が必要です。それ以外の場合は、b += a[i];を使用して各文字を末尾に追加する必要があります。

この考えてみましょう::

:追加の質問に答えるために

int main() 
{ 
    int i; 

    string a, b; // these are both empty 

    std::cout << "a.size() = " << a.size() << '\n'; 
    std::cout << "b.size() = " << b.size() << '\n'; 

    cin >> a; // now a contains something 

    std::cout << "a.size() = " << a.size() << '\n'; 
    std::cout << "b.size() = " << b.size() << '\n'; 

    // for(i = 0; a[i] != '\0'; i++) // no don't test for null 
    // { 
    // b[i] = a[i]; // no b has no spaces 
    // } 

    for(std::size_t i = 0; i < a.size(); ++i) 
     b += a[i]; // increases b's size by one each time 

    std::cout << "b.size() = " << b.size() << '\n'; 

    cout << b; 
} 

またstd::stringはヌルがそう、\0をチェックする彼らのsize()を使用しないでくださいを終了しではありませんa)std::stringがnullで終わる内部実装の詳細です。 null終端文字は、パブリックインターフェイスの有効な範囲外であり、アクセスするには技術的には「未定義の動作」です。 正しいの末尾を見つける方法は、size()関数またはそのend()イテレータを使用しています。

b)文字列の終わりを超えて割り当てられたメモリがあると、純粋な運があります。たとえそこにメモリがあっても、文字列の一部ではなくではなくの法律の文字列操作a = b;の間にコピーされます。

c)完全に未定義の動作です。おそらくstd::cout << b;は、size()zeroの文字列であり、size()zero(私の例を参照)であるため何も印刷しないことを決定します。しかし、c_str()は単に文字列の先頭のメモリアドレスを返します。メモリアドレスだけでは、std::coutは、それが来る文字列がどれくらい大きいかを知ることができません。したがって、nullを検出するまで印刷文字を保持します。あなたが望んでいるものを印刷するなら、それは純粋な運です。

+0

助けてくれてありがとうございます。編集を確認してください。 – Zag

+0

@Zag私はあなたの追加の質問に私ができる限り答えるために私の答えを編集しました。 – Galik

3

std::stringは通常のCスタイルの文字列のようには動作しないことに気付かれるかもしれません。それに気づくことが重要です。

まず、そのような直接割り当ては機能しません。本当の理由は、これが文字列のサイズを変更しないということです。 b.size()を出力するか、b.start()b.end()の両方が同じcharを参照していることを確認すると、自分で見つけることができます。b[0]

最初にbのサイズをaに変更した場合、実験は機能します。

b.resize(a.size()); 

第2に、ループを見てください。それがCスタイルの文字列であるかのように、\0と比較しないでください。代わりに、i < a.size()をチェックしてください。std::stringがnull(\0)になる保証はありません。

あなたは本当にすべきことはありますが、単純にaをbに割り当て、bには意図したとおりのaのコピーがあります。

b = a; 
+0

助けてくれてありがとうございますが、編集を確認してください! – Zag

関連する問題