0

私のスキルをテストするために、いくつかの標準ライブラリ関数の独自のバージョンを作成しようとしています。, の代わりを書きましstrlen()strlength():

int strlength(const char *c){
    int len = 0;
    while (*c != '\0') {
        c++;
        len++;
    }
    return len;
}

これにはヌルターミネータが含まれていません。文字列を逆にする関数を作成しようとしています。これ:

char *reverse(const char *s){
    char *str = (char *)malloc(sizeof(char) * strlength(s));
    int i = 0;
    while (i < strlength(s)) {
        str[i] = s[(strlength(s) - 1) - i];
        i++;
    }
    str[strlength(s)] = '\0';
    return str;
}

のような 32 文字 (null ターミネータを含まない) を除くすべての文字列で機能しますfoofoofoofoofoofoofoofoofoofooforeverse()関数 while-loopでハングします。他のすべての量の文字については、機能します。なぜこうなった?

4

5 に答える 5

6

バッファstrが 1 ずれています。書き込みが残りのヒープにオーバーフローしています。

32 以外の値で機能する理由については、ヒープのメモリ アラインメントと関係があると思います。コンパイラは、バッファー サイズを小さくするために追加のパディングを追加していますが、32 バイトは適切に配置されているため (2 のべき乗、8 の倍数など)、追加のパディングを追加せず、バグがマニフェストの原因となっています。他の 8 の倍数を試してみると、おそらく同じ動作になるでしょう。

于 2013-06-25T16:34:50.337 に答える
1

交換

malloc(sizeof(char) * strlength(s))

malloc(sizeof(char) * (1+strlength(s)));

この線:

str[strlength(s)] = '\0';

malloc ライブラリ ルーチンはワード境界で整列されたブロックを予約し、呼び出しで要求された分だけ割り当てるため、頻繁に機能します。2 の累乗ですが、オーバーフローしたデータが割り当てられた部分を超えて上書きされた場合は、デバッガーを使用して逆アセンブリを調べることが、ターゲットの動作に固有のビルド ツール チェーンを理解するための最善の方法です。行は while ループ内ではなく、while ループをたどっているため、逆アセンブルしないと、while ループがどのように無限に変化するかは予測できません。

于 2013-06-25T16:39:27.090 に答える
0

バッファオーバーフローとランタイムのメモリ割り当ての実装/戦略の気まぐれについて他の人が言ったこと。C ストリングのサイズは、NUL 終了オクテットにより、その長さよりも 1 大きくなります。

このようなことを行う必要があります(少しクリーンで読みやすい):

#define NUL ((char)0) ;

char *reverse( const char *s )
{
  int   len = strlen(s) ;
  char *tgt = ((char*)malloc( 1+len )) + len ;
  char *src = s ;

  *(tgt--) = NUL ;
  while ( *src )
  {
    *(tgt--) = *(src++) ;
  }

  return tgt;
}

実装strlen()も必要以上に複雑です。これはあなたが必要とするすべてです:

int string_length( const char *s )
{
  char *p = s ;
  while ( *p ) ++p ;
  return p - s ;
}
于 2013-06-25T19:08:43.723 に答える