• ベストアンサー

関数に文字列を渡すことについて

参考書にあったプログラムなのですが、 ------------------------------------------- #include<stdio.h> void strout(char ss[ ]); int main(void) { char st[ ]="ABCDEF"; strout(st); strout("ABab12"); return 0; } void strout(char ss[ ]) { int i; printf("ss=%s\n",ss); i=0; while(ss[i]){ printf("%X ",ss[i]); ++i; } printf("\n"); } ---------------------------------------------- ------------実行結果--------------- ss=ABCDEF 41 42 43 44 45 46 ss=ABab12 41 42 61 62 31 32 ----------------------------------- 初心者という事で、いろいろと疑問があるのですが、 ◎1「stとして、文字配列をss[ ]に渡すのと、"ABab12"として直接文字列をss[ ]に渡すのはとは、どういうことなのかということ。そしてその時ss[ ]はどうなっているか?」 ◎2「実行結果で、最初のprintfからループさせなくてもss=ABCDEF、ss=ABab12が何故2つとも表示され、2つとも16進数が表示されるのか?」 ◎3「while(ss[i])だけで何故、'\0'でない間ループするという事が出来てしまうのか?」 以上のような疑問があります。 先頭のアドレスを渡すといったような説明はあるのですが、いまひとつ分かりません。 教えていただけると嬉しいです。

質問者が選んだベストアンサー

  • ベストアンサー
  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.2

> ◎1「stとして、文字配列をss[ ]に渡すのと、"ABab12"として直> 接文字列をss[ ]に渡すのはとは、 変数stとは、ある番地に格納された'A''B''C''D''E''F'という char[6]型というchar配列型となります。 strout関数にこれを渡す時、配列の一番最初の場所を示す値 (先頭アドレス)を関数に与えます。 "ABab12"をstrout関数に渡す場合、この場合は、 この文字列を格納する場所を示す値が渡されるのは同じですが 文字列リテラル(文字定数)は静的メモリ領域に配置されます ので「中身を書き換えることが許されていません」一方最初に 渡されるstは変数なので、その領域内であれば書き換えることが 可能です。 # 今回はstrout関数が中身を参照するだけで # 書き込みを行わないので問題はありません。 > そしてその時ss[ ]はどうなっているか?」 C言語ではssのようなものを仮引数と呼びます。 仮引数は、関数が呼び出されるたびに、 与えられた引数のコピーを伴って初期化されます。 つまり、strout(st);が呼び出された時点で、 ssはstの配列の一番最初の場所を示す値で初期化され この関数を抜けるときssは破棄され、また、 strout("ABab12");の呼び出しで、"ABab12"の 一番最初の場所を示す値で初期化され、関数を抜けるとき 破棄されます。 >◎2「実行結果で、最初のprintfからループさせなくても > ss=ABCDEF、ss=ABab12が何故2つとも表示され、 > 2つとも16進数が表示されるのか?」 ここでのstrout関数とは呼び出すだけで文字列と 16進数字を表示してくれる機能をおもっています。 最初でstrout(st);とstrout("ABab12");で 2回呼び出されているので2つ表示されます。 >◎3「while(ss[i])だけで何故、'\0'でない間 > ループするという事が出来てしまうのか?」 C言語の文字列の終わりは'\0'であることが決められています。 '\0'は式上ではに0と等価です。 whileやifなどの条件式では0が偽(成り立たない), 0以外が真(成り立つ)ということが決まっています。 条件式のwhile(ss[i])'とは、文字列の終端が来た場合に、 while('\0')となるので、条件が成り立たなくなり、 ループを終えることができます。 説明べたで長くなりましたがこんな感じです。

muffler
質問者

お礼

>ssはstの配列の一番最初の場所を示す値で初期化されこの関数を抜けるときssは破棄され、また、strout("ABab12");の呼び出しで、"ABab12"の一番最初の場所を示す値で初期化され、関数を抜けるとき破棄されます。 これは、ssが2回以上初期化されたといった、エラーが出ないのは、「関数を抜けるときssが破棄される」からといった感じだからでよいのでしょうか?

すると、全ての回答が全文表示されます。

その他の回答 (3)

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.4

> これは、ssが2回以上初期化されたといった、 > エラーが出ないのは、「関数を抜けるときssが破棄される」 > からといった感じだからでよいのでしょうか? 初期化と書きましたが様はmainから渡された式の結果の代入です。 「破棄されるから」というよりは、strout関数に指定された引数が、 ssという名前に置き代わる以外は、1回目に呼び出された時のssと 2回目に呼び出されたssには関係が無いというか、分けて 考えるべきだということです。 #ちょっと説明下手なので語弊を招くかもしれませんが。

muffler
質問者

お礼

>1回目に呼び出された時のssと2回目に呼び出されたssには関係が無いというか、分けて考えるべきだということです。 かなり納得いたしました。ありがとうございます。

すると、全ての回答が全文表示されます。
回答No.3

◎1 mainでは、どっちも「文字列の先頭のアドレスだけ」を渡しています。 stroutでは「文字列の先頭アドレスだけ」を受け取っています。 配列や文字列の全部をそのまま受け渡ししている訳ではありません。 簡単に言うと、mainからは「文字列のある場所だけ教えるから、教えた場所から取り出して使ってね」と関数を呼び出します。 呼ばれたstroutは「なるほど、ここにあるのか。ここから取り出して使おう」と、教えられた場所を信じて動きます。 配列そのものや、文字列そのものは、受け渡ししていません。 実は void strout(char ss[ ]) { 中身略 } と書くと void strout(char *ss) { 中身略 } と書いたのと同じなのです。 ◎2 質問が日本語ではないようです。日本語で大丈夫なので、日本語で書いて下さい。 ◎3 条件式は「非0なら真、0なら偽」です。 '\0'は、数値的には「0」なので 「非0なら真、0なら偽」 と 「非'\0'なら真、'\0'なら偽」 は等価です。 なので while(ss[i]) と while(ss[i] != '\0') は等価です。 ただし、前者の方が判断する時間が短くなる場合があります。

muffler
質問者

お礼

while(ss[i]) と while(ss[i] != '\0') が同じ意味ということかなり納得いきました。 ありがとうございます。

すると、全ての回答が全文表示されます。
  • Hardking
  • ベストアンサー率45% (73/160)
回答No.1

◎1、文字型配列変数に一時格納するか、文字定数するかの違いで    処理結果上違い。はありません。    ss[]とは変数型であって、変数名としてはssです。 strout(st); ----ssの値 ABCDEF strout("ABab12"););----ssの値 ABab12 ◎2、ABCDEF、ABab12と表示されるのprintf文で%sとしている為。    16進数で表示されるのはprintf文で%Xとしている為。    文字として表示するのであれば、%cとする。 ◎3、文字列の末端は必ず\0(ヌル)文字である決まりごとだからです。

すると、全ての回答が全文表示されます。

関連するQ&A