dポイントプレゼントキャンペーン実施中!

参考書にあったプログラムなのですが、
-------------------------------------------
#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'でない間ループするという事が出来てしまうのか?」

以上のような疑問があります。
先頭のアドレスを渡すといったような説明はあるのですが、いまひとつ分かりません。
教えていただけると嬉しいです。

A 回答 (4件)

> ◎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')となるので、条件が成り立たなくなり、
ループを終えることができます。

説明べたで長くなりましたがこんな感じです。
    • good
    • 0
この回答へのお礼

>ssはstの配列の一番最初の場所を示す値で初期化されこの関数を抜けるときssは破棄され、また、strout("ABab12");の呼び出しで、"ABab12"の一番最初の場所を示す値で初期化され、関数を抜けるとき破棄されます。

これは、ssが2回以上初期化されたといった、エラーが出ないのは、「関数を抜けるときssが破棄される」からといった感じだからでよいのでしょうか?

お礼日時:2009/02/03 12:10

> これは、ssが2回以上初期化されたといった、


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

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

かなり納得いたしました。ありがとうございます。

お礼日時:2009/02/03 18:02

◎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')
は等価です。

ただし、前者の方が判断する時間が短くなる場合があります。
    • good
    • 0
この回答へのお礼

while(ss[i])

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

お礼日時:2009/02/03 17:59

◎1、文字型配列変数に一時格納するか、文字定数するかの違いで


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

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!