• ベストアンサー

char型の比較

C++で文字の比較をしたいのですが、コンソールアプリで   char str[3] = "困";   printf( "%x", str[0] ); と記述すると、"困"の文字コードは"8da2(Shift_JIS)"なので、   8d と表示されると思っていたのですが、実際は   ffffff8d と表示されます。 同じ理由で文字の比較をする際にも   str[0] == 0xffffff8d または   str[0] == (char)0x8d としなければ正しい結果が得られません。 これは何が原因なのでしょうか? よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
noname#140082
noname#140082
回答No.3

省略時解釈の問題になります。 まず基本事項として、(char)0x8dと(int)0xffffff8dは、どちらも10進数で「-3」となります。 「0xnn」の定義の場合、省略時にはint型と解釈されます。 ですから正確には0x8dは「0x0000008d」となります。 また、str[0]との比較は大きい方の方に拡張されて比較されます。 ですから、str[0]と0x0000008dとの比較は、int型での比較になります。 また、char型,int型はどちらも符号付き整数ですので、符号付き整数値(int型)に拡張されます。 つまり、str[0]に0x8dが入っている場合、先頭ビットが符号となりますので、0xffffff8dと拡張されます。 結果的にstr[0]==0x8dの比較は 0xffffff8d==0x0000008dの比較となりますので、同じ値とはなりません。 逆に「(char)0x8d」は、そのままchar型として比較されますので、同じ値として判定されます。

ClickHere
質問者

お礼

ご回答ありがとうございます。 >先頭ビットが符号となりますので、0xffffff8dと拡張されます。 拡張時に先頭ビットが関係していることは初めて知りました。 実際に試してみると確かにその通りの動作をしました。 1つ新しい知識が付きました。ありがとうございます。

その他の回答 (4)

  • 5S6
  • ベストアンサー率29% (675/2291)
回答No.5

1です。 普通のcだと文字列の扱いが不便ですよね。 失礼しました。 比較だけであればstrcmpを使うとか、Stringクラスであればそのまま比較できます。 あとはsprintfを使う手もありますよ。こちらは以外と使えます。 '\0'も注意しましょう。

ClickHere
質問者

お礼

再度のご回答、ありがとうございます。 この度のサンプルでは載せていませんが、当初の目的はShift_JISで全角・半角の 分別を行いたかったからです。 その為、文字列判定は殆ど使うことはないでしょうね~。 >普通のcだと文字列の扱いが不便ですよね。 >失礼しました。 いえいえ、失礼だなんてとんでもない! 回答して頂けるだけでもとても助かっています。 何かご縁がありましたら、またお助け頂けると嬉しいです。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

ただの char が符号付きか符号なしかは処理系に依存します. あなたが使っている処理系ではたまたま符号付きなのでこうなっているのでしょう. 符号なしの処理系があることも考えると, 書かれているように str[0] == (char)0x8d と明示的にキャストするか, あるいは str[0] == '\x8d' のように文字定数との比較にすることになるでしょう.

ClickHere
質問者

お礼

ご回答ありがとうございます。 '\x'というエスケープシーケンスがあるんですね。 char型にキャストするより打ち易いですが、可視性の面では微妙かもしれませんね。 選択肢の一つとして参考にさせて頂きました。

回答No.2

char型が符号付き8bitとして扱われているからでしょう。 その場合、0x8dは最上位ビットが1なので、負の数として扱われます。 printfに渡す場合は、char型からint型に昇格されるので、同値の負の数である0xffffff8dになってしまいます。 また、0x8dと比較する際も、そのままではintとの比較とみなされるため、同じ現象が起こるのだと思います。

ClickHere
質問者

お礼

ご回答ありがとうございます。 printf関数内では(他の関数・演算子内でも)変数の扱いが異なるんですね その点は初めて知りました。

  • 5S6
  • ベストアンサー率29% (675/2291)
回答No.1

%02x にしてみる

ClickHere
質問者

お礼

ご回答ありがとうございます。 せっかくのご回答を無下にしてしまうようで申し訳ありませんが、 printf関数のみの使用でしたら問題ないのですが printf関数を使用したのはあくまで値を確認する為ですので 変換指定子で制限しても根本的な解決には至りません。

