C言語関係掲示板

過去ログ

No.618.コマンドライン引数のメモリの使われ方について

[戻る] [ホームページ]
No.5997

コマンドライン引数のメモリの使われ方について
投稿者---伊藤(2003/04/27 21:42:00)


C言語を勉強し始めたばかりの者です。
メモリの使われ方について、ご教示頂けませんでしょうか。

まず、前提知識が間違っていたら仕方がないのでそれを述べたいと
おもいます。以下の解釈をしております。

・関数内で自動変数が宣言されると、その変数はメモリのスタック
 領域へ格納され、スコープはその関数内のみとなる。

・文字列定数や、動的変数、外部変数が宣言されると、メモリの静的
 領域へ格納され、スコープは初期化がされてからプログラムが終了
 するまでとなる。


そこで、疑問が湧きました。

以下のようにコマンドライン引数をmain関数で受ける場合、

main(int argc, char *argv[])

コマンドラインで入力された文字列定数は静的領域へ格納され、
argc,*argv[]はスタック領域へ格納される、という考えで
正しいでしょうか。

以上

No.6000

Re:コマンドライン引数のメモリの使われ方について
投稿者---かずま(2003/04/27 22:41:30)


> ・関数内で自動変数が宣言されると、その変数はメモリのスタック
>  領域へ格納され、スコープはその関数内のみとなる。
>
> ・文字列定数や、動的変数、外部変数が宣言されると、メモリの静的
>  領域へ格納され、スコープは初期化がされてからプログラムが終了
>  するまでとなる。

オブジェクトの寿命と、識別子(変数名)のスコープ(通用範囲)をごっちゃに
されていますね。

オブジェクトとは、メモリ上に確保された領域で、型が指定されているもの
です。オブジェクトは、メモリ上に値を持ち、それを操作する命令がアドレス
や型を意識しています。

変数名は、オブジェクトに付けられた名前です。
スコープは、その変数名が見えるかどうかということです。

自動変数の変数名のスコープは、ソースプログラムでその関数内だけです。
自動変数はオブジェクトであり、そのの寿命は、実行時に、関数に入ったとき
から、戻るときまでです。他の関数を呼び出して、関数を出てもオブジェクト
は存在し続けます。スタックによる実装が適していますが、規格でそう決まって
いるわけではありません。

文字列定数は、正式には文字列リテラルといって、これはオブジェクトですが、
名前がないので、スコープはありません。オブジェクトの寿命はプログラムの
開始から終了までです。静的なデータ領域に確保され、書き換え可能な実装も
ありますが、リードオンリーなコード領域に確保される実装もあります。

動的変数は、malloc で確保したメモリ上の領域ですが、その領域には名前が
ないので、スコープはありません。その領域を指すポインタによって、アドレス
と型が指定され、オブジェクトになります。寿命は、free を実行するまでです。
静的なデータ領域の場合もありますし、それとは別のヒープ領域をとる実装も
考えられます。

外部変数の変数名のスコープは、その宣言された場所から、ファイルの終わり
までです。外部変数はオブジェクトであり、その寿命はプログラム開始から、
プログラムの終了までです。静的なデータ領域にとられるのが普通でしょう。


> main(int argc, char *argv[])
>
> コマンドラインで入力された文字列定数は静的領域へ格納され、
> argc,*argv[]はスタック領域へ格納される、という考えで
> 正しいでしょうか。

argc と argv は、スタック領域ですが、文字列がどこに確保されるか
は、実装依存です。次のプログラムを試してみてください。
#include <stdio.h>
#include <stdlib.h>

int g;

int main(int argc, char *argv[])
{
    int a;
    char *p = malloc(16);

    printf("%p: main\n", main);     /* コード領域   */
    printf("%p: 自動変数\n", &a);   /* スタック領域 */
    printf("%p: 文字列リテラル\n", "abc");
    printf("%p: 動的変数\n", p);    /* ヒープ領域   */
    printf("%p: 外部変数\n", &g);   /* データ領域   */
    printf("%p: &argc\n", &argc);
    printf("%p: &argv\n", &argv);
    printf("%p; argv\n", argv);     /* 文字列へのポインタの配列 */
    printf("%p; argv[0]\n", argv[0]); /*  文字列 */
    return 0;
}


No.6079

Re:コマンドライン引数のメモリの使われ方について
投稿者---伊藤(2003/04/30 20:49:31)


かずまさん
ご丁寧な説明、ありがとうございました。

オブジェクトの寿命、識別子、スコープについて、理解できました。

コマンドライン引数から入力された文字列についてですが、私の環境
ではスタック領域に取られていることが、プログラムを実行すること
によって判明しました。


ちなみに、文字列リテラルのお話でもう1点。
int main()
{
  char *p = "ABCD"; /*文字列リテラル宣言*/
  *p = "a";

  return 0;
}

のように、文字列リテラルを変更しようとすると、処理系によっては、
落ちるのですね。
#私の環境では落ちました。

当然ですが、スタック領域に取られたコマンドライン引数の
文字列を変更しても、落ちませんでした。


色々勉強になりました。
ありがとうございました。

以上