7

文字列からスペースを削除したいプログラムがあります。エレガントな方法を見つけたかったので、フォーラムで次のコードを見つけました(読みやすくするために少し変更しました) :

char* line_remove_spaces (char* line)
{
    char *non_spaced = line;
    int i;
    int j = 0;
    for (i = 0; i <= strlen(line); i++)
    {
        if ( line[i] != ' ' )
        {
            non_spaced[j] = line[i];
            j++;
        }
    }
    return non_spaced;
}

ご覧のとおり、この関数は文字列を受け取り、同じ割り当てられたメモリ空間を使用して、スペースのない文字のみを選択します。できます!

とにかく、ウィキペディアによると、C の文字列は「ヌル終了文字列」です。私はいつもこのように考えていて、すべてが良かったです。しかし問題は、文字列の最後に「ヌル文字」を入れていないことnon_spacedです。そして、どういうわけか、コンパイラは、「non_spaced」文字列によって変更された最後の文字で終了することを認識しています。それはどのように知っていますか?

4

7 に答える 7

12

これは魔法では起こりません。コードに次のものがあります。

for (i = 0; i <= strlen(line); i++)
              ^^

ループ インデックスiまで実行strlen(line)され、このインデックスで文字配列にヌル文字があり、これもコピーされます。その結果、最終結果の目的のインデックスにヌル文字が含まれます。

もしあなたが持っていたら

for (i = 0; i < strlen(line); i++)
              ^^

次に、次のように nul 文字を手動で配置する必要がありました。

for (i = 0; i < strlen(line); i++)
{
    if ( line[i] != ' ' )
    {
        non_spaced[j] = line[i];
        j++;
    }
}
// put nul character
line[j] = 0;
于 2012-04-27T11:39:34.290 に答える
7

他の人がすでにあなたの質問に答えていますが、これは同じコードのより高速で、おそらくより明確なバージョンです。

void line_remove_spaces (char* line)
{
  char* non_spaced = line;

  while(*line != '\0')
  {
    if(*line != ' ')
    {
      *non_spaced = *line;
      non_spaced++;
    }

    line++;
  }

  *non_spaced = '\0';
}
于 2012-04-27T12:02:11.787 に答える
2

ループは を使用する<= strlenので、ヌル ターミネータもコピーします (これは ati == strlen(line)です)。

于 2012-04-27T11:38:36.440 に答える
1

あなたはそれを試すことができます。スペースを1つだけ含む文字列を処理しているときにデバッグします" "。インデックスがどうなるかを注意深く観察してiください。

于 2012-04-27T11:35:47.207 に答える
0

それが「知っている」ことをどうやって知っていますか?最も可能性の高いシナリオは、未定義の動作に単に運があり'\0'、有効な終了バイトの後に-文字があることですline

また、最後にスペースが表示されていない可能性が高くなります。スペースは、迷子の「ラッキー'\0'」に当たる前に印刷される可能性があります。

他のいくつかのポイント:

  • インデックスを使用してこれを記述する必要はありません。
  • strlen()ループの反復ごとに呼び出すのはあまり効率的ではありません。
  • isspace()より多くの空白文字を削除するために使用することをお勧めします。

isspace()とポインタを使用して、次のように記述します。

char * remove_spaces(char *str)
{
  char *ret = str, *put = str;

  for(; *str != '\0'; str++)
  {
    if(!isspace((unsigned char) *str)
      *put++ = *str;
  }
  *put = '\0';

  return ret;
}

これにより、スペースのないバージョンの文字列終了するため、返されるポインタは有効な文字列を指すことが保証されていることに注意してください。

于 2012-04-27T11:37:00.643 に答える
0

関数の文字列パラメーターは null で終了していますよね? また、ループでは、元の文字列のヌル文字も間隔のない返された文字列にコピーされます。したがって、間隔のない文字列も実際には null で終了します!

コンパイラにとって、null 文字は、特別な処理を行わないバイナリ データの 1 つにすぎませんが、文字列 API では、文字列の終わりを簡単に検出するための便利な文字として使用されます。

于 2012-04-27T11:42:46.803 に答える
0

を使用する場合は、インクルードの<= strlen(line)長さがプログラムが機能するようにします。デバッグを使用して分析を実行できます。strlen(line)'\0'

于 2012-04-27T13:38:10.200 に答える