質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

4047閲覧

getenv関数でchar*の戻り値が返せる理由

redhat98

総合スコア236

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2018/05/31 06:33

タイトルにも書いてありますが、c言語でgetenv関数でcharが返せる理由が知りたいです。
今までchar
を戻り値に返したいときは、スコープの関係で

C

1char* test(char* p1) { 2 p1 = "test"; 3 return p1; 4}

としていました.
しかし、getenv()を使ってみたところ

c

1 char *env_name = "HOME"; 2 char *env = getenv(env_name); 3 printf("%s", env_name);

とできました。
getenv()はなぜ、char*をreturnできるのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

C言語でポインタを返す場合、どこかに実体を確保しないといけませんが、「static変数」や「mallocで確保した領域」であれば、(それぞれ使い方には要注意ですが)与えていないポインタを返すことができます。

そして、getenvについては、一例としてLinuxのmanを見てみると、

通常の実装では、 getenv() は環境リスト内の文字列へのポインターを返す。 呼び出し元はこの文字列を変更しないように注意しなければならない。 この文字列を変更すると、そのプロセスの環境を変化させることになるからである。

とあるように、環境変数を保存する領域へのポインタを返している、とのことです。

投稿2018/05/31 06:39

編集2018/05/31 06:46
maisumakun

総合スコア145121

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

redhat98

2018/05/31 06:45

回答ありがとうございます。 通常のパターンはchar*を返しちゃダメだけど、getenvの場合はOSが確保しているから特に問題ないということでしょうか?
maisumakun

2018/05/31 06:47 編集

「char*を返しちゃダメ」なんていうルールはありません。あくまで「ローカルな自動変数へのポインタ」を返せないだけです。
redhat98

2018/05/31 06:47

わかりました。 ありがとうございます。
guest

0

Unix/Linuxでは環境変数は、グローバル変数に格納されています。getenvはその中を検索してポインタを返します。

C

1#include <stdio.h> 2#include <unistd.h> 3 4int main(void){ 5 int i; 6 for(i=0; __environ[i]; i++){ 7 printf("%s\n",__environ[i]); 8 } 9}

投稿2018/05/31 07:17

otn

総合スコア84423

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー決まっちゃっいましたけど、書きかけたので投稿しておきます。

maisumakunさんの回答どおりでgetenvについては付け足すところはありません。

そもそも最初に書いているコードが間違っています。

c

1// 元のコード 2char* test(char* p1) { 3 p1 = "test"; 4 return p1; 5} 6 7// こう書いても一緒です 8char* test(void) { 9 char *p1 = "test"; 10 return p1; 11} 12 13// 更にこれでも一緒です 14char* test(void) { 15 return "test"; 16}

char*(に限らずアドレス)を返してはいけないのはこういうパターンですね。

c

1char* test(void) { 2 char p[5]; 3 strcpy(p, "abc"); 4 return p; 5}

pはローカル変数なので関数を抜けた時点で値の保障はできません。

これなら大丈夫。

c

1char* test(void) { 2 static char p[5]; 3 strcpy(p, "abc"); 4 return p; 5}

投稿2018/05/31 06:55

ttyp03

総合スコア16996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

redhat98

2018/05/31 07:10 編集

こんにちは >char* test(char* p1) { > p1 = "test"; > return p1; >} "test"という文字列のスコープは、ローカル変数と同じだよ。 だから、"test" って文字列は代入でセットするんじゃなくて、 strcpy()でセットしましょう!!って事を言いたいのでしょうか?
ttyp03

2018/05/31 07:11

違います。 p1 = "test" って、p1に文字列"test"を入れているわけではないですよ。 "test"というリテラル文字列が格納されている場所のアドレス値をp1に入れているだけですよ。 引数がポインタになってますけど、ダブルポインタ(char**p1)にして *p1 = "test" とするならともかく、今の書き方だとローカル変数を宣言して使うのと変わりはありません。 結局のところ"test"が格納されているメモリ上のアドレスを返すだけなので、return "test" としても一緒です。
redhat98

2018/05/31 07:49

>char* test(void) { > static char p[5]; > strcpy(p, "abc"); > return p; >} グローバル?な領域に入れて、値を受け渡すというパターンがあるよ ということですね。 変数pの管理を間違えると、大変なことになりそうですね。 >ダブルポインタ(char**p1)にして *p1 = "test" とするならともかく すいません、ここの意味がわからないです。 なぜ、ダブルポインタの話が出てくるのですか?
ttyp03

2018/05/31 07:58

>なぜ、ダブルポインタの話が出てくるのですか? ポインタの引数に値を代入するということは、引数の値を変更して呼び出し元に返したいということですよね。 なのでダブルポインタにすれば、戻り値で返さずともできますよということです。 ポインタの引数だから話がややこしくなりますが、通常のint型なんかで考えてみればわかりやすいでしょう。 int test(int i){  i = 5;  return i; } これって意味ないですよね。 これと一緒だから。 int test(void){  int i = 5;  return i; } つまりこれと一緒。 int test(void){  return 5; } 戻り値で返さないならこう書くこともできますよの例。 void test(int *p){  *p = 5; } int型を今回のchar*に置き換えて考えてみるとよいでしょう。
redhat98

2018/05/31 08:05

ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問