ログイン
kid's world

文字列の操作

文字列の操作

文字列の代入

ところで,

char s[10];
s = "ABC";

という「文字列の代入」は誤りだと述べたが,このような代入をしたくなる場面は多々ある。実際にどうすればよいのだろうか。

ここで,List 10を見てみよう。最初にs1とs2という2つのchar型へのポインタを宣言している。次にそれぞれに"ABC\n"と"DEF\n"を「代入」し,それぞれの内容を表示している。その次にs1にs2を,これまた「代入」している。そして,s1の内容を表示している。

List 10: 単なるポインタのコピー

#include <stdio.h>

main()
{
  char *s1, *s2;
  
  s1 = "ABC\n";
  s2 = "DEF\n";
  printf(s1);
  printf(s2);
  
  s1 = s2;
  
  printf(s1);
}

このプログラムは正しくコンパイルできるし,正しく実行される。実行結果も思ったとおりになっただろう。「なんだ,配列ではなくポインタを使えばいいのか」と思っただろうか。もしそう思ったとしたらそれは間違いだ。このプログラムは文字列を代入しているのではなく,単にポインタを代入しているにすぎないからだ(Fig. 4)。

Fig. 4: 単なるポインタのコピー

/c/string-fig4.png

したがって,本当に文字列そのものをコピーしたいと思ったら,めんどうでも1文字ずつコピーしていかなければならない。

しかしそんなめんどうなコードをいちいち書いてはいられない。幸いにC言語には文字列をコピーする関数,strcpy関数があらかじめ用意されているので,これを使ってしまおう。

この関数は,コピー元の先頭から'\0'までのデータを,コピー先に指定されたアドレスを先頭として順番にコピーしていく。この関数を使うにはstring.hをインクルードする。strcpy関数の第1パラメータにコピー先,第2パラメータにコピー元の,それぞれchar型へのポインタを指定する。代入演算子のように,左側にコピーされる側がきている形になっているので覚えやすい。

List 11に,List 10を書き換えたプログラムを示す。このプログラムを実行すると,イメージ的にはFig. 5のように処理されることとなる。

List 11: strcpy関数

#include <stdio.h>
#include <string.h>

main()
{
  char *s1, *s2;
  
  s1 = "ABC\n";
  s2 = "DEF\n";
  printf(s1);
  printf(s2);
  
  strcpy(s1, s2);
  
  printf(s1);
}

Fig. 5: strcpy関数によるコピー

/c/string-fig5.png

文字列の連結

2つの文字列を連結して,1つの文字列

にしたい場合は,どのようにすればよいの

だろうか。

たとえば,

char s1[]="ABC", s2[]="DEF", s3[80];

という3つのchar型の配列があったとき,s1とs2を連結して,"ABCDEF"という文字列をs3にコピーするにはどのようにすればよいのだろう。もちろん,

s3 = s1 + s2;

という演算はできない。配列の名前だけを指定すると,その配列の先頭アドレスを表すからだ。文字列を連結するには,やはり1文字ずつコピーしていかなければならないのだが,string.hで宣言されているstrcat関数を使えば簡単に処理できる。strcat関数は,第1引数で与えられた文字列の後ろに,第2引数に与えられた文字列を追加する。そのため,まずs3にs1の文字列をコピーする。これは前述のstrcpy関数で行える。

strcpy(s3, s1);

そして,strcat関数で,s3にs2の文字列を追加する。

strcat(s3, s2);

これで,s3は”ABCDEF”という連結され

た文字列になった(List 12)。

List 12: 文字列の連結

#include <stdio.h>
#include <string.h>

main()
{
  char s1[]="ABC", s2[]="DEF", s3[80];

  strcpy(s3, s1);
  strcat(s3, s2);

 printf(s3);
}

文字列の入力

でもまだこれだけではちょっとつまらない。キーボードから文字を入力できる方法についても解説しよう。

以前,キーボードから文字や数値を入力するのにscanf関数を使ったが,文字列の入力も同じくscanf関数を使う。ただし,空白文字で区切られてしまうことに注意。

変換文字には「%s」を使う。ちなみに,printf関数でも「%s」を使って文字列を表示することができる。具体的にはList 13のように書く。このようにして,入力された文字列がchar型の配列sに記憶されるわけだ。

List 13: 文字列の入力

#include <stdio.h>

main()
{
   char s[200];
   
   scanf("%s", s);
   printf("入力した文字:%s\n",s);
}

メモリの確保に気をつけよ!

文字列を扱う際に気をつけなければならないことがある。それは,「メモリの確保」だ。たとえば先ほどのList 13を,List 14のように書いても,コンパイルはできる。

List 14: 文字列の入力の誤った例

#include <stdio.h>

main()
{
  char *s;

  scanf("%s", s);
  printf("入力した文字:%s\n",s);

しかし,このプログラムを実行してはならない。scanf関数は,char型へのアドレスを受け取り,キーボードから入力された文字列を,そのままそのアドレスから順番にコピーしていく。したがって,もしその部分のメモリが正しく確保されていなかったら,たいへんなことになってしまう。このことについてはこれまでに詳しく説明してきたことだ。

したがって,List 13のように配列を使ってあらかじめメモリを確保しておくか,List 15のようにmalloc関数を使ってメモリを動的に確保する必要がある。

List 15: malloc関数を使った例

#include <stdio.h>
#include <stdlib.h>

main()
{
  char *s;
  s=malloc(200);
  
  scanf("%s", s);
  printf("入力した文字:%s\n",s);
  
  free(s);
}

文字列を扱うときはとくに,このようなメモリの管理を忘れてしまう場合が多い。神経質なぐらいに気をつけてもちょうどよいぐらいである。

おわりに

C言語で文字列を扱うのは,少々やっかいだ。文字列という型はないため,char型へのポインタによってむりやり文字列を扱っているという感覚だ。しかしポインタであることを積極的に利用すれば逆に効率的なコードを組むことができるので,一概に悪いともいえない。

ただ,最初はつまずくことが多いだろう。char型へのポインタを扱うということもそうだが,それ以上に,メモリの管理にかなり神経を使わなければならないからだ。知らず知らずのうちに,確保していないメモリ領域に書き込んでしまっていた,なんてことがよく起こるだろう。

これは知識を詰め込めば避けられるかというとそうではなくて,失敗をしながら経験を蓄えるしか方法がないようだ。したがって,失敗してもいい今のうちに,どんどん進んで失敗するべきであろう。

次回はファイルの扱い方について解説する。ファイルを扱えるようになると,さらにぐっと作れるプログラムの幅が増す。ぜひともマスターしていただきたい。


条件判断」へ進む

広告


©Toshio Koide 1996-2007.

目次

リンクについて

リンクは御自由にどうぞ。

メール

mail.gif

広告