[初学者向け] C言語　argc, argvとはなんぞや

argc, argv (c言語のメイン関数がとるコマンドライン引数) の勉強のために書いてみました. 
僕と同じ初学者の方で, argc, argvとはなんぞやという人のお役に立てばと思います. 
環境としては、macでVSコード（Visual Studio Code）中心に使っていて, TerminalかiTermを使うこともあります.
プログラミング自体がはじめての方, 「コマンドライン, 引数って何？」という方はよかったらこちらをご覧ください. 

https://qiita.com/uzo/items/a0baabfc612a79ff5c4f

___

## 1. argc, argvとは

#### 1-1. [argc]

 "argument count"の略で, 入力したコマンドライン引数の個数をコンピューターが自動的に数えてくれたものです.
プログラム実行コマンド（デフォルトでは"./a.out"）もコマンドライン引数としてカウントされます. 

```: コマンドライン
 % ./a.out
```

プログラム実行時, コマンドラインにプログラム実行コマンド（"./a.out"）以外の引数を入力しなければ, 引数は実行コマンドのみになるため, 引数の個数は1つだけとなります. そのため, 上のコマンドラインから計測されるargcの値は1になります.

ただし, カウントされるのはプログラム実行コマンドとその後の入力値のみのようです. 
例えば以下のようなコマンドを入力した場合, 上の"user % ./a.out"と同じでargcは1となります. 

```: コマンドライン
 % gcc -Wall -Wextra -Werror command_line_args.c　; time ./a.out
```

(プログラムのメイン関数が認識するコマンドライン引数は"./a.out"のみ. コマンドライン上の他の引数 ("gcc"から"time"まで) はメイン関数への引数としてはカウントされない)

#### 1-2. [argv]
"argument vector"の略で, 入力したコマンドライン引数の入力値（文字）を指します.
argv[0]は実行したプログラム名(デフォルトでは"./a.out").
プログラムファイル名の後に入力した値(文字)がargv[1]以降のコマンドライン引数として扱われます.

```: コマンドライン
 % ./a.out string 12345
```

↑ この場合, "string" -> argv[1],  "12345" -> argv[2]　になる. argcは3.


## 2. コーディング -> プログラム実行

<details><summary><strong>2-1. ファイル作成</strong> (詳細はここをクリック)</summary>

```: コマンドライン
 % touch args.c
```

</details>

__2-2. コーディング__

```c: エディタ
    #include <stdio.h>

    int	main(int argc, char *argv[])
    {
    	printf("argc    = %d\n", argc);
    	printf("argv[0] = %s\n", argv[0]);
    	printf("argv[1] = %s\n", argv[1]);
    	return (0);
    }
```

<details><summary><strong>2-3. コンパイル</strong>　(詳細はここをクリック)</summary>

```: コマンドライン
 % gcc -Wall -Wextra -Werror args.c
```

プログラミング自体がはじめて, 「ファイル作成 -> コンパイル -> プログラム実行をまだやったことない!」 という方は, よかったらこちらをご覧ください.

https://qiita.com/uzo/items/e739340a9a120a50b55d

</details>

__2-4. プログラム実行__

```: コマンドライン
 % ./a.out
```

__2-5. 実行結果__

無事プログラムが実行されると, 以下のように出力されるはずです.

```: ターミナル
       argc    = 1    
       argv[0] = ./a.out
       argv[1] = (null)
```

上記の"% ./a.out"のプログラム実行コマンドラインでは, "./a.out"以外に何も入力してないので, コマンドライン引数は"./a.out"だけとなります.

そのため, コマンドライン引数の個数は1つだけです. ということで, "argc"は1になり, "./a.out"は最初のコマンドライン引数ということで, "argv[0]"となります.

今回のコードでは"argv[1]"もprintf()関数で出力するようにしてますが, 上のコマンドラインでは”./a.out”の後に何も入力されてません. 
そのためargv[1]は入力なしということで, "(null)"（ナル: 無効）と出力されてます.

## 3. コマンドライン引数を追加

#### 3-1. argv[1] = "string"

では, 今度はコマンドライン引数を追加で入力してみましょう.
文字列を意味する"string"を"./a.out"の後ろに半角スペースを置いたあとに入力してみます.
コマンドライン引数はそれぞれ半角スペースで区切られていることで認識されます.

```: コマンドライン
　% ./a.out string
```

最初に載せたコードを使ってコンパイルすると, 結果は以下のようになるはずです.

```: ターミナル
       argc    = 2
       argv[0] = ./a.out
       argv[1] = string
```

今回のコマンドライン引数は"./a.out"と"string"ですから, コマンドライン引数は２つ. そのため, "argc"は2となり, "argv[0]"はさっきと同じ "./a.out". さっきは入力なしで, printf()関数では"(null)"として出力されていた"argv[1]"の値は, 今度は"string"となって出力されました.

#### 3-2. argv[2] = "12345"

ではこんなのはどうでしょうか

```: コマンドライン
 % ./a.out string 12345
```

今度は "./a.out" (スペース) "string" (スペース) "12345"という入力内容です. 結果は以下のようになるはずです.

```: ターミナル
       argc    = 3 
       argv[0] = ./a.out
       argv[1] = string
```
 
3つめのコマンドライン引数"12345"は"argv[2]"として認識されているのですが, "argv[2] = 12345"のように出力されてはいません. これは, 最初に載せたコード内でprintf()関数が出力するように指定したargv[]が, argv[1]までだからです. ただ, 出力はされてないですが、認識はされてるので、"argc"の値は3となってます.

"argv[1]"以降のコマンドライン引数をプリントしたい場合,

```c
    printf("argv[1] = %s\n", argv[1]);
```

の関数をコピペして, "argv[1]"のところの数字を2, 3と変えてあげれば, 他のコマンドライン引数も出力できます.


## 4. スペースも引数の一部として入力したい

また、コマンドライン引数はスペースで区切られると上に書きましたが, スペースも文字列の一部として入力したい場合はスペースを含んだ文字列を" " (ダブルクォーテーション)で囲んであげましょう.

先ほどの

```: コマンドライン
 % ./a.out string 12345
```

を

```: コマンドライン
 % ./a.out "string 12345"
```

としてみてください. 結果は以下のようになるはずです.

```: ターミナル
    argc    = 2
    argv[0] = ./a.out
    argv[1] = string 12345
```

## 5. 安全なコーディングのために

また, コメントで指摘をいただいたので, より安全にプログラムを実行するために下記のようなコードを書いてみました.

```c
#include <stdio.h>

int	main(int argc, char *argv[])
{
	int	i;

	i = 0;
	printf("argc    = %d\n", argc);
	while (i < argc)
	{
		printf("argv[%d] = %s\n", i, argv[i]);
		i++;//または i += 1;
	}
	return (0);
}
```

こうすると, 入力されたコマンドライン引数をすべて出力しつつ, 引数の数を超えてprintf()関数がargvを出力しようとするのを防げます.
先ほどの

```: コマンドライン
 % ./a.out string 12345
```

をコンパイル後に実行すると, 結果は以下のようになるはずです.

```: ターミナル
    argc    = 3
    argv[0] = ./a.out
    argv[1] = string
    argv[2] = 12345
```