関連するQ&A

  • char型+char型ってint型? if(char型==int型)?

    C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。 char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。 (下のプログラムの printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */ という部分の結果は4なので、int型と考えるべきなのかな。) 私は、char型とint型の加算の結果はint型だと思っていましたが、 char型とchar型の加算の結果はやはりchar型だと思っていました。 (それが間違えているのでしょうか。) if(a[0]==i) /* char型とint型の比較(?) */ の部分では、左辺はchar型、右辺はint型ですが、このように型の違う変数を比較しても文法上構わないのでしょうか。 (私は、「比較は必ず型の同じもの同士でしかできない」と思っていました。) 左辺はchar型のように見えて、じつはint型ですか。 #include <stdio.h> int main(void) { char a[4]; int i=77; printf("sizeof(int)は%d\n", sizeof(int)); printf("sizeof(char)は%d\n", sizeof(char)); printf("sizeof('M')は%d\n", sizeof('M')); printf("sizeof(a[0])は%d\n", sizeof(a[0])); a[0]='M'; a[1]=7+6; a[2]=a[0]+a[1]; printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */ printf("sizeof(+a[0])=%d\n", sizeof(+a[0])); if(a[0]==i) /* char型とint型の比較(?) */ puts("a[0]==i"); else puts("a[0]!=i"); return(0); } ちなみにワーニングもエラーもなんにもでません。

  • charと%c , %s の関係について

    char型の変数の扱いで悩んでいます。 具体的には以下の二つのプログラムの差異についてです。 ---------------------- char c; scanf("%c", &c); printf("%c\n", c); ----------------------- char c; scanf("%s", &c); printf("%s\n", &c); ----------------------- 上のプログラムは正しいと思うのですが、下のプログラムが正しいのかどうか、わかる方に教えていただきたいと思い質問させていただきました。 どちらのプログラムも問題なく動作します。 僕自身は 下のプログラムの printf 関数については間違った使い方なのではないかと思っています。 scanf("%s", &c) は入力された文字のうち、終端文字の手前までの文字を引数のポインタが示すオブジェクトへ順に格納していく関数だと理解しているので、入力された文字が一文字だった場合、&cの示すオブジェクトに文字が代入されると考えたからです。 逆に printf("%s", &c) は、&cの示すオブジェクトから”ヌル文字”の手前までの文字列を順に表示する関数だと理解しているので、問題なく動作しているのは&cで示されるオブジェクトの後ろの領域が偶然'\0'だったからではないかと考えたからです。 何かの本で、未使用の領域は0である確率が高いという記述をみたことがあり、'\0'は0と同じだということなので問題なく動作する率が高いのではないかと思っています。 僕の考え方がどの程度正しくて、正確にはどうなのかを教えて欲しいです。 ちなみに、 ----------------------- char c; char str[100]; scanf("%s", str); scanf("%c", &c); ------------------------ と書くと c には改行文字が代入されてしまいます。 scanf("%s", str); において"aasssdd "と最後に空白を入れると c には空白文字が代入されます。 しかし、 -------------------------- char str1[100]; char str2[100]; scanf("%s", str1); scanf("%s", str2); -------------------------- においては、 scanf("%s", str1); で "asdfg "と最後に空白を入れても次のstr2が空白で始まることはありません。 この辺りの処理がどのような法則で実行されているのかが分かりづらくて悩んでいます。 おそらく、 scanf("%s", str); の場合には最初の文字が空白や改行文字でも、その次に有効な文字があればそれらの改行や空白を無視するのではないかと思っています。 分かる方がいましたら回答をよろしくお願いします。

  • char型での演算子

    畏れ入ります。 X番目の文字を調べたいとき strにStringbufferで文字列が入っていた場合 if(str.charAt != "") とすることができません。 互換性のない型、と出てしまいます。 また、""を’’ とすると、「空の文字リテラルです」 と出てしまいます。 charが空であることを調べるのにはどうすればいいですか?

    • ベストアンサー
    • Java
  • char*型が0x0を含む場合

    char *str = {0x61, 0x62, 0x0, 0x64}; ができないから、 char *str = "abcd"; str[2] = 0; として、{0x61, 0x62, 0x0, 0x64} という文字列を作ってみた。 このポインタ str は解放する必要がない。 malloc( ) で確保したなら free( ) する必用がある。 普通のポインタは、もしかしたら 0x0 までしか 確保されていないのかなと思いました。 この場合では、str[3] == 0x64 だという結果になったけど、 それは str[2] の次のデータが 0x64 だったわけで、 str[2] に 0x0 が入った時点で、str[3] 以降の領域は str とは無関係かもしれないと思いました。 つまり、char*型は、0x0 までの部分だけを確保し、 この例のソースでは、str[3] 以降の領域は確保されていないから 後で、知らないうちに値が変わっている可能性がある。 という想像をしてみたけど、あってますか?

  • プログラミング ポインタを使った文字列比較

    プログラミング ポインタを使った文字列比較 2つの文字列str1, str2を入力し,それらが等しければ0,等しくなければ1を返す関数str_compareを作り、返り値によって以下のように表示するプログラムを作れ。ただし,関数strcmpを使ってはならない。 文字列の入出力はmain関数で行い,関数str_compareの仮引数にはポインタ変数を宣言し,ポインタと間接演算子*を用いた処理を行うこと。 % ./a.out input str1 = Worldcup input str2 = Worldcup same strings % ./a.out input str1 = World input str2 = cup different strings この問題に私は次のようにプログラミングしました。 #include <stdio.h> #define MAX 100 int str_compare(char *, char *); main() { char str1[MAX], str2[MAX]; printf("input str1 = %s", str1); scanf("%s", str1); printf("input str2 = %s", str2); scanf("%s", str2); str_compare(str1, str2); if (str_compare(str1, str2) == 0) printf("same strings\n"); else if (str_compare(str1, str2) == 1) printf("different strings\n"); } int str_compare(char *s1, char *s2) { int i; for (i = 0; s1[i] != '\0'; i++) { if (s1[i] != s2[i]) { break; } } if (s1[i] == s2[i]) { return 0; } else { return 1; } } これで実行したところ、「input str1 =」の右のスペースが文字化け?してしまいます。(半角カタカナや記号が出る)ただ、その後に文字列を入力すると、正しく機能します。 これは何が悪いなのでしょうか、どなたか教えてください。

  • 文字列比較

    最長10文字の文字列を2件入力し、char型の配列にそれぞれ格納する。2つの文字列を比較し、文字列が同じだったら「equal」を表示し異なっていたら「Not equal」を表示するプログラムを作成せよという課題が出ました。 条件として、11文字以上の文字が入力されたら、先頭から10文字までを有効とし、11文字目以降を無視する。下記のプログラムで文字列1に11文字以上入力すると、うまく動きません。なぜ、うまくいかないかと、どうなおしたらよいかを教えてください。 #include<stdio.h> #include<string.h> #define max_length 10 void get_string (char *p_str, int size); int main() { char string1[max_length+2]; char string2[max_length+2]; printf("文字列1:"); get_string(string1,max_length+2); printf("文字列2:"); get_string(string2,max_length+2); if(!strncmp(string1,string2,max_length)) puts("equal"); else puts("Not equal"); } void get_string (char *p_str, int size) { fgets(p_str,size,stdin); }

  • ポインタ

    質問なのですが、このソースのchar *str_copy(char *d, const char *s)関数内のchar *p=d;はなんで、*pにdを入れるか分かりません。それと、このdは、*dなのですか?どうして、while (*d++ = *s++) みたいに*dをつけないんですか?教えてください。宜しくお願いします。 #include <stdio.h> char *str_copy(char *d, const char *s) { char *p=d; while (*d++ = *s++) ; return (p); } int main(void) { char tmp[100]; char st1[100], st2[100],st3[100]; printf("文字列を入力してください:"); scanf("%s",tmp); str_copy(st1,str_copy(st2,tmp)); printf("文字列st1は%sです。\n", st1); printf("文字列st2は%sです。\n", st2); printf("文字列st3は%sです。\n", str_copy(st3,tmp)); return (0); }

  • 変数と日本語文字列を比較する方法とは?

    いつもお世話になっております。 変数と日本語を比較する簡単な方法を教えてください。 <input type="submit" name="update" value="更新"> という更新ボタンをJSPから押すと、 public void doPost(HttpServletRequest request,HttpServletResponse) request.setCharacterEncording("Shit_JIS"); request.setContencType("text/html; charset=Shift_JIS"); String str = getParameter("name"); System.out.println("s="+ s);  で、str=更新という値を取得します。 このあと、 if(str=="更新")  { 更新用サーブレットへ }   else { それ以外の処理へ } としたいのですが、str=="更新"の比較ができず、if文が機能しませんでした。 コンソールへは「s=更新」と出力できるのですが。 日本語文字列の比較の問題と思うのですがリクエストの文字コードをShift-JISに設定するだけでは対応できないものなのでしょうか? どうぞよろしくお願いいたします。

    • ベストアンサー
    • Java
  • MySQLの関数でCHARと言うのがありますが、この関数に与えられる数値は0x0000から0x1ffffffffで良いのでしょうか?

    MySQLの関数でCHARと言うのがありますが、この関数に与えられる数値は0x0000から0x1ffffffffで良いのでしょうか? 実験したこと: SELECT CHAR( 0x200000000 ); ↑空白文字が返ってくる。 SELECT MD5(CHAR(0x0000)), MD5(CHAR(0x0001)); ↑この二つは異なった暗号文字列を返す。 SELECT MD5(CHAR(0x1fffffffe)), MD5(CHAR(0x1ffffffff)); ↑この二つは異なった暗号文字列を返す。 ※サーバはshift_jis コード表に沿った文字を返してくる。 CHARには保障された下限値、上限値があるのでしょうか? サーバー等、環境に左右されるのですか? 左右されない下限値、上限値はありますか? 以上、宜しくお願いします。

    • ベストアンサー
    • MySQL
  • 文字列の検索

    プログラミングの勉強の際に下のプログラムを作りました。 最初にある文字列を入力して、その後別の文字列を入力して、 後に入力した文字列が最初に入力した文字列に含まれていれば1、 含まれていなければ0と表示するプログラムです。 コンパイルは通るのですが、文字列を2つ入力すると 「セグメンテーション違反です」と表記されます… どこが悪いのでしょうか? どなたか解説・指摘・模範解答などおねがいします。 (使用するのは#include<stdio.h>のみ、ポインタ変数必須です) #include<stdio.h> char *mystrfin(char *a, char *b); int main(void) { char str1[100],str2[100]; printf("1>>"); fgets(str1,100,stdin); printf("2>>"); fgets(str2,100,stdin); *mystrfin(c,d); } char *mystrfin(char *a,char *b){ char *c,*d; while(*c!='\0'){ c=a; d=b; while(*c!='\0' && *d!='\0') if(*c!=*d) printf("0"); break; c++; d++; } if(*d='\0') printf("1"); a++; return a; return NULL; }

専門家に質問してみよう