久々に長文になりますが、ご容赦下さい。
凄く良い質問だと思いましたので。
私も学び始めて1年間位は、ポインタなんて絶対に必要ない。無くたって組めるじゃん。と思っていた時期がありましたよ^^;
結論から言うと、ポインタが無いと物凄く困ります。私はC言語系の技術で飯の種を作っていますが、もしこの概念が消えたら、C言語はすぐにやめます;
ライブラリ製作者的に、どれだけ不便になる事か・・・
確かに、1つの関数(main等)の中で、ポインタなんて使っても、何の意味も無いですからね。
ただアスタリスクを付けたら中身が、付けなければアドレスが表示できます。程度のものです。
それと、ポインタが文字列操作をする時にばかり使う物だと思っていませんか?確かに参考書だと文字列に関する物が多いですからね。
そこだけで考えると、配列と文字列の違いがピンと来ないと思います。文字列操作における配列と文字列の違いは、代表的な所で内部でのメモリの参照方法云々の話なので、あまり表面化されませんし。
初心者・初級者の内は触れることすら無いでしょう。
ですが、文字列に関してもポインタ、つまりアドレスをきちんと扱える事は、C言語プログラマには絶対必須として求められます。
厳しい言い方になりますが、それが出来ない、必要ないと言うなら、C言語プログラマは名乗れないかと。
少なくとも、私はその人をC言語使いとは認められません。
ビットフィールドや可変個引数の関数なんて知らなくても良いですが、アドレスの概念を把握し、応用出来ない事は、C言語でソフトを作る上では致命的です。
もしそのような人がメンバにいたら、その仕事は断りたい位です。絶対迷惑かけられますから。
ポインタを使わないプログラムなら、他の言語でも出来ますので、わざわざCを使う必要が激減します。
ポインタがその真価を発揮するのは、関数を学び始めてからです。
ライブラリ等、共通していつでも使いたいと言う処理を関数化しておくと、ソースを組みやすくなり、効率が何十倍以上にも上がったりするのですが。
初心者との事ですので、関数が分からない場合申し訳無いのですが、少しソースを書いて説明しますね。
例題なので実用的では無いですが、ご容赦下さい。
例)第一、第二パラメータに数値を入力し、大きい方を第三、小さい方を第四パラメータに格納する関数を作り、その第三、第四パラメータの値をmain()で表示する。
そんな機能が欲しかったとします。
以下に、ポインタを使う場合と使わない場合の関数を作ってみます。
#include <stdio.h>
/* ポインタを使わない */
void no_pointer( int i_iA, int i_iB, int i_iC, int i_iD );
/* ポインタを使う */
void pointer( int i_iA, int i_iB, int *po_iC, int *po_iD );
int main( void )
{
int iMax = 0;
int iMin = 0;
/* ポインタを使わない */
no_pointer( 10, 30, iMax, iMin );
printf( "iMax = %d\n", iMax );
printf( "iMin = %d\n", iMin );
/* ポインタを使う */
pointer( 10, 30, &iMax, &iMin );
printf( "iMax = %d\n", iMax );
printf( "iMin = %d\n", iMin );
return 0;
}
void no_pointer( int i_iA, int i_iB, int i_iC, int i_iD )
{
if ( i_iA >= i_iB ) {
i_iC = i_iA;
i_iD = i_iB;
}
else {
i_iC = i_iB;
i_iD = i_iA;
}
}
void pointer( int i_iA, int i_iB, int *po_iC, int *po_iD )
{
if ( i_iA >= i_iB ) {
*po_iC = i_iA;
*po_iD = i_iB;
}
else {
*po_iC = i_iB;
*po_iD = i_iA;
}
}
実行くだされば分かると思いますが、no_pointer関数だと、スコープの問題で数値の変化が適用されません。
no_pointerの中だけで処理が完結してしまうからです、その為、pointer関数には、変数のアドレスを渡しています。これで数値の変化が行われます。
表示するだけなら、no_pointer関数の中にprintfを入れれば良いと思われるかも知れませんが、表示の仕方は必ずしもprintfが使われる訳ではないです。
Windowsアプリケーションなら、文字を表示では無く、描画する関数が必要になります。ここでno_pointerの中にprintfが入っていた場合、no_pointerはコンソールアプリケーションでしか使えない関数になってしまいます。
ifdef等で処理分けし、コンパイルオプションで適用させる方法も取れなくは無いですが、一々オプションを設定する等、面倒ごとを嫌うプログラムの世界では、やはり好まれません。
あくまで、数値の大小を比べて、格納すると言う意味を持たせたい時に、ムダに使用可能な領域を狭める様な処理を入れるのは、汎用的な処理が求められるライブラリを製作する場合には好ましくありません。
また、通常は、1つのソフトに関数が数百個と入っています。数の大小を比べたい場所が200個あったとして、それぞれ全てにif(~)と、処理を並べますか?
数値の比較程度なら数行で収まりますが、中には100行以上の処理を要する場合もザラにあります。
一々全て書いていたら、100行*200個で、2万行も書かなければいけません。関数にすれば、100行ですみ、19900行も違いが出ます。
関数1つ呼んで、1行で済むなら楽な物ですし、処理が見やすく、メンテナンスもしやすくなります。
もし関数名を変える事になっても、全てでpointerと書いておけば、エディタのグレップ機能で一括変換してくれます。
ソフトウェアを作る場合、初心者が考える以上に規模が巨大であると言う事(物によってはムダに数百万行とか)と、作る際になるべく楽に、作った後も見やすく、メンテナンスしやすいように。と言う心がけが必要です。
これは、Cに限らず、どの言語でも同じ事です。
プログラム言語の作成者は、我々言語の利用者よりも遥かに深く考え、追求し、その結果を機能に盛り込んでいます。
必要の無い機能なんてそうそうありませんし、ポインタが必要だと熟練者が口を揃えて言うのも、きちんとした苦労談や経験に基づいての事ですので、言語の新しい機能が難しく、用途が分からないと言う理由だけで、ないがしろにするのは、後で困りますよ^^;
経験して真意を掴んだ瞬間に、これ以上無いくらいに理解できると思いますがw
お礼
失礼なんてとんでもないです。 初心者の私にはとってもありがたいです。 ポインタ=アドレスって凄く強くもってしまってるので、その一途な概念は捨てないとなのですね・・。 もちろん、アドレス指定ってことも捨ててはならないってことも伝わってきました。 今回お教えいただけたことを思いながら、努力を重ねていきたいとおもいます。 お返事ありがとうございました。 がんばってみます。