- ベストアンサー
ポインタを使って回文かどうかチェックしたい
タイトルの通り、ポインタを使って 回文(前から読んでも後ろから読んでも同じってやつです) であるかどうか判断するプログラムを 作りたいのですが、 どうしてもうまく行きません。どうしたらいいでしょうか。 今の所こんな感じです #include <stdio.h> int main(void) { char string[256]; char *checkA, *checkB; printf("Input String >> "); scanf("%s", string); for(checkA = string; *checkA != '\0'; checkA++){ ; } checkB = string; for(checkA = checkA - 1; checkA <= 0; checkA--){ *checkB = *checkA; checkB++; } if(*checkA == *checkB){ printf("%s は左右対称です。\n", string); } else{ printf("%s は左右対称ではありません。\n", string); } return 0; }
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
おはようございます. 終了処理が怪しい為に一寸危険な感じになってますね. ここでは,以下の方針を使います. (1)文字列の長さの取得はstrlen()を使う (2)ヌル文字での終端を保証するためにfgets()を使う (3)前から走査するポインタと逆に走査するポインタで一文字づつ比較. 実装例として以下のような感じでどうでしょうか. この場合,長さが奇数なら「真ん中の文字」を同時に参照した段階で止まります. 長さが偶数なら「となり同士の文字」で止まります. 参考までに. #include <stdio.h> #include <string.h> #define MAX_STR 256 int main(void) { char string[MAX_STR]; char *checkA, *checkB; int len, isanag; printf("Input String >> "); fgets(string, MAX_STR, stdin); /* scanfは安全じゃない */ len = strlen(string); /* 長さを取得 */ /* 文字列の長さが奇数なら自動的に終了する */ /* checkAは先頭から,checkBは最後尾から始める */ for(checkA = string, checkB = string + (len - 1), isanag=1; (checkA !=checkB); checkA++, checkB--){ if(*checkB != *checkA){ isanag = 0; break; /* 途中一文字でも違ったら終了 */ } if((checkA+1)==checkB){ break; /* 文字列の長さが偶数の時の終了処理 */ } } if(isanag){ printf("%s は左右対称です。", string); } else{ printf("%s は左右対称ではありません。\n", string); } return 0; }
その他の回答 (8)
- nda23
- ベストアンサー率54% (777/1415)
#8です。ポインタを使うんでしたね。以下のように直してください。 static BOOL iskaibun(char *p) { if ( p == NULL ) return FALSE; //NULLポインタの場合 WCHAR uni[256]; //UniCode取得用の領域 int a = MultiByteToWideChar(0,0,p,-1,uni,256) - 1; if ( a <= 1 ) return FALSE; //有効字数が1以下の場合 WCHAR *seq = uni; //順方向のポインタ WCHAR *rev = &uni[a - 1]; //逆方向のポインタ for ( a /= 2 ; a > 0 ; a-- ) { //字数の半分の回数 if ( *(seq++) != *(rev--) ) return FALSE; } return TRUE; }
- nda23
- ベストアンサー率54% (777/1415)
漢字を考慮する必要があります。 考え方として、UniCode化してから比較すると楽です。 #include <windows.h> static BOOL iskaibun(char *p) { if ( p == NULL ) return FALSE; //NULLポインタの場合 WCHAR uni[256]; //UniCode取得用の領域 int a = MultiByteToWideChar(0,0,p,-1,uni,256) - 1; if ( a <= 1 ) return FALSE; //有効字数が1以下の場合 for ( int b = 0 ; b < a ; b++ ) { if ( uni[b] != uni[--a] ) return FALSE; } return TRUE; } int main(void) { == 略 == if ( iskaibun(string) ) { printf("%s は左右対称です。\n", string); } else { printf("%s は左右対称ではありません。\n", string); } == 略 == ★インデントに漢字空白を使っています。コピペ注意 MultiByteToWideCharは終端のNULL文字も字数として返すので、1を 減じてから使います。aは順方向、bは逆方向のインデックスです。 NULLポインタ、空文字列、1文字だけの場合はFALSEが返ります。 http://msdn.microsoft.com/ja-jp/library/cc448053.aspx
- yaemon_2006
- ベストアンサー率22% (50/220)
何度も申し訳ない。 k = (isalpha(*s) != 0) に再度訂正。
- yaemon_2006
- ベストアンサー率22% (50/220)
k = (isalpha(*s) != 0) は、 k = 0 に訂正。
- yaemon_2006
- ベストアンサー率22% (50/220)
#include <stdio.h> #include <string.h> #include <ctype.h> int kaibun(unsigned char *s) { unsigned char *p = s + strlen(s) - 1; int i, j, k = (isalpha(*s) != 0); while(s < p){ i = isalpha(*s); j = isalpha(*p); k |= (i || j); if(i && j){ if(toupper(*s ++) != toupper(*p --)) return 0; } else{ s += !i; p -= !j; } } return k; } int main(void) { const char *result[] = {"回文ではありません。", "回文です。"}; char s[128]; scanf("%127[^\n]%*[^\n]%*c", s); puts(result[kaibun(s)]); return 0; }
- echoes_x86
- ベストアンサー率65% (21/32)
一寸間違えました. 読み込み部分を以下のようにしないと駄目です. fgets(string, MAX_STR, stdin); /* scanfは安全じゃない */ checkA = string; /* 改行文字を潰す */ strsep(&checkA, "\n"); こうしないと,常に「先頭の文字」と「改行文字」が比較されてしまいます. 失礼いたしました.
お礼
投稿ありがとうございます>< ちょこちょこまだテキストに出てこない部分がありましたが、 すごい参考になりました!!
こんにちは。 別なやり方として /* ポインタを使って前後が逆になっている文字列を作成する */ /* 元の文字列と逆の文字列とを文字列比較する */ ご参考までに。
- D-Matsu
- ベストアンサー率45% (1080/2394)
どう「うまくいかない」のかを書きましょう。まぁ現状ではSegmentation Faultだと思いますが。 > for(checkA = checkA - 1; checkA <= 0; checkA--){ ループ終了条件が間違っているので、checkAがstringの先頭に到達しても終了せず更に前に行ってしまいます。 > *checkB = *checkA; 元文字列のstringを壊してます。また上記の通りループ終了条件が間違っているのでstringの終端に到達しても止まりません。 > if(*checkA == *checkB){ 「文字列」の比較に論理演算子==は使えません。
お礼
僕の書いた奴だと先頭の文字だけ比較していたので thatのようなものでもthatのtが同じだから 回文扱いされていました。 文字列の比較には==使えないんですか; 他の方がされているように 一文字一文字確認しないといけないですね;
お礼
ユニコードを使う方法もあるんですね。 参考になりましたありがとうございます><