ページ 1 / 1
連続した文字列の位置
Posted: 2009年5月13日(水) 14:27
by 研修生
getcharで入力した文字列の中に連続した2個以上の連続した空白がある場合1つの空白に置き換えるプログラム
を作っている所ですが・・getcgarで入力した1行の文字列の中の連続した空白の始まりの位置を終わりの位置について
導きだせないのでおしえてください。
例
s=a○○○aのときs[1]の1が始めの位置で終わりはs[3]の3です。この数字2つを求めたいのですが
char s[1000];
int c, x;
//入力した文字を配列sにいれる
for(int i=0; i<(c = getchar()) != EOF && c != '\n'; ++i){
s = c;
}
//位置を探す
for(int j=0; j<i; j++){
if(s[j] == s[j + 1] && s[j] ==' '){
x = j;
}
}
まだ全然できていないんですがここからわかりません・・
位置を探すプログラムですが例えばa○○aなら正しく動くんですが
a○○○aやそれ以上の空白があるとxの値が更新されうまくいきません。
多分やり方がおかしいと思います。どのようにすれば導き出せるか教えて下さい。
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 14:43
by GPGA
前のプログラムのときから気になっていますが、for文のループ継続条件の
i<(c = getchar()) != EOF
の意味を、きちんと理解していますか?
1, c = getchar()を実行する
2, i < c を実行する。この結果を仮にxとする
3, x != EOF を実行する。
ということをやっているのですよ。
以下、位置を求めるプログラム。
最終目的の空白を詰めるのに役立つかどうかは別。
#include <stdio.h>
#include <string.h>
int main()
{
const char* s = "a a b b c";
const int len = strlen(s);
int cnt = 0;
for (int i = 0; i < len; ++i) {
if (s == ' ') {
if (cnt == 0) {
cnt = i;
printf("空白開始ポイント:%d\n", cnt);
} else {
++cnt;
}
} else {
if (cnt != 0) {
printf("空白終了ポイント:%d\n", cnt);
}
cnt = 0;
}
}
}
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 14:55
by Mist
私の会社の新人研修と同じ問題でびっくり。
> 連続した2個以上の連続した空白がある場合1つの空白に置き換える
この仕様を満たせばいのであればこんなめんどくさいことはしないです。
「//入力した文字を配列sにいれる」の部分で「今読んだ文字が空白の場合、ひとつ前の文字が空白だったら配列に入れない」とすればいいだけです。
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 16:22
by 研修生
そんなやり方もあったんですね。それでちょっとくんでみたら
int main()
{
int i,c;
char s[1000];
for(i = 0; i < (c= getchar()) != EOF && c!= '\n'; ++i){
if(c == ' ' && s == ' '){
;
}
else{
s = c;
}
}
printf("%s", s");
return 0;
}
これうまくいかないんですがどこかおかしいでしょうか?
デバッグでみればわかるかもなのですが超絶ド素人の為ステップインしていくと
for(i = 0; i < (c= getchar()) != EOF && c!= '\n'; ++i){
のところで下記画像のようなのがでてきてしまいます。
開発環境はVisualC++ 6.0です。
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 16:24
by 研修生
これのせいで中身が上手く見れません・・
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 16:27
by 御津凪
おそらく、ステップインで getchar() の中に入っていませんか?
(ソースデータが見つからないのでこのようなダイアログが出ます)
ステップオーバーで進めると、関数の中には入らないようになります。
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 16:38
by 研修生
デバッグはできました・・ ありがとうございます。
見るとa○○aを入力すると
i=2のときにifに入ってませんね・・
値は一致してるのになんでだろ・・
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 16:43
by Mist
> s
うん、何となくこの失敗するような気がしてました。
iは0から始まるからi=0のときs[-1]を参照することになります。
範囲外アクセスです。
ヒント:最初の一文字目が「空白が連続した場合」という条件にヒットすることはありえるでしょうか。
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 16:48
by Mist
あと、GPGAさんの指摘をもう一度よく読みなおして。
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 17:06
by 初級者
こんな感じ?
#include <stdio.h>
enum { NON_BLANK, BLANK, BLANKS };
int main(void)
{
int c, mode = NON_BLANK;
while ((c = getchar()) != EOF) {
if (c != ' ') {
switch (mode) {
case BLANK: case BLANKS:
putchar(' ');
/* fall thru */
case NON_BLANK:
putchar(c);
mode = NON_BLANK;
break;
}
}
else {
switch (mode) {
case NON_BLANK:
mode = BLANK;
break;
case BLANK: case BLANKS:
mode = BLANKS;
break;
}
}
}
return 0;
}
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 17:07
by 研修生
for(i = 0; i < (c = (getchar() != EOF)) && c != '\n'; i++)
にしろってことかな・・ なんかおかしいのはわかったきがする・・
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 17:25
by 御津凪
> for(i = 0; i < (c = (getchar() != EOF)) && c != '\n'; i++)
これでは、
"getchar() != EOF" で比較した結果(真偽値)を c に代入し、
それ( c )と i の比較をする、
という処理順序になります。
これだと c に入力した文字が入りませんし、正しくループされません。
for(i = 0; i < 1000 && (c = getchar()) != EOF && c != '\n'; i++)
が、正しいかと思います。
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 17:30
by 研修生
初級者さんの提示されたプログラムだとちゃんとできました。ありがとうございました。
自分が今までやってきた方法でもやってみようとおもいます。
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 17:34
by 研修生
そういうことか・・
確かにcに文字が入らないですね
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 17:48
by 初級者
あのソースはどういう考え方によって書いてあるのかを、よく吟味してください。
「動いた~」だけではダメですよ。
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 18:02
by 研修生
それなんですよ。じっくりデバッグで辿っていくと正しいプログラムだというのはわかります。
しかしこれが自分で思いつけるか?といったら少し厳しい気がします。
どういう発想で作ったのか理解していくのが大事なのかな
Re:連続した文字列の位置
Posted: 2009年5月13日(水) 18:29
by 初級者
【考え方】
今、自分がどういう状態にいるか(モード)の概念を導入します。
モードには次の3種類があります。
1)非空白モード(NON_BLANK、初期値)
2)1文字空白モード(BLANK)
3)連続空白モード(BLANKS)
各々のモードに対して、入力した1文字が非空白か空白かが対応します。
入力文字とモードの組合せは、下表の6とおりあります。
あのソースは、下表をそのままコード化しただけです。
+-----------+-----------+----------------+----------------+
| モード | 非空白 | 1文字空白 | 連続空白 |
| | NON_BLANK | BLANK | BLANKS |
|入力 | | | |
+-----------+-----------+----------------+----------------+
| | そのまま | 空白&そのまま | 空白&そのまま |
| 非空白 | 出力して | 出力して | 出力して |
| | NON_BLANK | NON_BLANK | NON_BLANK |
| | モードへ | モードへ | モードへ |
+-----------+-----------+----------------+----------------+
| | 何も | 何も | 何も |
| 空白 | 出力せず | 出力せず | 出力せず |
| | BLANK | BLANKS | BLANKS |
| | モードへ | モードへ | モードへ |
+-----------+-----------+----------------+----------------+