文字列bの最初の単語だけをコピーする関数の作成

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ケン@ポチ

文字列bの最初の単語だけをコピーする関数の作成

#1

投稿記事 by ケン@ポチ » 17年前

前回作成した文字列bを文字列aにコピーする関数をもとにつくっています。
今回は単語のコピーで、単語の区切りは空白で表しています。また、文字列の先頭の空白は読み飛ばすようにします。

例えば
(入力) This is a pen
(出力)This
といった感じです。Thisの前の空白は読み飛ばしています。

そこで前回の文字列bを文字列aにコピーする関数を改変して以下のようなプログラムにしました。
#include<stdio.h>

int word_copy(char *p1,char *p2);

int main(void){
char a[256],b[256];
char *p1,*p2;

p1= a;
p2= b;

gets(p2);

word_copy(p1,p2);

return 0;
}

int word_copy(char *p1,char *p2){
int c=0;
while(*p2 != ' '){ /*文字列が空白になるまで*/
*p1 = *p2;
p1++;
p2++;
c++;
}
while(p1>p2){
p1--;
}
printf("%s\n",p1);
printf("length=%d\n",c);
return c;
}

このプログラムを実行すると、This is a penと入力した際にis a penと表示されてしまいます。
単語の長さはちゃんとThisの4が表示されるのですが、文字のほうが表示されません。
これはwhile文はちゃんと条件通りに行っているという事ですよね?
p1とp2共に空白のアドレスまで移動し、p1はそこから最初のアドレスまで戻っているのだからThisが表示されると思うのですが・・・

またこの場合だとThisの前に空白があると当然Thisは読み取られません。解決するにはどのようにしたらよいでしょうか?

なぎ

Re:文字列bの最初の単語だけをコピーする関数の作成

#2

投稿記事 by なぎ » 17年前

is a pen と表示されるのは、
while(p1>p2){
p1--;
}
が、そもそも間違っているからです。
p1 は、「最初のアドレス」までは戻りません。
運が良ければ、「現在の p2 のアドレス」に戻るだけです。
つまり、最初のスペースの次です。

word_copy() の最初のほうで、

char *wk = p1;
で p1 の「関数に入った時の=コピーが終了した時のコピー先の」アドレスを保存しておいて、
単に表示させるだけであれば、
printf("%s\n",wk);
でOKです。

また、この場合、コピー先のデータは、文字列の終端処理がされていません。
先ほどのものは、たまたま、コピー元の文字列の先頭をポイントしましたし、今回お書きのプログラムも、p2 の途中から表示しているので、問題は表面化しませんでしたが、

while(*p2 != ' '){ /*文字列が空白になるまで*/
*p1 = *p2;
p1++;
p2++;
c++;
}
の直後に、
*p1 = '\0';
が必要です。

さらにいえば、呼び出し側で、

p1= a;
p2= b;

gets(p2);

word_copy(p1,p2);

とする必要はなく、

gets(b);
word_copy(a, b);

でOKです。
この方が、シンプルになると思います。

最後に、「This の前に空白があると……」というのは、その処理がないだけですね。

事前に(以前のプログラムにあった)
while(*p2 != '\0'){
p2++;
}
で空白を読み飛ばせばOKです。(今回は、コピーせずに読み飛ばすだけ9

なぎ

Re:文字列bの最初の単語だけをコピーする関数の作成

#3

投稿記事 by なぎ » 17年前

ちょっと訂正。

事前に(以前のプログラムにあった)
while(*p2 == ' '){
p2++;
}
で空白を読み飛ばせばOKです。(今回は、コピーせずに読み飛ばすだけ)

ケン@ポチ

Re:文字列bの最初の単語だけをコピーする関数の作成

#4

投稿記事 by ケン@ポチ » 17年前

以下のように書くことで、最初の空白の呼び飛ばし、最初の単語だけ表示ができました!


#include<stdio.h>

int word_copy(char *p1,char *p2);

int main(void){
char a[256],b[256];


gets(b);

word_copy(a,b);
return 0;
}

int word_copy(char *p1,char *p2){
int c=0;
char *p3;

p3 = p1;
while(*p2 ==' '){
p2++;
}
while(*p2 !=' '){
*p1 = *p2;
p1++;
p2++;
c++;
}
*p1='\0';
printf("%s\n",p3);
printf("length=%d\n",c);
return c;
}

今回はp3にp1の先頭アドレスを代入しておいて、p1が端っこまで行ってもp3で先頭アドレスが呼び出せるということですね。最後の所をp1 = p3としprintf("%s\n",p1)としても同じ結果が得られました。どっちもp1の先頭アドレスを指す事に変わりはない事も確認できました。

また
while(*p2 == ' '){
p2++;
}
の記述ですが、目にすると「なぁんだそんな事かぁ」と思うのですが、それがなかなか思いつかないので大変です。柔軟な思考が大事ですね!ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る