博士

文字列・・・に入る前に

文字表示関数を自作してみよう

博士「ここをチェックじゃ」

問題じゃ!
複数の文字・・・「ABC」を表示するプログラムを作る場合はどうすればよいかの?


困った顔のぷうさん

一個の変数に一つの文字しか入れないから・・・配列だったっけ?
それとループ文を使って表示する・・・するんだよね!?


博士「Good!」

正解じゃ♪
自作の関数を使うとプログラムが短くスッキリするぞい。

実行文

#include <stdio.h>
void hyoji(int num, char *top);
main()
{
   char moji[3]={'A','B','C'}; //注1
   hyoji(3,&moji[0]);
}
void hyoji(int num, char *top) //注2
{
   int i;
   for (i=0;i<num;i++) {
      printf("%c",*(top));
      top++;
   }
}

注1
moji[0]=A、moji[1]=B、moji[2]=Cとする。
注2
先頭アドレスをtopというポインタで受け取っている。

実行結果

ABC

博士

分かったかの?


ぷうさん「(^^♪」

OK☆

文字列の表示方法と初期化

博士

お次は、文字列じゃ。「%c」は1文字表示と言ったの。


ぷうさん

うん。


博士「ここをチェックじゃ」

複数の文字つまり文字列は、「%s」で表示するんじゃ。


ぷうさん「OK」

なるほど、「c」はキャラクターで、「s」はストリングの頭文字だね!!


博士

そうじゃ、とりあえず実際に使ってみようかの。
・・・まずは下のプログラムと表をよく見比べるのじゃ。

プログラム文

#include <stdio.h>
main()
{
   char moji[4]="ABC";
   printf("%s",&moji[0]);
}
変数 文字 数値
moji[0] A 65
moji[1] B 66
moji[2] C 67
moji[3] \n(NULLコード) 0

ポイント

博士

文字列を表示させる場合は、変数の先頭のアドレスを指定するんじゃぞ。
そして表示させたい箇所に、前にも言ったように%sをprintf文に入れるんじゃ。









博士「ここをチェックじゃ」

moji[4]は[0]から[3]までということは、もう分かっとるな?


ぷうさん

はい、はい。


博士「怒」

返事は一度でよろしい!


ぷうさん「OK」

はいっ!


博士

そこに書かれておらんでも、文字列の最後にはNULLコード(ヌルコード)と言って必ず\nがついいておるのじゃ。
じゃから、”ABC”=abc0というわけじゃ。


ぷうさん「(^^♪」

ここで文字列が終わりだよ~という印だね。


博士「Good!」

そうじゃ、この事を忘れんようにな。

NULLコードについて
/0で表示されますが、お使いされているフォントによって0の前の文字がバックスラッシュ(/の左右反転)か¥の半角のどちらかで表示されております。

文字列コピー関数

博士

今度は文字列をコピーしてみようかの。

実行文

include <stdio.h>
void mojicopy(char *pnt2,char *pnt1);
main()
{
   char moji1[4]="ABC";
   char moji2[4]="DEF";
   printf("%s\n",&moji2[0]);
   mojicopy(&moji2[0],&moji1[0]);
   printf("%s\n",&moji2[0]);
}
void mojicopy(char *pnt2,char *pnt1)
{
   while ( *(pnt1)!=0 ) {
      *(pnt2)=*(pnt1);
      pnt1++;
      pnt2++;
   }
   *(pnt2)=0;
}

pnt1
moji1| A | B | C | \n|
pnt2
moji2| D | E | F | \n|

実行結果

DEF
ABC

C言語らしい省略した書き方

博士

プログラムの意味が分かったところで、もう少しC言語らしくしたプログラムに変えてみようかの。
前のプログラムと見比べるんじゃぞ。

include <stdio.h>
void mojicopy(char *pnt2,char *pnt1);
main()
{
   //配列の大きさを省略して宣言
   char moji1[]="ABC";
   char moji2[]="DEF";

   //&でなく配列名を宣言
   printf("%s\n",moji2);
   mojicopy(moji2,&moji1);
   printf("%s\n",&moji2);
}
void mojicopy(char *pnt2,char *pnt1)
{
   //文字列の最後を明確に
   while ( *pnt1!='\0' ) {
   //代入と同時にポインタの更新
      *(pnt2++)=*(pnt1++);
   }
   //文字列の最後を明確に
   *pnt2='\0';
}

変更箇所について

博士「ここをチェックじゃ」

どうじゃ、分かるかの?
&mojimojiと書けるんじゃぞ。


困った顔のぷうさん

なんか、本当にプログラムを理解してないと・・・ごちゃごちゃになりそう。


博士「?」

質問は?


ぷうさん「こちら」

はいはい!ポインタの宣言がしてない、それも両方とも!


博士「(^^♪」

そうじゃのお・・・つまりそれは、配列の宣言ですませてるって思っておいてよいのじゃ。(・・・と思う・)

まず、void mojicopy(char *pnt2,char *pnt1);とプロトタイプが宣言してある。
そして、main関数の中で、mojicopy(moji2,&moji1);とmijicopy関数を読んでおる。

その型同志を照らし合わせてみるんじゃ。
mojicopy(char *pnt2,char *pnt1);
mojicopy(moji2,moji1);

こうして並べてみると、一緒じゃというのが分かるじゃろ?
ここで、すでに *pnt2=moji2,*pnt1=moji1 となっておるんじゃ。
勿論、moji1とmoji2は配列じゃぞ。

ぷうさん「?」

いちいち宣言しなくても、この手を使えば宣言とポインタが指すアドレスも指定済みってわけでいいのかな?


博士「Good!」

まあ、そうなんじゃろう、多分。


困った顔のぷうさん

ちょっと、ちょっと多分ってどういう事よ?


困った顔の博士

・・・・・ま、ま、そう深く考えずにじゃな・・・ふぉっふぉっふぉっ!

文字列は先頭アドレスを持っているという

博士「(^^♪」

次いくぞ!文字列は先頭アドレスを持っているという事の確認じゃ。

プログラム文

include <stdio.h>
void mojitest(char *pnt);
main()
{
   char moji[]="ABC";
   char *pnt;
   printf("main %d:%s\n",moji,moji);  //注1
   mojitest(moji);  //注2

   pnt="DEF";  //注3
   printf("main %d:%s\n",pnt,pnt);
   mojitest(pnt);
}
void mojitest(char *pnt)
{
   printf("test %d:%s\n",pnt,pnt);
}

注1
配列の先頭アドレス値を持っている。
注2
mojitest関数に文字列”ABC”の先頭アドレスが渡る。
注3
メモリのどこかに’D’,’E’,’F,’\0’がとられ、
文字列”DEF”の先頭アドレスをポインタ”pnt”に入れている。

実行結果

main 3538:ABC
test 3538:ABC
main 660:DEF
test 660:DEF

ポイント

博士「ここをチェックじゃ」

pnt=”ABC”は文字列の先頭アドレスが代入されるって事をよ~く覚えておくんじゃぞ!


ぷうさん「OK」

ふぉ~い!

文字列と配列とポインタ

博士「(^^♪」

も一個いくぞ♪

プログラム文

include <stdio.h>
void mojicopy(char *pnt2,char *pnt1);
main()
{
   char moji[]="ABC";
   char *pnt;
   printf("%s\n",moji);

   pnt="DEF";  //注1
   printf("%s\n",pnt);

   mojicopy(moji,"GHI");  //注2
   printf("%s\n",pnt);
}
void mojicopy(char *pnt2,char *pnt1)
{
   while ( *(pnt1)!=0 ) {
      *(pnt2++)=*(pnt1++);
   }
   *(pnt2)=0;
}

注1
ポインタpntに文字列”DEF”の先頭アドレスを入れている。
注2
配列mojiへ文字列をコピーする。

実行結果

ABC
DEF
GHI

ポイント

博士「ここをチェックじゃ」

main関数に入ってすぐのchar moji[]=”ABC”;のところじゃが、
moji=”ABC”とはできないんじゃ。わかるかの?


ぷうさん

・・・う~んとぉ・・・mojiだけだと配列名でしょ?
そこは、先頭アドレスしか持ってないから、3文字も入らない!


博士「Good!」

そうじゃ。mojiは配列の先頭アドレス(定数)なんじゃ。
それに対してpntは、アドレスを入れることの出来る(変更可の)ポインタじゃから、
mainでmojicopy(moji,”GHI”)としてmojicopy関数に”GHI”を渡し、同時にmojiヘコピーするという処理をまかしておるんじゃ。
mojicopyの方はポインタじゃからの。

その三 文字列操作の標準関数へ

四日目 文字列について 目次

三日目へ

ぷうさんの七日間戦争 四日目

五日目へ