質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.91%

→以降の文字列のみを表示できたのですが、文字化けしてしまいます。

受付中

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 595

KZK13

score -9

環境は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;

}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+10

この回答は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についてのリファレンスを見てみましょう。

文字定数 - cppreference.com

'文字'という表現は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()です。リファレンスを見てみましょう。

strchr - cppreference.com

'→'intですので型としては問題ないように思いますが、注意事項があります。

...内の ch ((char)ch によって行われたかのように char に変換した後) が...

この一文です。つまり、intを受け取るが、実際は(char)chcharにキャストするかのようになります。(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以外の文字、つまりは漢字や平仮名といった普通の日本語の文字ですら正しく扱うことはできません。皆さん、日本語は注意して扱いましょうね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

元のソースと比較して見ましょうv^^

#include <stdio.h>
#include <string.h>

int main( )
{

    char str1[128] = "範馬裕次郎→最強";

    char str2[128];

    char *p;

    p = strstr(str1, "→");  //ここで→以降の文字をbuffer3に入れる。

    strcpy(str2, p);

    printf("%s\n%s\n", str1, str2);

    return 0;
}


結果

usr ~/Project/test % ./a.out
範馬裕次郎→最強
→最強

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/05 09:01

    Visual Studio2019だと、Warningは出ないようですね。この辺は、raccyさんの回答にありますね。(初心者マークへの回答としては? ですが)
    C言語の場合、半角英数以外の扱いは要注意(元々、考慮されていない)と言うのが、ポイントでしょうか。

    キャンセル

  • 2020/07/05 13:21

    特殊な例ですが、strstr でダメな場合があります。
    "範馬裕次郎→最強" を "風吹ィチロウ→最強" に変えてみてください。
    'ィ' は半角の小文字の「ィ」です。

    キャンセル

  • 2020/07/05 14:15 編集

    UTF-8環境では問題なしです。>kazuma-sさん
    usr ~/Project/test % ./a.out
    風吹ィチロウ→最強
    最強

    キャンセル

0

バイト単位で比較する strstr ではなく、
文字単位で比較する sjis_strstr を作ってみました。

#pragma warning(disable: 4996)
#include <stdio.h>
#include <string.h>   // strlen, strncmp, strcpy
#include <windows.h>  // IsDBCSLeadByte

char *sjis_strstr(const char *s1, const char *s2)
{
    for (int n = strlen(s2); *s1; s1 += IsDBCSLeadByte(*s1) ? 2 : 1)
        if (strncmp(s1, s2, n) == 0) return (char *)s1;
    return NULL;
}

int main()
{

    char str1[128] = "範馬裕次郎→最強";
    char str2[128];
    char* p;
    p = sjis_strstr(str1, "→");
    strcpy(str2, p);
    printf("%s\n%s\n", str1, str2);

    char str3[] = "風吹ィチロウ→最強";
    p = sjis_strstr(str3, "→");
    strcpy(str2, p);
    printf("%s\n%s\n", str3, str2);

    return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る