前回作成した文字列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は読み取られません。解決するにはどのようにしたらよいでしょうか?
文字列bの最初の単語だけをコピーする関数の作成
Re:文字列bの最初の単語だけをコピーする関数の作成
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
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の最初の単語だけをコピーする関数の作成
ちょっと訂正。
事前に(以前のプログラムにあった)
while(*p2 == ' '){
p2++;
}
で空白を読み飛ばせばOKです。(今回は、コピーせずに読み飛ばすだけ)
事前に(以前のプログラムにあった)
while(*p2 == ' '){
p2++;
}
で空白を読み飛ばせばOKです。(今回は、コピーせずに読み飛ばすだけ)
Re:文字列bの最初の単語だけをコピーする関数の作成
以下のように書くことで、最初の空白の呼び飛ばし、最初の単語だけ表示ができました!
#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++;
}
の記述ですが、目にすると「なぁんだそんな事かぁ」と思うのですが、それがなかなか思いつかないので大変です。柔軟な思考が大事ですね!ありがとうございました。
#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++;
}
の記述ですが、目にすると「なぁんだそんな事かぁ」と思うのですが、それがなかなか思いつかないので大変です。柔軟な思考が大事ですね!ありがとうございました。