環境はWindows10、visual stuido 2019です。
「範馬裕次郎→最強」という文字列で→以降の文字列のみを表示できたのですが、以下のように文字化けしてしまいます。
C:\Users>C:\Users\source\repos\ConsoleApplication3\x64\Release\ConsoleApplication3.exe 範馬裕次郎→最強 ィ最強
以下がコードです。
#pragma warning(disable: 4996) #include <stdio.h> #include <string.h> int main() { char str1[128] = "範馬裕次郎→最強"; char str2[128]; char* p; p = strchr(str1, '→');//ここで→以降の文字をbuffer3に入れる。 strcpy(str2, p); printf("%s\n%s", str1, str2); return 0; }
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
この回答はCおよび一般的な文字コードの知識を前提とし、この質問を読んだ質問者以外の人が参考するために記載しています。申し訳ありませんが、質問者には理解できない部分が多数あると思われますので、あらかじめご了承ください。
Visual Studio 2019のC++コンパイラ(cl.exe、以下cl)は、標準で、実行環境で設定されている言語でのANSI文字コードを内部文字コードに設定します。日本語環境であれば、Windows-31J(CP932)です。これは、ソースコードがWindows-31J、BOM付きUTF-8、BOM付きUTF-16LE、BOM付きUTF-16BEのいずれであっても同じです(文字コード認識のためにUTF-8であってもBOMは必須です。これ以外の文字コードをclは自動認識できません)。ですので、Windows-31Jでどうなっているかを確認していく必要があります。
問題は下記の部分です。
p = strchr(str1, '→');//ここで→以降の文字をbuffer3に入れる。
buffer3
が何を意味しているのか不明ですので、コメントは無視します。'→'
がいくつになるのかを確認しなければなりません。
まずは一般的なCについてのリファレンスを見てみましょう。
'文字'
という表現はchar
型の値を扱うための文字リテラルです。リテラルの型自体はint
ですが、それはchar
での文字がそのままマッピングしたものとなります。このとき注意しなくてはならないのはchar
一つで表せない文字だったときの動作です。'A'
(41)や'ア'
(B1)のようにWindows-31Jでchar
一つで表現できる文字は問題ありませんが、'あ'
(82 A0)のようないわゆる2バイト文字はchar
一つで表現できません。この場合、リテラルが何になるのかは処理系定義となっています。
と言うことでMSDNでMicrosoftの処理系ではどうなっているのかを見てみましょう。
文字列リテラルと文字リテラルC++() | Microsoft Docs
cppreferenceの説明とちょっと違う部分がありますが、どうやら、マルチバイト文字であってもそのまま上位からくっつけて、int
にするようです。シングルバイトでの文字が複数の場合でもint
に収まる限りはそのまま上位から下位までの一つの文字として扱うとなっています。
|文字リテラル|Windows-31J|リテラル値|バイト表示|
|---|---|---|
|'A'
|41|65|00000041|
|'ア'
|B1|-79|FFFFFFB1|
|'あ'
|82 A0|33440|000082A0|
|'→'
|81 A8|33192|000081A8|
'ア'
のように上位ビットがあるとMicrosoftの処理系ではchar
が負の値になるため、int
としては負の値になることに注意してください。
これで'→'
が33192
であることが分かりました。次はstrchr()
です。リファレンスを見てみましょう。
'→'
はint
ですので型としては問題ないように思いますが、注意事項があります。
...内の ch (
(char)ch
によって行われたかのようにchar
に変換した後) が...
この一文です。つまり、int
を受け取るが、実際は(char)ch
とchar
にキャストするかのようになります。(char)33192
は-88
です。16進数ですとA8となります。strchr()
は各文字をunsigned char
として解釈しくいき、その中でA8のバイトがあるところを探すとなります。検索対象の文字列をバイト表記にすると次のようになります。
str1 範 馬 裕 次 郎 → 最 強 94 CD 94 6E 97 54 8E 9F 98 59 81 A8 8D C5 8B AD ↑
ここがp
です。ここまで来れば分かりますね。strcpy()
でp
以降をコピーとなりますので、str2
は次のようになると言うことです。
str2 ィ 最 強 A8 8D C5 8B AD ↑
Windows-31Jで(A8)のみは"ィ"です。よって最終的に表示されるのも"ィ最強"となるわけです。
strchr()
関数や'文字'
リテラルはASCIIのみといったシングルバイト文字を前提に作られています。Windows-31Jのようなマルチバイト文字の場合は想定した通りの動作はできません。ASCII以外の文字を扱いたい場合は、ワイド文字やUnicode文字を使う、文字列として処理するなどしないとむずかしいでしょう。ただ、ワイド文字であってもUTF-16の場合はサロゲートペアという罠があるため、絵文字だけ文字化けとかのバグが起きる場合があります。
内部文字コードがUnicodeに統一されていて一つの方法ぐらいしか用意されていない他言語と違い、Cでは様々な文字コードを直接バイト列として扱えたり、マルチバイト文字としてもさまざまな手段が用意されています。その分、文字コードの正しい知識が無いと、ASCII以外の文字、つまりは漢字や平仮名といった普通の日本語の文字ですら正しく扱うことはできません。皆さん、日本語は注意して扱いましょうね。
投稿2020/07/04 22:23
編集2020/07/05 04:54総合スコア21739
0
元のソースと比較して見ましょうv^^
c
1#include <stdio.h> 2#include <string.h> 3 4int main( ) 5{ 6 7 char str1[128] = "範馬裕次郎→最強"; 8 9 char str2[128]; 10 11 char *p; 12 13 p = strstr(str1, "→"); //ここで→以降の文字をbuffer3に入れる。 14 15 strcpy(str2, p); 16 17 printf("%s\n%s\n", str1, str2); 18 19 return 0; 20}
結果
text
1usr ~/Project/test % ./a.out 2範馬裕次郎→最強 3→最強 4
投稿2020/07/04 20:25
編集2020/07/04 20:29総合スコア6851
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/07/04 20:59
2020/07/04 21:07
2020/07/04 21:20
2020/07/04 21:22
2020/07/04 21:29
2020/07/05 00:01
2020/07/05 04:21
2020/07/05 05:18 編集
0
バイト単位で比較する strstr ではなく、
文字単位で比較する sjis_strstr を作ってみました。
C
1#pragma warning(disable: 4996) 2#include <stdio.h> 3#include <string.h> // strlen, strncmp, strcpy 4#include <windows.h> // IsDBCSLeadByte 5 6char *sjis_strstr(const char *s1, const char *s2) 7{ 8 for (int n = strlen(s2); *s1; s1 += IsDBCSLeadByte(*s1) ? 2 : 1) 9 if (strncmp(s1, s2, n) == 0) return (char *)s1; 10 return NULL; 11} 12 13int main() 14{ 15 16 char str1[128] = "範馬裕次郎→最強"; 17 char str2[128]; 18 char* p; 19 p = sjis_strstr(str1, "→"); 20 strcpy(str2, p); 21 printf("%s\n%s\n", str1, str2); 22 23 char str3[] = "風吹ィチロウ→最強"; 24 p = sjis_strstr(str3, "→"); 25 strcpy(str2, p); 26 printf("%s\n%s\n", str3, str2); 27 28 return 0; 29}
投稿2020/07/05 04:36
総合スコア8224
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。