• ベストアンサー

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

参考書にあったプログラムなのですが、 ------------------------------------------- #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には関係が無いというか、分けて考えるべきだということです。 かなり納得いたしました。ありがとうございます。

  • chie65535
  • ベストアンサー率43% (8519/19367)
回答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

  • 文字列を関数に渡すぷろぐらむなのですがおかしいです。

    <ソース> #include<stdio.h> #include<stdlib.h> void str(char a[]); int main() { char st[10]="abcde"; str(st); str("ABCabc123"); return 0; } void str(char a[]) { int i; printf("%s\n",a); i=0; while(a[i]){ a[i]=toupper(a[i]); putchar(a[i]); i++; } putchar('\n'); } 分からないところがあるので質問します。 toupperは、大文字にするんですよね。 putcharは、基本的にchar型でしたっけ? putsとgetsは、int型でしたっけ? 後、プログラムが暴走してます。 どこがおかしいんでしょう?

  • 文字の数値化 関数化

    文字を入力されたとき、数値入力を促す関数を作りたいのですが、 最初の文字が文字ならエラーメッセージがちゃんと出るのですが、 最初の文字が数字ならエラーメッセージが出てくれません。 アドバイスお願いいたします。 tew2 ← エラー出る 2test ← エラー出ない #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> float ss_input(void); int main(){ int i; int pop; printf("何人の入力しますか(3人以内)->"); do{ pop=ss_input(); if(pop >3) printf("3人以内でお願いします\n"); }while(pop<1 || pop>3); return 0; } float ss_input(void){ char p[100]; float st; int i=0; scanf("%s",p); while( p[i] != '\0'){ if(isdigit(p[i])==0){ printf("数値を入力してください->"); scanf("%s",p); continue; } else{ break; } } st=atof(p); return st; }

  • 配列やポインタに文字列を設定することについて

    ◎1------------------------- #include<stdio.h> int main(void) { char ss[80]; scanf("%s",ss); printf("%s\n",ss); return 0; } ---------------------------- ◎2--------------------------- #include<stdio.h> int main(void) { char *ss="abcde"; printf("%s\n",ss); return 0; } ------------------------- ◎3---------------------- #include<stdio.h> int main(void) { char *ss; ss="abcde"; printf("%s\n",ss); return 0; } ------------------------- 以上3つプログラムで疑問をいだいたのですが、 まず◎1で、これは例えば、 cahr ss[80]="abc"; のように配列ssに文字列"abc"そのものを入れているのか、 char *ss="xyz"; のようにまず"xyz"という文字列をメモリ上のどこかに設定し、その先頭番地をssに代入しているのか、どちらの考えでいいのかわかりません。 次に、◎2、3ではどちらも正常に実行できたのですが、特に◎3で「ss="abcde";」と記述していますが、ssにはアドレスを代入するという認識かあるのですが、文字列定数を代入しても問題ないのか?という疑問があります。 教えていただけたら嬉しいです。

  • プログラミング 関数

    逆順する関数reverseを作成したいんです。 以下のは関数reverseを利用したmainのプログラムです。 #include <stdio.h> void reverse(char str1[],char str2[]); int main (void) { char strin[255]="abcdefg"; char strout[255]; reverse(strin, strout); printf(" input=%s\n",strin); printf("output=%s\n",strout); return 0; } 教えてください。

  • 文字列について

    textファイルをいくつかに分割して保存しようと思い、以下のプログラムを作りましたが、うまくいきません。 予定では "0000.txt", "0001.txt", ....と文字列を生成するはずです。 #include <stdio.h> #include <string.h> #define LENGTH 4 //番号の桁数 void filename(int n) {    char name[LENGTH +4 +1];    char text[5] = ".txt";    int i;    for(i = 0; i <= LENGTH; i++)       name[i] = '0';    i = LENGTH;    //自然数を文字列に変換    do{       name[i] = (char)(n%10 + 48);       i--;       n /= 10;    }while(n != 0 && i >= 0);    strcat(name, text);    printf("filename:%s", name); } int main(void) {    int i;    for(i = 0; i < 5; i++){       filename(i);       printf("\n");    }    return 0; } 実行結果は filename:00000@.txt filename:00001.txt filename:00002.txt filename:00003.txt filename:00004.txt このように、文字化けしています。 何が原因なのでしょうか。 よろしくお願いします。

  • 文字列

    下のプログラムは何をするためのプログラムなのか教えてください。 個人的にはJISコードに関係していると思うのですがさっぱりわかりません。 どなたか詳しい説明お願いします。 #include <stdio.h> #define LEN 255 int main(void) { char str[LEN]; char cipher[LEN]; int ikey; int i,n; printf("文字列を入力せよ : "); scanf("%s", str); printf("鍵を入力 : "); scanf("%d", &ikey); i = 0; while (str[i]!='\0') { n = (str[i]-'A'+ikey)%26; cipher[i] = 'A'+n; ++i; } cipher[i] = '\0'; printf("%s\n", cipher); return 0; }

  • C言語 文字列の操作

    文字Cが含まれる個数を求めたいです #include <stdio.h> int str_chnum(const char str[],int c) { int i; int count=0; for(i=0;str[i]!="\0";i++) if (str[i]==c) count++; return(count); } int main(void) { char st[100]; printf("検索文字列を入力してください:"); scanf("%s",st) ; printf("検索文字列数は%uです。\n",st,int str_chnum(const str[],int c)); return(0); } コンパイルできません。なぜですか?printfの行がたぶん間違っていると思うんですが。。。

  • c言語 文字列と配列

    #include<stdio.h> int charlen(int n); void cap2sml(int b); int main() { char a[100],b[100]; int n,i; /*Input CARACTERS*/ printf("CAPITAL?\n"); fgets(a,100,stdin); charlen(n); printf("total cahrs=%d\n",n); //printf in main cap2sml(i); printf("small=%s\n",b); return(0); int charlen(int n) n=0; while(1){ if(a[n]=='\0') break; n++; } void cap2sml(int b) int i; for(i=0;a[i]!='\0';i++){ b[i]=a[i]+0x20; } b[i]='\0' } のプログラムでエラーがでるのですが、どこを直せばよいでしょうか? ユーザー関数を使い文字列(大文字)を入力したときの文字列の長さと大文字を小文字に変化するプログラムです

  • 大文字変換についてですが・・・

    初歩的なことですがよく分かりません。。 tokyoをTOKYOに大文字変換するプログラミング作成したいのですがどこを修正すればいいでしょうか? 初歩的な質問ですいませんがご教授お願いします。 #include <stdio.h> void henkan(char *a); void main(){ int i; char *aa="tokyo"; printf("%s\n",aa); henkan(aa); printf("%s\n",aa); } void henkan(char *a){ int i; char *b; b=a; while(*b!='\0'){ *b=*b+0x20; b++; } }

  • -'0'の意味について

    C言語を学んであまり経っていない初心者です。 勉強していてどうにもわからないので質問させていただきたいと思います。 以下のプログラム、文字列stに含まれている数字文字'0'~'9'の個数を、cnt[0]cnt~[9]に格納して、数字文字'9'が文字列stにいくつ含まれているかを確認するプログラムです。 疑問なのは関数cntdigit内のwhile文内の cnt[*st - '0']++;というところです。 - '0'は何の役割を果たしているのでしょうか。 ためしに- '0'を抜いて実行したら数字文字がstに入力されるとエラーが発生します。 #include<stdio.h> void cntdigit(char *st, int *cnt) { int i; for (i = 0; i < 10; i++) *(cnt + i ) = 0; while (*st) { if (*st >= '0' && *st <= '9') cnt[*st - '0']++; ←ここ st++; } } int main(void) { int cnt[9]; char st[100]; printf("文字列を入力してください : "); scanf("%s" , st); cntdigit(st , cnt); puts("格納しました。 "); printf("9の数は%dです。", cnt[9] ); return (0) ; }

専門家に質問してみよう