このページでは、C言語での「コマンドライン引数の扱い方」について解説していきます!
例えば下記は、コマンドライン引数を扱うプログラムのソースコードの一例で、プログラムに渡された2つの引数の足し算結果を表示するものになります。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("下記の引数を指定して実行してください\n");
printf(" 第1引数:足し算を行う1つ目の値\n");
printf(" 第2引数:足し算を行う2つ目の値\n");
printf("実行例:%s 100 200\n", argv[0]);
return 0;
}
int num1 = atoi(argv[1]);
int num2 = atoi(argv[2]);
int sum = num1 + num2;
printf("%d + %d = %d\n", num1, num2, sum);
return 0;
}
こんな感じで、コマンドライン引数を利用すれば、プログラム実行時に引数を指定し、指定した引数に応じて動作を切り替えるようなプログラムを作成することができるようになります。
以降では、まずコマンドライン引数がどのようなものであるかについて解説し、その後C言語プログラムでのコマンドライン引数の扱い方やコマンドライン引数を扱うプログラム作成時の注意点・ポイント等について解説していきます!
Contents
コマンドライン引数とは
まずコマンドライン引数とは、前述でも少し触れましたが、「プログラムに渡す引数」のことを言います。
C言語の場合は main
関数に渡す引数と考えて良いと思います(最初に実行される関数に渡される引数)。
このコマンドライン引数を利用することで、プログラム実行者はプログラムに引数を渡し、それに応じてプログラムの動作を切り替えるようなことができるようになります。
C言語ユーザーにとって分かりやすい例は gcc
コマンドですかね!
gcc
コマンドでは、例えば下記のようにコマンドを実行すれば、main.c
がコンパイルされ、実行可能ファイルとしては main.exe
が作成されることになります。
gcc main.c -o main.exe
その一方で、下記のようにコマンドを実行すれば、sub.c
がコンパイルされ、実行可能ファイルとしては sub.exe
が作成されることになります。
gcc sub.c -o sub.exe
これらの gcc
に続く文字列が引数であり、この引数によって gcc
実行者はコンパイルするファイルや生成する実行可能ファイルを変更することが出来ます。
また、単にファイルを変更するだけでなく、下記のようなコマンドにより gcc
のヘルプを表示するような事も可能です。
gcc -help
要は、gcc
利用者は引数の指定によって gcc
の動作を切り替えることが出来ます。
コマンドライン引数を利用すれば、この gcc
のような引数に応じた動作の切り替えを、あなた自身が作成したプログラムでも実現することができるようになります。また、これにより、gcc
のように引数の指定に応じて1つのプログラムで様々な動作を実現することができるようになります。
コマンドライン引数の扱い方
大体コマンドライン引数がどのようなものであるかはイメージできたでしょうか?
次は、実際にコマンドライン引数を扱うための方法を解説していきます。
C言語プログラムでコマンドライン引数を扱うためには、下記の3つのことが必要になります。
- コマンドライン引数を指定してプログラムを実行する
- コマンドライン引数を受け取るようにする
- 受け取ったコマンドライン引数を利用して処理を行う
1. に関してはプログラム実行時に必要なことであり、プログラム利用者が行う必要のある手順となります。また、2. と 3. に関してはプログラム作成時に必要なことであり、プログラム開発者が行う必要のある手順となります。
スポンサーリンク
コマンドライン引数を指定してプログラムを実行する
まず、コマンドライン引数を扱うためには、プログラム実行時にプログラムに渡すコマンドライン引数を指定するようにする必要があります。その方法について解説していきます。
コマンドライン引数の指定方法
コマンドライン引数を指定しない場合は、単に実行したい「プログラムのファイルパス」のみを指定してプログラムを実行すると思います。
それに対してコマンドライン引数を指定する場合は、下記のように「プログラムのファイルパス」の後ろ側に引数を指定してプログラムを実行します(下記は引数を3つ指定する例です)。プログラムのファイルパスや各引数の間は「スペース」で区切る必要があります。
プログラムのファイルパス 第1引数 第2引数 第3引数
例えば、実行したいプログラムのファイルパスが ./main.exe
で、その main.exe
実行時に "add"
と "100"
と "200"
の引数を指定したい場合は下記のようにコマンドを実行します。
./main.exe add 100 200
これにより、下記の4つが main.exe
(の main
関数)に渡されることになります。
"./main.exe"
"add"
"100"
"200"
コマンドライン引数の注意点
ここで、コマンドライン引数に関する注意点を2つ挙げておきます。
まず1つ目は、プログラムに渡されるコマンドライン引数には「プログラムのファイルパス」が含まれます。上記の "./main.exe"
がその「プログラムのファイルパス」となります。
つまり、”本当の意味での引数” + “プログラムのファイルパス” がプログラムに渡されることになります。
実行するプログラムのファイルが PATH に設定されたフォルダに置かれている場合、プログラムのファイル名のみでプログラムを実行することが可能です
例えば前述の gcc
コマンドもプログラムのファイル名のみでプログラムを実行することが可能で、それと同じ話です
このようにファイルパスではなく “プログラムのファイル名” でプログラムを実行した場合、 “プログラムのファイル名” がプログラムに渡されることになります
また、全環境で “プログラムのファイルパス” や “プログラムのファイル名” が渡されることを確認したわけではありませんので、環境によってはもっと異なる文字列が格納されている可能性もあります
このページでは “プログラムのファイルパス” が渡されることを前提に解説を進めますが、上記の点に関しては注意してください
2つ目は、プログラムに渡されるコマンドライン引数は全て「文字列」として扱われます(終端が '\0'
である char
型の配列)。従って、100
や 200
といった数値を引数で指定したつもりであっても、受け取り側のプログラムでは "100"
や "200"
といった文字列を受け取ることになります。
こういった注意点はプログラム実行時にはそこまで意識する必要はありませんが、コマンドライン引数を受け取る側のプログラムを作成する際には注意が必要です。この辺りは、次の コマンドライン引数を受け取るようにする 以降で解説していきます。
特殊文字を含めた引数の指定の仕方
また、コマンドライン引数の指定についていくつか補足も加えておきます。
まず、コマンドライン引数では「スペース」によって引数が区切られることになります。そのため、スペースを含む文字列を引数で指定した場合、普通に指定してしまうと異なる引数であると判断され、異なる引数としてプログラムに渡されてしまいます。
スペースを含む文字列を引数で指定したい場合は、引数をダブルクォーテーションマークで囲む必要があるので注意してください。
./main.exe "my name is daeu"
これにより、スペースがあったとしても、ダブルクォーテーションマークで囲まれた部分が1つの引数としてプログラムに渡されることになります。
また、もし引数にダブルクォーテーションマークを含ませたい場合は、エスケープシーケンス \
を利用する必要があります。
./main.exe "my name is \"daeu\""
コマンドライン以外からのプログラム実行時
ここまではコマンドライン(Windows のコマンドプロンプトや Mac や Linux のターミナル)からプログラムを実行する際の「コマンドライン引数の指定方法」について解説しましたが、コマンドラインからはプログラムを実行しないという方もおられるかもしれません。
例えば VSCode(Visual Studio Code)等の開発環境からプログラムを実行する方も多いのではないかと思います。もちろんコマンドライン引数は、こういった開発環境からプログラムを実行する際にも指定することが可能です。
このページでは、後述の コマンドライン引数を VSCode で指定する方法 で、VSCode からプログラムを実行する際にコマンドライン引数を指定する方法についても解説したいと思います。
コマンドライン引数を受け取るようにする
ここからは、コマンドライン引数を扱うプログラムの作り方について解説していきます。
このためには、まずプログラム(main
関数)が引数を受け取れるようにする必要があります。
通常、プログラムで引数を受け取る必要がない場合、下記のように main
関数の引数を void
と記述すると思います。
int main(void) {
/* main関数の処理 */
}
それに対してコマンドライン引数を受け取る際には、下記のように main
関数の引数に argc
と argv
を指定する必要があります。
int main(int argc, char *argv[]) {
/* main関数の処理 */
}
引数名は変更しても問題ありません。ですが、argc
と argv
が最も一般的で分かりやすいと思います。
また、第1引数の型は int
、第2引数の型は char *
の配列である必要があります。この順番は間違わないように注意してください。
第2引数は char *argv[]
ではなく char **argv
のようにポインタのポインタとして表現しても良いです(同じ意味のものとして扱われるため)
引数 argc
と argv
の意味
引数 argc
と argv
の意味は下記のようになります。
argc
:受け取ったコマンドライン引数の数argv
:受け取ったコマンドライン引数を指すポインタの配列
特に引数 argv
の型が char *argv[]
となっていてややこしいですが、要は argv
は文字列を指すポインタの配列です。
まず、プログラムが受け取ったコマンドライン引数は、メモリ上のどこかに文字列として格納されています。
そして argv
は、そのメモリ上に格納された「文字列の先頭を指すポインタ」の配列になります。
より具体的には、受け取ったコマンドライン引数の個数を 0
からカウントするとすれば、argv[i]
には第 i
個目のコマンドライン引数の文字列の先頭アドレスが格納されています。つまり、argv[i]
は第 i
個目のコマンドライン引数の文字列の先頭を指します。
ただし、前述の通り、プログラムに渡されるコマンドライン引数には「プログラムのファイルパス」が含まれます。より具体的には、argv[0]
はプログラムのファイルパスを指すポインタとなります。
そのため、”本当の意味での引数” は argv[1]
以降が指すことになるので注意してください。
また、これも前述の通り、argv[i]
には第 i
個目のコマンドライン引数の「文字列の先頭アドレス」が格納されています。
例えば printf
で文字列を表示する場合、表示したい文字列の先頭アドレスを引数として指定すると思います(配列の場合、配列の変数名のみを指定すれば、その配列の先頭アドレスを指定することになる)。
char str[] = "aiueo";
printf("%s\n", str); /* 文字列の先頭アドレスを指定 */
argv[i]
にも文字列の先頭アドレスが格納されていますので、同様に printf
の引数に argv[i]
を指定すれば、文字列として表示することが可能です。
printf("%s\n", argv[i]); /* 文字列の先頭アドレスを指定 */
要は、argv
はポインタの配列で難しく思えますが、argv[i]
のように1つの1つの要素に注目すれば、通常の文字列の配列を扱う時と同様にして文字列の先頭アドレスの指定を行うことが出来ます。
ですので、例えば下記のように strcpy
関数を実行すれば、第 i
個目のコマンドライン引数を配列 str
にコピーするようなこともできます。
char str[256];
strcpy(str, argv[i]);
さらに、main
関数が受け取ったコマンドライン引数の数は引数 argc
として渡されますので、argv[0]
から argv[argc - 1]
に各コマンドライン引数の文字列の先頭を指すポインタが格納されていることになります(argc
は、前述の「プログラムのファイルパス」も含めた個数となります)。
ですので、下記のようにループを組み、その中で argv
の各要素を表示するようにしてやれば、プログラム(main
関数)が受け取ったコマンドライン引数を全て表示することが出来ることになります。
#include <stdio.h>
int main(int argc, char *argv[]) {
for (int i = 0; i < argc; i++) {
/* 第i個目のコマンドライン引数を表示 */
printf("%s\n", argv[i]);
}
return 0;
}
例えば、上記のソースコードをコンパイルして作成したプログラムのパスが ./main.exe
であるとすれば、下記のように main.exe
を実行した場合、
./main.exe add 100 200
下記が表示されることになります。
./main.exe add 100 200
上記では単に表示を行なっているだけですが、プログラム実行時に指定されたコマンドライン引数がプログラムに渡され、そのコマンドライン引数を main
関数が受け取っていることは確認できると思います。
受け取ったコマンドライン引数を利用して処理を行う
コマンドライン引数を main
関数が受け取れるようになれば、あとはコマンドライン引数を使用して処理を行うようにソースコードを実装していけば良いだけです。
基本的には、通常の引数を受け取る関数を作成するときと同様にして実装を行えば良いです。
ただし、コマンドライン引数を指定してプログラムを実行する や コマンドライン引数を受け取るようにする で解説したことも含め、下記の3点には注意する必要があります。
- 本当の意味での引数は
argv[1]
以降に存在する - コマンドライン引数は全て文字列として扱われる
- 引数が足りない状態で実行される可能性がある
本当の意味での引数は argv[1]
以降に存在する
まず、main
関数が受け取るコマンドライン引数の1つ目、すなわち argv[0]
は「プログラムのファイルパス」となります。
つまり、実際にユーザーがプログラム実行時に指定する “本当の意味での引数” は argv[1]
以降に存在することになります。argv[0]
にユーザーが指定した引数が存在すると考えて実装してしまうと、指定された引数とプログラムの処理とで話が合わなくなってしまうので注意してください。
コマンドライン引数は全て文字列として扱われる
また、コマンドライン引数は全て文字列として扱われます。ですので、コマンドライン引数を数値として扱いたいのであれば、main
関数が受け取った引数を文字列から数値に変換する必要があります。
この文字列から数値への変換は、atoi
や atof
といった標準ライブラリ関数を利用することで簡単に行うことが出来ますし、strtol
や strtod
等を利用すれば、指定されたコマンドライン引数が数値でない場合のエラー処理なども行うことが可能です。
この辺りの関数については下記ページで解説していますので、詳しく知りたいかたはこちらを参考にしていただければと思います。
【C言語】文字列を数値に変換する方法(atoi・strtol など)例えば、argv[1]
が指す文字列を atoi
を用いて整数に変換するのであれば、atoi(argv[1])
を実行するだけで返却値として変換後の整数を得ることが出来ます。
引数が足りない状態で実行される可能性がある
また、通常の関数では、(可変長引数等を利用しない場合等を除いて)必ず必要な引数が渡される状態で実行されます。
もし引数が足りない状態で関数が実行される場合はコンパイルエラーになるはずです。
その一方で、コマンドライン引数の場合は引数の数が足りない、つまりプログラムが想定しているコマンドライン引数の数よりも argc
が少ない状態でもプログラムの実行は可能です。
例えば、そのプログラム利用者が指定必要な引数の数を知らなかったり、たとえ知っていたとしても引数を指定し忘れて引数が足りない状態でプログラムが実行されるようなことがよく起こります。
そのような「引数が足りない状態」でプログラムを通常通り動作させてしまうと、足りない引数を利用して処理が実行されてしまうため基本的にプログラムは正常に動作できません。最悪不正アクセスなどが発生してプログラムが落ちるようなこともあり得ます。
そういったことが起こらないように、プログラムで想定している分の引数が渡されているかをチェックし、足りない場合はエラー終了する等の対処を行うことが必要になります。さらに、そのエラー終了時に “引数が足りない” ことを printf
関数等でユーザーに示すようにすることで、より使いやすいプログラムに仕立てることが出来ます。
具体的には、渡された引数の数は argc
から判断できますので、argc
に想定した値が格納されているかどうかを判断し、argc
に想定していない値が格納されていない場合はエラー終了するようにすれば良いです。
もちろん必ずエラー終了する必要があるというわけではなく、足りない引数をデフォルトの設定値等で代替して処理を継続するような作りにしても良いです。が、一番楽なのは引数が足りない場合にエラー終了してやることだとは思います。
コマンドライン引数を利用するプログラム例
ここまで解説してきた注意点を踏まえて作成した「コマンドライン引数を利用するプログラム例」のソースコードは下記となります。
#include <stdio.h> /* printf */
#include <stdlib.h> /* atoi */
#include <string.h> /* strcmp */
int main(int argc, char *argv[]) {
if (argc != 4) {
/* コマンドライン引数の数が合わない場合 */
printf("下記の引数を指定して実行してください\n");
printf(" 第1引数:add or sub\n");
printf(" 第2引数:1つ目の数値\n");
printf(" 第3引数:2つ目の数値\n");
printf("実行例:%s add 100 200\n", argv[0]);
return 0;
}
if (strcmp(argv[1], "add") == 0) {
/* 計算に用いる引数を数値に変換 */
int num1 = atoi(argv[2]);
int num2 = atoi(argv[3]);
/* 第1引数で指定された文字列に応じた計算を実行 */
printf("%d + %d = %d\n", num1, num2, num1 + num2);
} else if (strcmp(argv[1], "sub") == 0) {
/* 計算に用いる引数を数値に変換 */
int num1 = atoi(argv[2]);
int num2 = atoi(argv[3]);
/* 第1引数で指定された文字列に応じた計算を実行 */
printf("%d - %d = %d\n", num1, num2, num1 - num2);
} else {
/* 第1引数で指定された文字列が想定したものでない場合 */
printf("第1引数には add or sub を指定してください\n");
}
return 0;
}
上記は、コマンドライン引数に応じて下記のような動作を行うプログラムのソースコード例となります。
- 第1引数が
add
の場合:第2引数と第3引数で指定された値の足し算結果を表示 - 第1引数が
sub
の場合:第2引数と第3引数で指定された値の引き算結果を表示
第1引数で指定される文字列に応じて実行する計算を切り替える必要があるため、第1引数の文字列と "add"
および "sub"
とが一致するかどうかを strcmp
関数を利用して判断するようにしています。
前述の通り、コマンドライン引数の第1引数は argv[0]
ではなく argv[1]
のポインタが指しているため、strcmp
関数の第1引数に指定するのは argv[1]
である必要があります。
また、第2引数と第3引数は計算を実行する対象となる引数となりますので、数値として扱う必要があります。前述の通り、コマンドライン引数は全て文字列として扱われますので、事前に atoi
関数を利用して文字列を数値に変換してから実際の計算を行うようにしています。
上記ソースコードから生成した実行可能ファイルのパスを ./main.exe
とすれば、下記のコマンドでプログラムを実行することで足し算が実行され、
./main.exe add 100 200 100 + 200 = 300
下記のコマンドでプログラムを実行することで引き算が実行されることが確認できると思います。
./main.exe sub 100 200 100 - 200 = -100
さらに、コマンドライン引数の数が足りない場合は下記を表示してプログラムが即座に終了するようにしています。
./main.exe 100 200 下記の引数を指定して実行してください 第1引数:add or sub 第2引数:1つ目の数値 第3引数:2つ目の数値 実行例:./main.exe add 100 200
スポンサーリンク
コマンドライン引数利用時の注意点・ポイント
続いて、コマンドライン引数を扱うプログラム開発時の注意点とポイントについて説明していきます。
コマンドライン引数として渡されるデータに注意する
ここまでにも何度も説明した通り、main
関数が受け取る引数には、”本当の意味での引数” だけでなく、プログラムのファイルパスも含まれます。”本当の意味での引数” を利用した処理を実装する際には、argv[0]
ではなく argv[1]
以降の引数を利用する必要があります。
また、main
関数の引数 argv
は「コマンドライン引数の文字列の先頭を指すポインタ」の配列であり、コマンドライン引数は全て文字列として扱われます。
数値として扱いたい場合は、事前に文字列を数値に変換する必要があります。
コマンドライン引数の数をチェックするようにする
引数が足りない状態で実行される可能性がある で説明したように、想定した数のコマンドライン引数を必ずプログラム利用者が指定してくれるとは限りませんので、引数が足りない場合にはエラー終了するように対処しておいたほうが良いです。
スポンサーリンク
プログラムの実行方法を提示する
また、コマンドライン引数を受け取らないプログラムに比べ、プログラム実行時に引数を指定する必要がある分プログラムの実行の仕方が複雑になります。
皆さんも何らかのコマンド実行時に、引数が足りなくてうまくコマンドが実行できなかったり、コマンドに指定すべき引数が分からなくて困ったりした経験があるのではないでしょうか?
要は、あなたが作成したプログラムにおいても、そのような状況が発生する可能性があるということです。
作成したプログラムを “あなたしか使用しない” というのであればそこまで気にする必要はないですが、特にコマンドライン引数を受け取るプログラムを他の人に利用してもらうような場合は、プログラムに指定する必要のある引数の情報をプログラム利用者に対して提示してあげたほうが良いです。
もちろん Word やテキストファイルでマニュアルを作成しても良いですが、そこまで引数が複雑でないのであれば、引数の数が足りない場合のエラー処理時に「必要な引数の数」「各引数の意味合い」「プログラム実行時のコマンド例」などを printf
等で表示してあげるだけでも、十分プログラム利用者に使い方を伝えることができると思います。
実際に コマンドライン引数を利用するプログラム例 でもコマンドライン引数が足りない時のエラー処理時にプログラムの使い方を表示するようにしていますので、こちらも参考にしていただければと思います。
コマンドライン引数を VSCode で指定する方法
最後に、コマンドライン以外からプログラムを実行する場合のコマンドライン引数の指定方法の例として、VSCode でプログラムを実行する場合のコマンドライン引数の指定方法について紹介しておきます。
VSCode の C/C++ プラグインや CodeLLDB プラグインを利用してC言語プログラムの実行を行なっている場合、launch.json
の "args"
を変更することでプログラムに対して引数を渡すことができるようになります。
具体的には、まず launch.json
を開きます。この launch.json
にはプログラム実行時の設定が記述されています。中身の文言等は人によって異なるので注意してください。
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "c_debug",
"type": "lldb",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"cwd": "${fileDirname}",
"preLaunchTask": "c_build",
},
]
}
さらに、launch.json
の "name"
や "type"
の行と同じ階層に、下記のように "args"
の行を追加します(最後の行に追加する場合、前の行の行末へのコンマのつけ忘れにご注意ください)。
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "c_debug",
"type": "lldb",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"cwd": "${fileDirname}",
"preLaunchTask": "c_build",
"args" : []
},
]
}
複数の実行構成を lauch.json
に記述している場合は、使用している実行構成に対して "args"
の行の追加が必要になります。
さらに、"args"
の後ろ側の [ ]
内にプログラムに渡したい引数を指定します。各引数はコンマ(,
)で区切ります。各引数はダブルクォーテーションマークで囲う形で指定する方が無難だと思います(CodeLLDB の場合は囲わないとエラーになるはず)。
例えばプログラムに add
と 100
と 200
の引数を渡したい場合は下記のように記述します。
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "c_debug",
"type": "lldb",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"cwd": "${fileDirname}",
"preLaunchTask": "c_build",
"args" : ["add", "100", "200"]
},
]
}
これにより、プログラム実行時に "args"
の後ろ側の [ ]
内で指定した引数がプログラムの main
関数に渡されるようになります。
要はコマンドラインで下記のコマンドを実行した場合と同じようにプログラムに引数が渡されるようになります。
プログラムのファイルパス "add" "100" "200"
あとは通常通り VSCode からプログラムを実行してやれば、コマンドライン引数を受け取った状態でプログラムを動作させることが出来ます。
ちょっと面倒ですが、コマンドライン引数を受け取るプログラムを一行一行止めながらステップ実行したいような場合は便利だと思いますので、是非参考にしていただければと思います。
そもそも VSCode の使い方や launch.json
の追加の仕方、VSCode でのC言語プログラムのデバッグ方法などをご存知ない方は、Mac 向けではありますが下記ページで解説していますので参考にしていただければと思います。
まとめ
このページでは、C言語での「コマンドライン引数の扱い方」について解説しました!
コマンドライン引数を受け取るようにし、さらにコマンドライン引数に応じた動作を実装することで、引数の指定によって1つのプログラムで様々な動作を実現することが可能です。
ただ、コマンドライン引数を受け取るようにすることで若干プログラムの実行方法が複雑になります。プログラム利用者が使い方を迷わないよう、受け取ったコマンドライン引数の数が足りない場合等に使い方を提示するようにしておくのが良いと思います!
オススメの参考書(PR)
C言語学習中だけど分からないことが多くて挫折しそう...という方には、下記の「スッキリわかるC言語入門」がオススメです!
まず学習を進める上で、参考書は2冊持っておくことをオススメします。この理由は下記の2つです。
- 参考書によって、解説の仕方は異なる
- 読み手によって、理解しやすい解説の仕方は異なる
ある人の説明聞いても理解できなかったけど、他の人からちょっと違った観点での説明を聞いて「あー、そういうことね!」って簡単に理解できた経験をお持ちの方も多いのではないでしょうか?
それと同じで、1冊の参考書を読んで理解できない事も、他の参考書とは異なる内容の解説を読むことで理解できる可能性があります。
なので、参考書は2冊持っておいた方が学習時に挫折しにくいというのが私の考えです。
特に上記の「スッキリわかるC言語入門」は、他の参考書とは違った切り口での解説が豊富で、他の参考書で理解できなかった内容に対して違った観点での解説を読むことができ、オススメです。題名の通り「なぜそうなるのか?」がスッキリ理解できるような解説内容にもなっており、C言語入門書としてもかなり分かりやすい参考書だと思います。
もちろんネット等でも色んな観点からの解説を読むことが出来ますので、分からない点は別の人・別の参考書の解説を読んで解決していきましょう!もちろん私のサイトも参考にしていただけると嬉しいです!
入門用のオススメ参考書は下記ページでも紹介していますので、こちらも是非参考にしていただければと思います。
https://daeudaeu.com/c_reference_book/