【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※返信付き投稿の削除は禁止!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら


本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール掲示板2こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.21301

関数からchar型の値をリターンで
投稿者---さい(2005/06/09 16:16:04)


関数からchar型の値をリターンで、呼ばれた関数に返しています。
コンパイルも通りますし、動きもします。
ですが、以下のメッセージが表示されます。

  a.c: In function `sub':
  a.c:18: warning: function returns address of local variable


warningを取り除くには、どうしたらいいのですか。
コンパイル時のオプションが不足なのでしょうか。

環境は、
 Soralis8
 gccでコンパイル
 gcc -o a a.c

---------------------------------------
#include <stdio.h>

char *sub() ;

main()
{
    char *p ;

    p=sub() ;

    printf("[%s]\n",p) ;
}

char *sub()
{
    char str[11] = {"1234567890"} ;

    return(str) ;
}



この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:関数からchar型の値をリターンで 21302 Blue 2005/06/09 16:32:29


No.21302

Re:関数からchar型の値をリターンで
投稿者---Blue(2005/06/09 16:32:29)


>char *sub()
>{
>    char str[11] = {"1234567890"} ;
>
>    return(str) ;
>}

変数のスコープを考えてみてください。
strの領域はsub内で有効ですが、mainの中では保障されないと思います。

動的に領域を確保し、その領域を返すようにすればいいかと。
(mallocやfreeを調べ見てください)



この投稿にコメントする

削除パスワード

No.21303

Re:関数からchar型の値をリターンで
投稿者---RiSK(2005/06/09 16:57:27)


>変数のスコープを考えてみてください。
>strの領域はsub内で有効ですが、mainの中では保障されないと思います。

文字列リテラルは自動的に静的記憶域をもつはず。
mainでも保証されるはず。
私の記憶違い?

char *sub() {
    return "1234567890";
}

ではどうですか?


この投稿にコメントする

削除パスワード

No.21304

Re:関数からchar型の値をリターンで
投稿者---Blue(2005/06/09 17:20:35)


>文字列リテラルは自動的に静的記憶域をもつはず。
>mainでも保証されるはず。
そのようですね。
あまり詳しくはわからないですけど。。。

WinXp,VC++6.0で試してみました。

#include <stdlib.h> #include <stdio.h> #include <string.h> char* test1() { return "test1"; } char* test2() { char s[] = "test2"; return s; } char* test3() { char* p = "test3"; return p; } char* test4() { char* p = ( char* )malloc( sizeof( char ) * 8 ); strcpy( p, "test4" ); return p; } int main( void ) { char* p; p = test1(); puts( p ); p = test2(); puts( p ); // これだけダメ p = test3(); puts( p ); p = test4(); puts( p ); free( p ); return EXIT_SUCCESS; }



この投稿にコメントする

削除パスワード

No.21306

Re:関数からchar型の値をリターンで
投稿者---si(2005/06/09 18:19:52)


どの環境でも同じじゃないですか(多分)
Linux(fc4t3) & gcc4 での結果

>char s[] = "test2";

gccの警告: 関数がローカル変数のアドレスを返しています
これだと文字配列、関数内のスタックに積まれてしまうような気がします。

>char* p = "test3";

こちらは、ポインタ変数 p が、データエリア内の文字配列を指す

違うかな?


この投稿にコメントする

削除パスワード

No.21309

Re:関数からchar型の値をリターンで
投稿者---elder(2005/06/09 22:02:07)


前橋和弥さんのK.Maebashi's home page,
 「配列とポインタの完全制覇」より引用

>文字列リテラルは、通常は書き込み禁止の領域に確保される (正確には実装依存)。
>しかし、char の配列を初期化している場合は、単に中括弧内に文字を区切って書く初期化子の省略形に過ぎないので、
>配列自体に const 指定がない限り書き込みが可能である。

ということで、文字列リテラルは静的記憶域、スタック、ヒープでもない
特別な領域に格納されてるようです。
(著書 C言語ポインタ完全制覇では、この領域を書き込み禁止領域と書き表しています。)

ちなみに、関数と文字列リテラルは同じ領域に格納されるそうです。
配列に関してはスタックに積まれるで合っています。


この投稿にコメントする

削除パスワード

No.21310

Re:関数からchar型の値をリターンで
投稿者---YuO(2005/06/09 23:42:41)


>>変数のスコープを考えてみてください。

スコープというのは「識別子」が有効である範囲のことです。
「オブジェクト」が有効である範囲(記憶域期間)とは異なります。
この二つは全く別物ですのでちゃんと区別して下さい。


>>strの領域はsub内で有効ですが、mainの中では保障されないと思います。
>文字列リテラルは自動的に静的記憶域をもつはず。
>mainでも保証されるはず。

文字列リテラルであれば,確かに静的記憶域期間をもっていますから,
当然mainでも生存しています。

ただし,元投稿では自動記憶域期間をもつオブジェクトへのポインタを返していますから,
mainでは既に死んでしまっています。


ちなみに,スタックだのヒープだのと言うのは実装に依存することであり,
自動記憶域期間をもつオブジェクトのためにスタックを使うなどと,
標準規格は言っていないです。
# 使ってはいけないわけではないが,使わなくても良い……それが実現できるなら。



この投稿にコメントする

削除パスワード

No.21311

Re:関数からchar型の値をリターンで
投稿者---Blue(2005/06/09 23:55:30)


>>>変数のスコープを考えてみてください。
>
>スコープというのは「識別子」が有効である範囲のことです。
>「オブジェクト」が有効である範囲(記憶域期間)とは異なります。
>この二つは全く別物ですのでちゃんと区別して下さい。

指摘ありがとうございました。
記憶域期間と混同していました。

# なんか、指摘されてばっかですな。。。orz




この投稿にコメントする

削除パスワード

No.21312

Re:関数からchar型の値をリターンで
投稿者---RiSK(2005/06/10 00:10:11)


>スコープというのは「識別子」が有効である範囲のことです。

私も知りませんでした。

>ただし,元投稿では自動記憶域期間をもつオブジェクトへのポインタを返していますから,
>mainでは既に死んでしまっています。

うーむ…,まだまだ勉強不足です>私
YuOさんのご指摘に感謝します。

# 実は,YuOさんの登場をとても期待してました (^^;


この投稿にコメントする

削除パスワード

No.21314

Re:関数からchar型の値をリターンで
投稿者---さい(2005/06/10 00:54:13)


説明、アドバイスありがとうございます。
まだまだ勉強不足です。

>ただし,元投稿では自動記憶域期間をもつオブジェクトへのポインタを返していますから,
>mainでは既に死んでしまっています。
とは、mailでは、受け取れる領域がないということでしょうか。
returnした時点で死んでいるということでしょうか。

mainで受け取れる領域を用意しておく必要があるということですか。


以下のようなことでしょうか。

pre>main()
{
char *p ;
cahr tmp[64] ;
p = tmp ;
p = sub() ;
}

main()
{
char *p ;
p = malloc(64) ;
p = sub() ;
}

main()
{
char p[64] ;
strcpy(p,sub()) ;
}</pre>


コンパイルで、warningがてていますが、動きますし、値も返却されていますが
何故、動いているのでしょうか。
初歩的なことですみません。



この投稿にコメントする

削除パスワード

No.21316

Re:関数からchar型の値をリターンで
投稿者---si(2005/06/10 01:22:12)


このスレッド、大変、勉強になります。

さい さんのお使いのgccのバージョンは
たまたま(かどうかは分かりませんが)動く様な実装になっているけど、gcc4に変えると動かなくなるのですかね

質問への、私の回答
char *sub()
{
   static char str[] = {"1234567890"} ;
    return(str) ;
}



この投稿にコメントする

削除パスワード

No.21318

Re:関数からchar型の値をリターンで
投稿者---RAPT(2005/06/10 01:42:10)


static char str[] = {"1234567890"};
は配列領域 str[11] を確保し、"1234567890"(終端nul)で初期化。
(値の書き換えは可能)

static char *str = "1234567890";
は文字リテラル "1234567890" へのポインタ。
(値の書き換えは不可能)

となります。参考になりますか?




この投稿にコメントする

削除パスワード

No.21322

Re:関数からchar型の値をリターンで
投稿者---Blue(2005/06/10 08:44:55)


>mainで受け取れる領域を用意しておく必要があるということですか。
だから、関数subの方が問題であってmainは問題ではないのです。

文字リテラルの"1234567890"は
YuOさんのおっしゃっているように
>文字列リテラルであれば,確かに静的記憶域期間をもっていますから,
>当然mainでも生存しています。
ですが、
str[11]のような自動記憶域期間をもつオブジェクトはこの関数subを
ぬけると、領域を保持しません。

# ちゃんとレスを読めば理解できるはずなんですが。。。

>コンパイルで、warningがてていますが、動きますし、値も返却されていますが
>何故、動いているのでしょうか。
たまたまでしょう。
本来なくなっている領域を指すポインタを参照しているので、やってはいけないかと。



この投稿にコメントする

削除パスワード

No.21323

Re:関数からchar型の値をリターンで
投稿者---さい(2005/06/10 13:54:03)


すみません。

書いてあることが理解できない自分が恥ずかしいです。

関数subで確保している領域が、関数subを抜けると領域が
なくなるので、アドレスを返そうとしてもアドレスがない
わけですから参照ができないと言うことですね。

static と宣言することにより、メモリ上に固定的に確保
されるので、関数が終了したとしても存在するので、参照
することができるということですね。



この投稿にコメントする

削除パスワード

No.21324

Re:関数からchar型の値をリターンで
投稿者---shu(2005/06/10 15:52:22)


記憶クラス


この投稿にコメントする

削除パスワード

No.21329

Re:関数からchar型の値をリターンで
投稿者---RiSK(2005/06/10 22:34:38)


細かいところ(用語とか)は怪しいですが OK だと思います。


この投稿にコメントする

削除パスワード

No.21337

Re:関数からchar型の値をリターンで
投稿者---さい(2005/06/11 10:42:35)


スコープというのは「識別子」が有効である範囲のことです。
「オブジェクト」が有効である範囲(記憶域期間)とは異なります。
この二つは全く別物ですのでちゃんと区別して下さい。
文字列リテラルは自動的に静的記憶域をもつはず。

混同しているのですが、同違うのでしょうか。


この投稿にコメントする

削除パスワード

No.21338

Re:関数からchar型の値をリターンで
投稿者---si(2005/06/11 11:31:29)


私は、掲示プログラムでいうと

>スコープというのは「識別子」が有効である範囲のことです。

ー>変数strの見える範囲

>「オブジェクト」が有効である範囲(記憶域期間)とは異なります。

ー>変数strが指すところの、オブジェクト 文字型配列”01234567890"の生存?期間

と解釈しておりますが。


この投稿にコメントする

削除パスワード

No.21339

Re:関数からchar型の値をリターンで
投稿者---RiSK(2005/06/11 13:07:22)


>混同しているのですが、同違うのでしょうか。
/*  1 */ int * func(void) {
/*  2 */     static int hoge;
/*  3 */     return &hoge;
/*  4 */ }
/*  5 */ 
/*  6 */ int main(void) {
/*  7 */     int * p = func();
/*  8 */     printf("%d\n", *p);
/*  9 */     hoge; /* コンパイルエラー*/
/* 10 */     return 0;
/* 11 */ }
識別子 hoge の有効範囲は 2-4 行目
よって main 内で hoge が現れてはならない
9 行目はコンパイルエラー

オブジェクト hoge の有効である範囲(記憶域期間)は
初めて 2 行目を通った時からプログラムが終了するまで
よって 7-8 行目は正しい


この投稿にコメントする

削除パスワード

No.21340

Re:関数からchar型の値をリターンで
投稿者---RiSK(2005/06/11 13:20:32)


訂正:

#include <stdio.h> が抜けてました


補足:

func の
>識別子 hoge の有効範囲は 2-4 行目
なので main で別のオブジェクトである hoge を
    int hoge;
と宣言・定義できます。

その場合は
>よって main 内で hoge が現れてはならない
>9 行目はコンパイルエラー
とはなりません。



この投稿にコメントする

削除パスワード

No.21352

Re:関数からchar型の値をリターンで
投稿者---さい(2005/06/11 23:56:08)


解説、説明ありがとうございます。
このスレッド、大変、勉強になります。



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