5

私は自分でC++を学んでおり、この問題に取り組んでいました:

文字列からすべての先頭の空白を削除する、trimfrnt() という名前の関数を作成します。戻り値の型が void のポインターを使用して関数を記述します。

問題に対する私の試みは以下のとおりで、この問題を 2 つの方法で解決しようとしました (私の 2 つの関数trimfrnt1()trimfrnt2(). が正常にtrimfrnt1()動作することがわかります。偶然にこれが機能するようになりました。コーディングした後、なぜそれが正確なのかわかりませんでした)。私の混乱はforループにあります. 以下の msg 配列の図を描きました:

             |<--ptrMsg--------->|
  |<------for loop---->|
   0    1    2   3     4   5     6    7
+----+----+----+----+----+----+----+----+
|    |    |  G |  R |  E |  A |  T | \0 |
+----+----+----+----+----+----+----+----+
|  G |  R |  E |  A |  T |    |    | \0 |                             
+----+----+----+----+----+----+----+----+                                

質問1

上の図から、オーバーラップのため、実際には「GREATAT」というテキストを期待していました。5 文字しかループしていないため、文字列全体がシフトされて再初期化されたのはなぜですか?

質問2

質問にはポインターを使用するように記載されているので、trimfrnt1インデックスを作成していたために不正行為をしていたので、別の方法を試してみましたtrimfrnt2。この関数は、while ループで立ち往生しています。

    // shift characters to beginning of char array
    while( *(ptrMsg + count) != '\0' )
    {        
        *ptrMsg = *(ptrMsg + count);
        ptrMsg++;
        count++;
    }

コードのこの部分がうまくいきません。を印刷する*(ptrMsg + count)と文字化けするのですが、*ptrMsgの内容に代入すると文字化けしてしまいます。この場合、残りの文字を再初期化していないため、「GREATAT」も期待していました。私がやろうとしているように、ポインターメソッドを使用してこれを行う方法はありますか?

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

#include<iostream>
#include<iomanip>

using namespace std;

void trimfrnt1(char msg[], int size)
{
    char *ptrMsg = msg;

    // Find beginning of text
    while(*ptrMsg == ' ')
        ptrMsg++;

    // Copy text to beginning of array
    for(int i=0; i < size; i++)
        msg[i] = *ptrMsg++;

    // Reset pointer to beginning of array
    ptrMsg = msg;

    // Print array
    cout << "new msg1: ";
    cout << "\"" << ptrMsg << "\"" << endl;    
    cout << endl;

    return;
}

void trimfrnt2(char msg[], int size)
{
    int count = 0;      // used to find leading non-white space
    char *ptrMsg = msg; // pointer to character array

    // find first place of non white space
    while( *(ptrMsg + count) == ' ')
        count++;

    cout << "count = " << count << endl;

    // shift characters to beginning of char array
    while( *(ptrMsg + count) != '\0' )
    {        
        *ptrMsg = *(ptrMsg + count);
        ptrMsg++;
        count++;
    }
    cout << "count = " << count << endl;

    // Reset pointer to beginning of array
    ptrMsg = msg;

    // Print array
    cout << "new msg2: ";
    cout << "\"" << ptrMsg << "\"" << endl;    
    cout << endl;
}


int main()
{
    char msg[] = "  GREAT";
    const int size = sizeof(msg)/sizeof(char);

    cout << "Orginal msg:\"" << msg << "\"" << endl;

    trimfrnt1(msg, size);

    return 0;
}
4

3 に答える 3

3

trimfrnt1()未定義の動作があります-forループが原因ptrMsgで配列を超えて到達するため、自分に属さないメモリを読み取っているため、何かが起こる可能性があります。あなたのプラットフォームでは、そのような読み取りは問題ないように思われるため、ループはメモリから「ランダムな」ジャンクを喜んでコピーしますが、その前に終了NUL文字をコピーするため、結果として取得できません"GREATAT"while次のようにループを変更する必要があります。

while(*ptrMsg == ' ')
{
  ptrMsg++;
  --size;
}

"GREAT"終了NULは結果の一部であるため、これでも が得られますsizeof

ではtrimfrnt2()、 をインクリメントしているため、ループが間違っていますがcount、そうすべきではありません。そのため、変数にわかりやすい名前を付けるとよいでしょう。セマンティクスの後に呼び出された場合 (例: numberOfSpaces)、コピーwhile()ループでインクリメントを記述することさえ考慮しません。その増分を削除すると、期待trimfrnt2()する結果が得られるはずです。"GREATAT"


インスピレーションのために、算術なしでポインターを使用してこれを実装する方法を次に示します。

void trimfrnt3(char *msg, size_t size)
{
  const char *src = msg;
  while (*src == ' ')
    ++src;
  char *dst = msg;
  while (*src)
  {
    *dst = *src;
    ++src;
    ++dst;
  }
  cout << "new msg: \"" << msg << "\"\n";  //don't use endl unless you want to flush immediately
}

ご覧のとおり、このバージョンではsizeパラメーターを使用していないため、削除される可能性があります。

于 2013-11-14T13:36:54.050 に答える