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

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

ただいまの
回答率

90.84%

  • C

    3351questions

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

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

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 131

redhat98

score 226

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

char* test(char* p1) {
    p1 = "test";
    return p1;
}

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

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


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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

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

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/31 15:45

    回答ありがとうございます。

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

    キャンセル

  • 2018/05/31 15:46 編集

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

    キャンセル

  • 2018/05/31 15:47

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

    キャンセル

0

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

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

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

// 元のコード
char* test(char* p1) {
    p1 = "test";
    return p1;
}

// こう書いても一緒です
char* test(void) {
    char *p1 = "test";
    return p1;
}

// 更にこれでも一緒です
char* test(void) {
    return "test";
}

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

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


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

これなら大丈夫。

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/31 16:05 編集

    こんにちは
    >char* test(char* p1) {
    > p1 = "test";
    > return p1;
    >}

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

    キャンセル

  • 2018/05/31 16:11

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

    キャンセル

  • 2018/05/31 16:49

    >char* test(void) {
    > static char p[5];
    > strcpy(p, "abc");
    > return p;
    >}
    グローバル?な領域に入れて、値を受け渡すというパターンがあるよ
    ということですね。
    変数pの管理を間違えると、大変なことになりそうですね。

    >ダブルポインタ(char**p1)にして *p1 = "test" とするならともかく
    すいません、ここの意味がわからないです。
    なぜ、ダブルポインタの話が出てくるのですか?

    キャンセル

  • 2018/05/31 16: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*に置き換えて考えてみるとよいでしょう。

    キャンセル

  • 2018/05/31 17:05

    ありがとうございました

    キャンセル

0

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

#include <stdio.h>
#include <unistd.h>

int main(void){
    int i;
    for(i=0; __environ[i]; i++){
        printf("%s\n",__environ[i]);
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.84%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C

    3351questions

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