入力: This is a pen.
入力文字列:[ This is a pen. ]
出力文字列;[ pen. a is This ]
―――――――――――――――――――
上に示したように単語の順番をさかさまにして表示するプログラムを作りました。しかし、今のプログラムでは、最初に空白が来たり、空白が連続すると正しく表示できません。どこを修正すればいいのか教えてください。
--------------------------
#include <stdio.h>
#define BUF 1024
void out(int,char);
int main(void){
char in[BUF]; /* 入力された文字列を保存する */
char out[BUF]; /* inoput の内容を単語逆順にして保存する*/
int wordcount; /* 文字カウント */
char *in_ptr,*out_ptr; /* それぞれの文字列の文字をさすポインタ */
int i,j,a,b; /* 繰り返し用カウンタ */
/* メッセージの表示+文字列の入力 */
printf("入力: ");
fgets(in, sizeof(in), stdin);
/* ポインタの初期化 */
in_ptr = in;
out_ptr = out;
/* 単語数の初期化 */
wordcount = 0;
/* 単語数を数える作業 */
while(*in_ptr != '\n'){
if(*in_ptr!=' '&&(*(in_ptr+1)==' '||*(in_ptr+1)=='\n')){
wordcount++;
}
in_ptr++;
}
/* メッセージの表示+単語数の表示 */
printf("\n文字数のカウント開始\n");
printf("文字数のカウント終了: %d単語\n",wordcount);
printf("\n入力文字列:[ %s ]\n", in);
printf("出力文字列;[ ");
/* 単語逆順処理作業 */
b=0;
for(a=0;a<wordcount;a++){
j=0;
b++;
in_ptr = in;
for(i=0;i<(wordcount-b);i++){
while(*in_ptr!=' '){
j++;
in_ptr++;
}
in_ptr++;
}
/* ポインタを単語の頭に持っていく */
in_ptr= in + (j+(wordcount-b));
/* inをoutにコピー */
while(*in_ptr!='\0' && *in_ptr!=' ' && *in_ptr!='\n'){
*out_ptr = *in_ptr;
in_ptr++;
out_ptr++;
}
if(*in_ptr==' '||*in_ptr=='\n'||*in_ptr=='\0'){
*out_ptr = ' ';
out_ptr++;
}
}
printf("%s]\n",out);
return 0;
}
A 回答 (4件)
- 最新から表示
- 回答順に表示
No.4
- 回答日時:
★回答者No.2です。
・前回のアドバイスをソースにしてみました。
参考にして下さい。
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define BUFF_SIZE 1024
#define WORD_SIZE 100
// メイン関数
int main( void )
{
char *word[ WORD_SIZE ];
char in[ BUFF_SIZE ];
char out[ BUFF_SIZE ];
char *pi = in;
char *po = out;
int n, pos;
// 入力
printf( "入力:" );
fgets( in, sizeof(in), stdin );
*strchr(in,'\n') = '\0'; // 簡単改行除去(*)
// (1)単語の先頭をポインタ配列にセット
for ( pos = 0 ; ; pos++ ){
if ( pos >= WORD_SIZE ){
printf( "単語の数が多すぎます。\n" );
return 1;
}
while ( isspace(*pi) ){ // 空白文字を読み飛ばし
pi++;
}
if ( (*pi == '.') || (*pi == '\0') ){
break;
}
word[ pos ] = pi; // 単語の先頭を記憶
while ( isalpha(*pi) ){ // 英字文字を読み飛ばし
pi++;
}
}
// (2)ポインタ配列の最後から順番に単語をコピー
for ( n = (pos - 1) ; n >= 0 ; n-- ){
pi = word[ n ]; // 単語の先頭を取り出す
while ( isalpha(*pi) ){ // 連続する英字文字をコピー
*po++ = *pi++;
}
*po++ = ' '; // 間の空白文字をコピー
}
// 最後にピリオド文字を追加
po[ -1 ] = '.';
po[ 0 ] = '\0';
// 表示
printf( "入力単語数:%d\n", pos );
printf( "入力文字列:[%s]\n", in );
printf( "出力文字列:[%s]\n", out );
return 0;
}
以上。
No.3
- 回答日時:
ソースコード読んでみました。
やっていることは、後ろの単語からout[]にコピーしているのですが、次の問題点があります:
コピーする単語の位置を得る処理
in_ptr = in + (j + (wordcount - b));
ぱっと見て、jは単語の先頭位置かと思ったのですが、それでは(wordcount -b)の説明がつかない。結局、
j: 空白を除いた場合の文字の位置("this is a pen."の場合、'p'の位置を示す7)
(wordcount - b): その単語に遭遇するまでに存在するであろう空白の数
空白が2個ずつある"this__is__a__pen."の場合、、(_を空白と読み替えてください)
そうすると、空白が2個ずつ入っていた場合、外側のループ数は4回固定なのに対し、空白は6個です。空白を見つけるとそれで1単語のコピー処理ループを実行するため、最後まで処理を行いません。
また、空白を見つけると、その次の位置に単語が入っていると仮定してコピーを行うので、結局空白をそのまま出力してしまっています。
"this__is__a__pen."(2個ずつ空白)の出力結果は
" is__this "
となります。
単語の認識は"this", "", "is", ""となるため、
・最初の空白は、""のあとに追加される空白
・"is"と"this"の間の空白2個は、"is"の後に追加される空白と、""の後に追加される空白
・最後の空白は、"this"のあとに追加される空白
また、out[]の最後にヌル文字を入れていないので、文字列を出力するさい、後ろにゴミが表示されることがあります。
修正といっても、半分作り直しに近いです。
・bを削除する
・jは配列位置そのままとする
・out[]を削除する(直接出力するため、必要ない)
・in_ptr, out_ptrは削除する
アルゴリズムとしては、
jを文字列の最後尾位置に設定し、後ろから前に走査していく方法です。
最後の単語位置を取得し、その単語を出力
ループ開始
次の単語位置を取得し、単語位置が0以上なら、
空白とその単語を出力
そうでなければ、
ループ脱出
ループ終了
となります。
一番最後の単語とそれ以前の単語は分けて考えなければなりません。
なぜなら、「単語が見つかったら、出力し、空白を出力する」というアルゴリズムだと、一番先頭の単語が見つかった後も空白を出してしまうからです。
"this is a pen."だと"pen. ", "a ", "is ", "this "(thisの後に空白がついてしまう)となり、最後に空白がついてしまいます。
最後の単語はそのまま出力し、その後は「空白を出力→単語を出力」だと、
"pen.", " a", " is", " this"となり、最後の空白はなくなります。
プログラムは次のようになります:
j = strlen(in) - 1;
j = get_next_word(j); //次の単語の先頭位置を得る
print_next_word(j); //その位置の単語を出力する
while (1) {
j = get_next_word(j);
if (j >=0) {
printf(" ");
print_next_word(j);
} else {
break;
}
}
printf(".");
get_next_word()は改行文字の扱い、print_next_word()は改行、空白、ピリオドの扱いに注意が必要です。
最後に、がんばってください。
No.2
- 回答日時:
★コンパイルしてみました。
>しかし、今のプログラムでは、最初に空白が来たり、空白が連続すると正しく表示できません。
↑
本当だ。正しく表示されないね。
>どこを修正すればいいのか教えてください。
↑
コードを読みたくないよ。
だから新しいアルゴリズムをアドバイスします。
(1)単語の先頭をポインタの配列に代入。
(a)先頭のスペースを読み飛ばす
(b)単語の初めをポインタ配列にセット
(c)連続する英字を読み飛ばす
(d)(a)へ戻る
(e)『\0』が現れるまで繰り返す
(2)ポインタ配列の最後から順番に単語をコピー。
(a)ポインタ配列の最後から先頭に向け処理
(b)ポインタ配列の単語を別領域へコピー
(c)連続する英字をコピーしてその次に間のスペースをコピー
(d)ポインタ配列の1つ前を処理
(e)ポインタ配列の先頭を処理するまで繰り返す
(3)画面に表示。
(a)普通にprintfで表示
・上記の新しいアルゴリズムで作り変えてみるのはどうですか?
あとスペースの読み飛ばしには isspace() 関数を使ってみるのはどう?
英字文字の判定では isalpha() 関数を使う。
でもピリオド文字はどうしましょう?
工夫して下さい。
・以上。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# [至急]Project Euler:#17Number letter countsコード入力出力解説 2 2022/09/24 02:46
- Visual Basic(VBA) VBAでのMATCH関数 3 2022/10/17 19:06
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- 英語 英文の添削お願いします。【長文です。】 マッチングアプリで相手を言い負かしている時のやつです。 色々 1 2023/07/01 02:12
- Visual Basic(VBA) 【再々投稿】VBAのプログラムで動作しなくて困っています 8 2022/10/14 09:06
- TOEFL・TOEIC・英語検定 英語の質問です Buttonholes that were strong enough to kee 3 2022/06/12 19:52
- 英語 英語ができる方に質問です。 以下の文がネイティブの方に伝わるかどうかを確認していただけないでしょうか 7 2022/12/16 14:54
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CStringについて
-
CStringのFindで文字列検索を行...
-
strstrを利用しない文字列検索...
-
sscanfとscanfの違いがよくわか...
-
ブランクのチェック
-
C言語のステップ数をカウントす...
-
charと%c , %s の関係について
-
反転した数値を表示させるやり方
-
Cについて教えてください。
-
(C言語)関数の中で文字列比較で...
-
fgets関数を使用したときの文字...
-
Cで「大文字、小文字の判定」は...
-
あと少しなんですが・・・
-
C言語超超初心者です。学校の課...
-
文字列の途中に「0」がある場...
-
「Aに対するBの割合」と「Aに対...
-
2÷3などの余りについて
-
マイナスからプラスへ転じた時...
-
大学数学の問題です。 加法群Z/...
-
信頼区間の1.96や1.65ってどこ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
CStringのFindで文字列検索を行...
-
sscanfとscanfの違いがよくわか...
-
charと%c , %s の関係について
-
fgets関数を使用したときの文字...
-
反転した数値を表示させるやり方
-
fgetsで拾われる改行文字を削除...
-
C言語 空白の行(改行のみ)が...
-
itoaわかりません
-
Cで「大文字、小文字の判定」は...
-
文字列中に含まれる文字の個数...
-
C言語で16進数文字列から16進数...
-
strstrを利用しない文字列検索...
-
小文字のみを数える方法
-
C言語のステップ数をカウントす...
-
C言語でパスワード作成ツール
-
単語数のカウントについて
-
str[j++]の意味
-
fgetsでバッファ残留文字列を無...
-
教えていただけませんか?C言語...
-
エディットボックスに入力され...
おすすめ情報