2016-05-19 6 views
0

私は、関数呼び出しで宣言された変数がスタックにプッシュされ、関数がその終わりに達すると、スタックに宣言されたローカル変数がポップされてララの土地に入ることを認識します。関数で宣言された配列を返すと、Cのローカル変数のアドレスが返されますか?

私が納得していないことは、関数内にポインタを宣言すると、コンパイラの苦情のないポインタを返すことができますが、配列では警告が出ます。それはgetStringArrayの()についての警告「ローカル変数の戻りアドレスを」スローコンパイル中

char * getStringArray(); 
char * getStringPointer(); 

int main(){ 
     char * temp1 = getStringPointer(); 
     char * temp2 = getStringArray(); 
     return 0; 
} 
char * getStringPointer(){ 
     char * retString = "Fred"; 
     return retString; 
} 
char * getStringArray(){ 
     char retString[5] = {'F', 'r','e','d','\0'}; 
     return retString; 
} 

:ここ

は、私が参照してるものの一例です。私が混乱しているのは、配列の名前だけで参照すること(retString、no []など)は、ポインタのように動作するメモリ内のアドレスを参照していると言われています。

配列は便利なことがありますし、関数内で配列を使用して返したいということが何度もありますが、これを回避する方法はありますか?

コメントで言及したように、これは機能しますか?私はmallocがヒープに割り当てることを推測していますが、その罰金です。私はまだ静的なデータとヒープ上のデータの違いについては少し不明です。

char * getStringPointer(){ 
     char * retString = (char *)malloc(sizeof(char)*4+1); 
     *(retString+0) = 'F'; 
     *(retString+1) = 'r'; 
     *(retString+2) = 'e'; 
     *(retString+3) = 'd'; 
     *(retString+4) = '\0'; 
     return retString; 
} 
+0

ララランドとは何ですか?ポインタはメモリ内のアドレスを指すポインタに過ぎません。 'getStringArray()'に関して、5文字の配列を宣言して定義して戻したが、定義は宣言され、charへのポインタとして定義されているプロトタイプとは一致しない。 – t0mm13b

+0

@ t0mm13b 'char'の配列は' char'へのポインタに崩壊します。したがって、言語弁護士によると、 'getStringArray'については何も*違法です*。しかし、もちろん、スコープ外に出るメモリを指しています。 –

+0

エラーの可能性があることを警告するために、Cコンパイラに依存するべきではありません。それは 'lint'やそれに類するユーティリティが対象としているもので、問題があるものはすべて捕まえていません。 –

答えて

3

getStringPointerは、スタックにポインタを割り当ててから、実行可能ファイルのどこか(スタックではない)の文字列 'Fred \ 0'を指すポインタを返します。 getStringArrayはスタックに5文字分のスペースを割り当て、 'F' 'e' 'd'と '\ 0'を割り当て、スタック上にある 'F'のアドレスへのポインタを返しますしたがって、関数が返った後は無効です)。

2つの方法があります。mallocヒープ上の配列のスペースか、または適切なサイズの配列を含むstructを作成して戻すことができます。関数から数値型、ポインタ型、構造体型を返すことはできますが、配列は返すことはできません。

+0

'getStringArray'が返ってくると、' retString'がスタックからポップされ、返されたポインタにアクセスするとUB – yano

+0

となります。私はOPが、スタックへのポインタは関数が(質問の1番目のパラから)返ってもはや有効ではないことを理解していると思うが、文字列定数 '' Fred ''がスタックにないことを理解していない。 – patstew

+0

私は複数の答えとコメントから集めているので、関数内のポインタを宣言することはグローバルですが、配列を宣言することはできません。配列を静的にすることはお勧めできません。その理由は何ですか? – Khaines0625

3

"Fred"無名の世界なので、離れて行くし、それへのポインタを返すことは安全ではありません。しかし、getStringArray()は、ポインタが指しているものすべてを割り当て解除しています。それは違いです。

+0

@ Khaines0625もちろん、グローバル配列もあります。戻り値に影響を与える可能性のある記憶域修飾子までです。 – t0mm13b

0

アレイは、スタックローカルメモリへのポインタであることは明白であり、コンパイラはそれが漏れていることを確信しているので、警告が表示されます。

アレイをstaticにして、警告と有効期限の両方の制限がなくなります。

ポインタは静的なものやヒープ(実際は静的だったもの)を指している可能性があります。そのため、スタック型のものかどうかを漏らしているかどうかは分かりません。だからこそ、安全な返品であるかどうかに関係なく、ポインタを返すときに警告を受け取らないのです。再び、ストレージクラスstaticが保存されます。あなたの文字列定数は静的であるため、うまくいきます。

+0

あなたは「静的であるか、ヒープで」と言っています。私は静的変数がヒープに格納されているという印象を受けましたか?それは本当ですか? – Khaines0625

+0

それは本当ではありません。静的データは、実際のイメージファイル自体に存在する実行可能ファイルのセグメントに格納されます。 Cでは、ヒープは 'malloc(3) 'によって割り当てられたオブジェクトに対して厳密に使用されます。一つのこととして、すべての初期化は動的でなければならず、遅くなければなりません。 – DigitalRoss

0

という修飾語を変数retStringに追加してポインタを戻すと、問題が解決されます。

char * getStringArray(){ 
     static char retString[5] = {'F', 'r','e','d','\0'}; 
     return retString; 
} 

これは適切な値を返します。

配列の最初の要素がタイプT(この場合はchar)のポインタに減衰しているため、ポインタとして扱われていることに注目してください。これは、ソースの開始時に定義された関数自身のプロトタイプ宣言と一致するので、コンパイラを幸せにします。

ideone sample

関連する問題