2009-03-18 14 views
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として印刷しようとしましたが、それでも動作しません。このプログラムで何が問題になっていますか?char *関数がCで正しく表示されない

+1

これは古典的ですエラー - 誰もが一度それを作る必要があります、その後、彼らは "範囲"について理解するでしょう。ところで、未定義のバッファはまだメモリに残っている可能性があるので、あなたは幸いです。時にはこのようなものは発見されません! – gbarry

答えて

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パラメーターは、バッファーが指すスペースの量を正確に指定します)。

3

バッファは関数が返ってきたときに蒸発するローカル変数です - あなたが見ているのは未定義の振る舞いです。このための迅速かつ汚い修正が、それは関数呼び出しの後の周りにハングするようにバッファを静的にすることです - 変更:

char buffer [80]; 

へ:

static char buffer [80]; 
+0

なぜ1000人が同じ人物が同じ回答を入力しても同じことを言っているのですか? –

+0

これは良い解決策ではありません。値を返すために何か静的にすることは、最初に取るべきアプローチではありません。これにより、変数はアプリケーションの存続期間全体にわたって存在します。代わりにメモリを割り当てるか、outパラメータを使用してください。 –

+0

さて、最初のカップルは、ニールがまだ入力していたときに入力していた可能性があるという言い訳があります。しかし、3〜4分後に答えた人は、彼らには言い訳があるとは思えませんが、そのうちのいくつかはもっと説明を書く時間がかかりました。 –

4

声明char buffer [80];bufferは、CSAののスタックに割り当てられます。それをmallocchar *buffer = malloc (80))に交換してください。大丈夫です。後で自分でバッファーを解放する必要があります。

0

あなたはczas()を呼び出しますが、戻った後は、作成されたバッファは存在しなくなりました。

0

スタックに割り当てられた「バッファ」が返されます。しかし、関数が復帰すると、スタックのその部分はもはや有効ではなくなります。

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

4

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

いずれか:

  • 静的バッファを使用し、関数はリエントラントではないことを認識し、発呼者にその後)(それを)(malloc関数でバッファを割り当て、そして解放することを忘れない

いずれのオプションにも欠点があります。

10

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

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

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

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

E.G:

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のがサイズのparamを取っ気づかなかった、私はこれを使用すると、正しくはstrftimeから結果を返すためのコードを更新しました。その結果、これははるかに堅牢で、誤ってバッファーをオーバーフローさせることはありません。

+0

また、バッファのアドレス指定が小さすぎる可能性がある場合は、czas関数の内部でsizeof(バッファ)をチェックするには不十分です。これは、バッファのサイズではなく文字ポインタのサイズだけを与えます。第2引数としてバッファサイズを渡す必要があります。 –

関連する問題