7

割り当てられた長さのchar*バッファを文字列の内容で埋める関数を作成する必要があります。弦が長すぎる場合は、カットするだけです。バッファは私ではなく、私の関数のユーザーによって割り当てられます。私はこのようなことを試みました:

int writebuff(char* buffer, int length){
    string text="123456789012345";
    memcpy(buffer, text.c_str(),length);
    //buffer[length]='\0';
    return 1;
}


int main(){
    char* buffer = new char[10];
    writebuff(buffer,10);
    cout << "After: "<<buffer<<endl;
}

私の質問はターミネーターについてです:それはそこにあるべきかどうか?この関数ははるかに広いコードで使用されており、文字列をカットする必要があるときに奇妙な文字で問題が発生するように見えることがあります。

従うべき正しい手順に関するヒントはありますか?

4

10 に答える 10

10

Cスタイルの文字列は、ゼロ文字で終了する必要'\0'があります。

さらに、コードに別の問題があります。ソース文字列の末尾を超えてコピーしようとする場合があります。これは古典的な未定義の動作です。文字列がヒープメモリブロックの最後に割り当てられ、コピーがメモリの保護された領域に移動して見事に失敗するまでは、機能しているように見える場合があります。バッファの長さまたは文字列の長さの最小値までのみコピーする必要があります。

PS完全を期すために、ここにあなたの関数の良いバージョンがあります。終了ヌルのオフバイワンエラーを指摘してくれたNaveenに感謝します。返される文字列の長さ、または渡された長さが0未満の場合に必要な文字数を示すために、戻り値を自由に使用しました。

int writebuff(char* buffer, int length)
{
    string text="123456789012345";
    if (length <= 0)
        return text.size();
    if (text.size() < length)
    {
        memcpy(buffer, text.c_str(), text.size()+1);
        return text.size();
    }
    memcpy(buffer, text.c_str(), length-1);
    buffer[length-1]='\0';
    return length-1;
}
于 2011-05-10T15:33:56.923 に答える
8

バッファを文字列として扱いたい場合は、NULLで終了する必要があります。このためには、length-1を使用して文字をコピーし、文字をとしてmemcpy設定する必要があります。length-1\0

于 2011-05-10T15:34:43.967 に答える
2

C ++を使用しているようです-与えられた場合、最も単純なアプローチは(インターフェイス仕様でNUL終了が必要であると仮定して)です。

int writebuff(char* buffer, int length)
{
  string text = "123456789012345";
  std::fill_n(buffer, length, 0); // reset the entire buffer
  // use the built-in copy method from std::string, it will decide what's best.
  text.copy(buffer, length);
  // only over-write the last character if source is greater than length
  if (length < text.size())
    buffer[length-1] = 0;
  return 1; // eh?
}
于 2011-05-10T15:50:52.897 に答える
1

char *バッファは、明示的に長さをどこにでも渡して、バッファがnullで終了しないように言っていない限り、nullで終了する必要があります。

于 2011-05-10T15:34:47.063 に答える
0

そこにあるはずです*。これにより、バッファに対して長すぎる文字列が完全にいっぱいになり、後でアクセスしたときにオーバーフローが発生するのを防ぎます。imoのstrncpy代わりに使用する必要がありmemcpyますが、それでもnullで終了する必要があります。(また、あなたの例はメモリをリークします)。

*疑問がある場合は、最も安全なルートに進んでください。

于 2011-05-10T15:33:03.200 に答える
0

私の質問はターミネーターについてです:それはそこにあるべきかどうか?

はい。そこにあるはずです。そうでなければ、後で文字列がどこで終わるかをどうやって知ることができますか?そして、どのようcoutに知るでしょうか?値がたまたまであるガベージに遭遇するまで、ガベージを印刷し続けます\0。プログラムがクラッシュすることさえあります。

補足として、プログラムがメモリリークを起こしている。割り当てたメモリは解放されません。ただし、を終了するためmain()、それほど重要ではありません。結局のところ、プログラムが終了すると、割り当てを解除したかどうかに関係なく、すべてのメモリがOSに戻ります。ただし、メモリ(またはその他のリソース)の割り当てを自分で解除することを忘れない場合は、一般的には良い習慣です。

于 2011-05-10T15:33:03.620 に答える
0

文字列をaで終了する必要があるかどうかは、関数\0の仕様によって異なりますwritebuff。関数を呼び出した後、持っているものがbuffer有効なCスタイルの文字列である必要がある場合は、それを。で終了する必要があります\0

ただし、これはaでc_str()終了する\0ため、ソース文字列のサイズとして使用できることに注意してください。text.size() + 1またlength、文字列のサイズよりも大きい場合はtext、現在のコードで提供されているものよりもさらにコピーすることに注意してください(これmin(length - 2, text.size() + 1/*trailing \0*/)を防ぐために使用し、buffer[length - 1] = 0上限を設定することができます)。

buffer割り当てられたがリークされていますmain、ところで

于 2011-05-10T15:34:16.237 に答える
0

strncpyが進むべき道であるというネクロリスに同意しますが、文字列が長すぎるとnullターミネータを取得しません。明示的なターミネータを配置することについては正しい考えがありましたが、記述されているように、コードはそれを最後から1つ超えて配置します。(これはCです。C++よりも多くのCを実行しているように見えたからですか?)

int writebuff(char* buffer, int length){
    char* text="123456789012345";
    strncpy(buffer, text, length);
    buffer[length-1]='\0';
   return 1;
}
于 2011-05-10T15:39:17.090 に答える
0

writerbuffまず、文字列を終了する必要があるかどうかわかりません。それは設計上の質問であり、存在すべきであると決定した人が答えるwritebuff必要があります。

第二に、全体としてあなたの特定の例をとると、2つの問題があります。1つは、終了していない文字列をに渡すことですoperator<<(ostream, char*)。2つ目は、コメントアウトされた行が、示されたバッファーの終わりを超えて書き込むことです。これらは両方とも未定義の動作を引き起こします。

(3番目は設計上の欠陥です-それlengthが常に長さよりも短いことを知っていますtextか?)

これを試して:

int writebuff(char* buffer, int length){
  string text="123456789012345";
  memcpy(buffer, text.c_str(),length);
  buffer[length-1]='\0';
  return 1;
}


int main(){
  char* buffer = new char[10];
  writebuff(buffer,10);
  cout << "After: "<<buffer<<endl;
}
于 2011-05-10T15:44:51.237 に答える
0
  1. では、で割り当てたバッファを割り当てるか、静的に割り当てるmain()必要があります( )。はい、それはたった10バイトです。はい、それは1回限りの割り当てであるため、リークではなくメモリの「プール」です。はい、プログラムの実行時間全体にわたってそのメモリが必要です。しかし、それでも夢中になれるのは良い習慣です。deletenew.char buf[10]

  2. C / C ++では、文字バッファーとの一般的な契約では、それらはnullで終了するため、明示的に行わないように指示されていない限り、これを含めます。もしそうなら、コメントし、char *パラメータにtypedefまたはnameを使用して、結果がnullで終了しない文字列であることを示します。

于 2011-05-10T15:52:34.933 に答える