2
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

char *czas()
{
  time_t rawtime;
  struct tm * timeinfo;
  char buffer [80];
  time ( &rawtime );
  timeinfo = localtime ( &rawtime );
  strftime (buffer,80,"Now it's %I:%M%p.",timeinfo);
  return buffer;
}

int main()
{
printf("%s",czas());
system("PAUSE");
}

理由はわかりませんが、このプログラムの結果は「任意のキーを押してください(...)」だけです。%c として印刷しようとしましたが、まだ機能しません。このプログラムの何が問題になっていますか?

4

7 に答える 7

10

ローカル変数 ('buffer') へのポインターを返していますが、これは無効であり、それに関する警告が表示されないことに驚いています。

関数が終了すると、すべてのローカル変数が存在しなくなり (範囲外になると呼ばれます)、それらのメモリは他の目的に使用されます。このメモリへのポインタを返していますが、何がそこにあるという保証はありません。

この場合、printf 呼び出しの時点で、メモリには空の文字列として扱われる 0 が含まれているようです。これは実際には非常に幸運なことです。ガベージが出力されたり、プログラムがクラッシュしたりする可能性があります。

これを解決するには、バッファーを czas に渡すか、czas にヒープにバッファーを割り当てさせて、後で解放します。前者をお勧めします。これは、実質的にすべてのライブラリ関数の動作と一致しているためです。また、呼び出し元が後でポインターを解放する必要があるメモリ割り当ても回避します。

例えば:

size_t czas(char* buffer, size_t buffer_size)
{
    time_t rawtime;
    struct tm * timeinfo;

    time ( &rawtime );
    timeinfo = localtime ( &rawtime );
    return strftime (buffer, buffer_size,"Now it's %I:%M%p.",timeinfo);
}

int main()
{
    char buffer [80];
    if (czas(buffer, 80))
    {
      printf("%s\n",buffer);
    }
    else
    {
      printf("Call to czas failed");
    }
    system("PAUSE");
}

更新: strftime がサイズ パラメータを使用していることに気付きませんでした。コードを更新して、これを使用し、strftime から結果を正しく返すようにしました。その結果、これははるかに堅牢であり、誤ってバッファーをオーバーフローさせることはありません。

于 2009-03-18T20:07:55.090 に答える
4

ステートメントchar buffer [80];buffercsas のスタックに割り当てられます。mallocこれを( )の呼び出しにchar *buffer = malloc (80)置き換えれば問題ありません。後でバッファを自分で解放する必要があります。

于 2009-03-18T20:03:58.843 に答える
4

関数内の戻りバッファーは、スタック以外の場所にある必要があります。auto 変数を固定サイズの配列として宣言したため、スタック上にあります。それへのポインターを返しますが、そのスペースは、後続の関数呼び出しによって「走り書き」できます。

また:

  • 静的バッファを使用し、関数が再入可能ではないことを認識します
  • malloc() でバッファーを割り当て、呼び出し元で後で free() することを忘れないでください

どちらのオプションにも欠点があります。私がそれらを列挙する前に、あなたは17の答えを持っているでしょう:-)

于 2009-03-18T20:06:17.437 に答える
3

buffer は、関数が戻るときに蒸発するローカル変数であるため、未定義の動作が見られます。これに対する手っ取り早い修正方法は、バッファーを静的にして、関数呼び出しの後にぶらぶらするようにすることです。次のように変更します。

char buffer [80];

に:

static char buffer [80];
于 2009-03-18T20:03:29.097 に答える
2

マルチスレッドコードでこれを使用することが決してなく、最初の回答を使用する前に2回呼び出すことがないことが確実でない限り、静的バッファを使用しないでください。

Malloc はオプションですが、呼び出し先が割り当てたメモリを呼び出し元に強制的に解放させると、所有権の問題が未解決のままになり、バッファにヒープ メモリ以外を使用する可能性がなくなります。

私の意見では、あなたの最善の策は、アンドリュー・グラントの提案を変更することですが、バッファの長さも渡します。

char *czas(char *buffer, size_t bufferLength)
{
  time_t rawtime;
  struct tm * timeinfo;
  time ( &rawtime );
  timeinfo = localtime ( &rawtime );
  strftime (buffer, bufferLength, "Now it's %I:%M%p.",timeinfo);
  return buffer;
}

int main()
{
   char buffer [80];
   printf("%s",czas(buffer, sizeof(buffer)));
   system("PAUSE");
}

または

#define TIME_BUFFER_LENGTH 80
int main()
{
   char *buffer = malloc(TIME_BUFFER_LENGTH);
   if (buffer)
       printf("%s",czas(buffer, TIME_BUFFER_LENGTH));
   free(buffer);
   system("PAUSE");
}

これにより、潜在的なメモリ リークやバッファ オーバーフローを追跡しやすくなります。czas引数が正しい限り、関数がバッファをオーバーフローしたり、メモリをリークしたりしないことがわかります。次に、いずれかのバージョンを調べmainて、メモリ リークがないこと、および czas に渡されたパラメータが正しいことを確認します (bufferLength パラメータは、バッファが指すスペースの量を正確に指定します)。

于 2009-03-18T20:22:27.223 に答える
0

czas() を呼び出しますが、戻った後、czas が作成したバッファーは存在しません。

于 2009-03-18T20:04:14.133 に答える
0

スタックに割り当てられた「バッファ」を返しています。ただし、関数が戻ると、スタックのその部分は無効になります。

ヒープで返された文字列にメモリを割り当てるか、戻り値として std::string を使用します。

于 2009-03-18T20:04:15.693 に答える