8
#include <string.h>
#include<stdio.h>
#include<stdlib.h>

char *chktype(char *Buffer, int Size)
{
   char *strng = "Content-Type: ";
   int sz;
   char *found = strstr (Buffer, strng);
   char *found1 = strstr(found, "\r\n");
   sz=strlen(found)-strlen(found1);
   char type[sz];
   strncpy(type, found1, sz-1);

   return(type);
}

void main(){

   char *buffer = "HTTP/1.1 200 OK\r\nDate: Tue, 25 Jun 2013 16:27:16
   GMT\r\nExpires: -1\r\nCache-Control: private,
   max-age=0\r\nContent-Type: text/html; 
   charset=UTF-8\r\nContent-Encoding: gzip\r\nServer: 
   gws\r\nX-XSS-Protection: 1; mode=block\r\nX-Frame-Options:
   SAMEORIGIN\r\nTransfer-Encoding: chunked\r\n\r\n";

   char *extension = chktype (buffer, sizeof(buffer));
   printf("%s\r\n", extension);
}

これにより、次の結果が得られます。

warning: function returns address of local variable [enabled by 
default]

...そして、ここで何が問題なのかわかりません。実行すると、出力が意味不明になると思いますtext/html; charset=UTF-8

警告の正確な意味は何ですか?

4

4 に答える 4

16

このchktype関数は、スタック上の自動変数にメモリを割り当て、この変数のアドレス (つまり、この変数へのポインタ) を返します。

問題は、スタックに割り当てられた変数がスコープ外になるたびに自動的に破棄されることです (つまり、関数を定義する中括弧の外に制御が渡されます)。

これは、基本的に、無効なメモリ位置へのポインターを返していることを意味します。これは悪いニュースです。C言語では、未定義の動作です。実際には、結果として出力が低下したり、場合によってはクラッシュしたりすることさえあります。

char *chktype(char *Buffer, int Size)
{
    // This pointer variable is allocated on the stack, but that's okay because
    // it's a pointer to a string literal, which are always constant.
    // (Technically, you should add the "const" qualifier to the declaration.)
    const char *strng = "Content-Type: ";

    int sz;
    char *found = strstr (Buffer, strng);
    char *found1 = strstr(found, "\r\n");
    sz=strlen(found)-strlen(found1);

    // Like all the above variables, the one is also allocated on the stack.
    // But it's the source of your problem here, because it's the one that
    // you are returning at the end of the function.
    // Problem is, it goes away at the end of the function!
    char type[sz];
    strncpy(type, found1, sz-1);
    return(type);
}

関数から aを返す正しい方法は、 (または) 関数char*を使用してヒープから新しいメモリを割り当てることです。これは、関数の呼び出し元が、戻り値によって使用されるメモリを解放する責任があることを意味します。そうしないと、プログラムでメモリ リークが発生します。(この要件は、常に関数のドキュメントに記載してください!「ドキュメント」が宣言の上のコメントを意味する場合でも)。malloccalloc

たとえば、コードを次のように変更します。

char *chktype(char *Buffer, int Size)
{
    // This pointer variable is allocated on the stack, but that's okay because
    // it's a pointer to a string literal, which are always constant.
    // (Technically, you should add the "const" qualifier to the declaration.)
    const char *strng = "Content-Type: ";

    int sz;
    char *found = strstr (Buffer, strng);
    char *found1 = strstr(found, "\r\n");
    sz=strlen(found)-strlen(found1);

    char *type = malloc(sz);  // allocate memory from the heap
    strncpy(type, found1, sz-1);
    return(type);
}

ここで、chktype関数の呼び出し側で、free戻り値の処理が終わったら必ず呼び出すようにする必要があります。

char *type = chktype(...);
// do something
free(type);

堅牢なコードはmalloc、null ポインターの結果をテストして、要求されたメモリの割り当てに失敗していないことを確認する必要があることに注意してください。その場合、何らかの方法でエラーを処理する必要があります。わかりやすくするために、上には示していません。

于 2013-06-26T05:50:35.190 に答える
9

クイック/ハッキーな回答(?):

作る

char type[sz];

の中へ

static char type[sz];

長い答え:エラーはかなり明確です。関数が を返すとすぐに破棄される変数のアドレスを返しています。これを回避するには、いくつかの方法があります。

簡単な方法の 1 つは type を作成することですstatic。これにより、型変数に program の有効期間を持たせることで問題が修正されますが、これは、2 回続けて呼び出すことができないことを意味し、再度呼び出す前に結果を印刷またはコピーする必要があります。 .

もう 1 つの方法は、関数内の配列にメモリを割り当てchar、使い終わったらそれを覚えておくfreeことです。そうしないと、メモリ リークが発生します。これにより、上記の欠点はありません。

于 2013-06-26T05:46:37.873 に答える
2

typeasを宣言するとchar type[sz]、ローカル変数が与えられます。関数が戻ると、そのメモリの有効期間は終了します。代わりに、たとえば を使用して動的にメモリを割り当てる必要がありますmalloc

char *type = (char *) malloc (sz * sizeof (char));
于 2013-06-26T05:50:02.823 に答える
0

を返します type。これは、スタックに割り当てられた配列を指し、関数chktype()が戻った後は無効です。

次のように、結果をヒープに割り当てることができます。

char * chktype(const char * buffer, int size)  
{
  char * strng = "Content-Type: ";
  char * found = strstr (buffer, strng);
  char * found1 = strstr(found, "\r\n");
  size_t sz = strlen(found) - strlen(found1);
  char * type = calloc(sz, sizeof(*type));
  if (type)
  {
    strncpy(type, found1, sz - 1);
  }

  return type;
}

しかし、不要にfree()なった後の結果には必要性があります。

于 2013-06-26T05:47:11.553 に答える