C言語関係掲示板

過去ログ

No.1004 文字列の2次元配列の初期化

[戻る] [ホームページ]
No.930

文字列の2次元配列の初期化
投稿者---Nancy(2004/01/03 23:14:38)


ジャンケンポン・ゲームを作ろうと思って、手の文字列を作るため

文字列の2次元配列を初期化しようと思ったのですが、
以下のようにやってもうまくいきません。

char *hand[]={"グー","チョキ","パー"};

char hand[3][5]={"グー","チョキ","パー"};


マルチバイト文字ということもあって、

char hand[3][5]={
	{'',''},
	{'',''},
	{'',''}
	};


のようなことはできにくいと思うのですが、
どのようにしたらいいのでしょうか?


No.931

Re:文字列の2次元配列の初期化
投稿者---おでん(2004/01/04 01:28:16)


>
>文字列の2次元配列を初期化しようと思ったのですが、
>以下のようにやってもうまくいきません。
>
どううまく行かなかったのでしょう?
・・・できれば、コンパイル環境等書き込んだほうがいいと思いますが。

>char *hand[]={"グー","チョキ","パー"};

↑は、OKだと思います。

>
>char hand[3][5]={"グー","チョキ","パー"};
>
↑こちらは、"チョキ"が7バイト使うので出来ません。

No.932

Re:文字列の2次元配列の初期化
投稿者---RAPT(2004/01/04 01:37:14)


> char *hand[]={"グー","チョキ","パー"};
これは、(char *)型の配列なので、問題なく初期化されるはずですが。

> char hand[3][5]={"グー","チョキ","パー"};
これは、(char [5])[3] ... 「char 5 つである配列」が3つである配列
であり、"チョキ" を格納するには、char[7]の大きさが必要。よって、
char hand[3][7]={"グー","チョキ","パー"};
とすればコンパイルはとおります。

まぁ、初期化としては、
char hand[3][5]={
  {'\0','\0','\0','\0','\0'},
  {'\0','\0','\0','\0','\0'},
  {'\0','\0','\0','\0','\0'}
  };
こんなのも正しい初期化ではありますが。

文字コードがShift_JISであれば、
unsigned char hands[3][7]={
  {131,79,129,91,},
  {131,96,131,135,131,76,},
  {131,112,129,91,},
};
こんなこともできますね。無意味ですが。

Win2k/VC++6sp5 ConsoleAppで確認済。


No.933

Re:文字列の2次元配列の初期化
投稿者---Nancy(2004/01/04 11:01:32)


Nancyです。
回答して下さってありがとうございます。

コンパイラはVC++6.0です。
C++で作っていて、文字列の初期化はC言語と変わらないと思ってたので
投稿したのですが。
C言語の質問ではないので大変恐縮ですが、C++ではクラスの定義内での
メンバフィールドは宣言と同時に初期化はできないのでしょうか?

また、

>>
>>char hand[3][5]={"グー","チョキ","パー"};
>>
>↑こちらは、"チョキ"が7バイト使うので出来ません。

の7バイトはどのようにして分かるのでしょうか?


>文字コードがShift_JISであれば、
>unsigned char hands[3][7]={
> {131,79,129,91,},
> {131,96,131,135,131,76,},
> {131,112,129,91,},
>};
>こんなこともできますね。無意味ですが。

この文字コードの数値はどのように考えたら分かるのでしょうか?

すみませんが、教えていただけないでしょうか。


No.934

Re:文字列の2次元配列の初期化
投稿者---おでん(2004/01/04 13:13:11)


>C言語の質問ではないので大変恐縮ですが、C++ではクラスの定義内での
>メンバフィールドは宣言と同時に初期化はできないのでしょうか?
>

コンストラクタを使ってください。

>>>
>>>char hand[3][5]={"グー","チョキ","パー"};
>>>
>>↑こちらは、"チョキ"が7バイト使うので出来ません。
>
>の7バイトはどのようにして分かるのでしょうか?
>

全角文字(shift JIS,EUC-JP,UTF-8等の場合)一文字2バイトの
領域を使います。従って、

チ:2バイト
ョ:2バイト
キ:2バイト
\0:1バイト

という事です。

>
>>文字コードがShift_JISであれば、
>>unsigned char hands[3][7]={
>> {131,79,129,91,},
>> {131,96,131,135,131,76,},
>> {131,112,129,91,},
>>};
>>こんなこともできますね。無意味ですが。
>
>この文字コードの数値はどのように考えたら分かるのでしょうか?
>
そのままですね。

グ:0x834f→0x83→131

No.935

Re:文字列の2次元配列の初期化
投稿者---YuO(2004/01/04 16:06:37)


>>C言語の質問ではないので大変恐縮ですが、C++ではクラスの定義内での
>>メンバフィールドは宣言と同時に初期化はできないのでしょうか?

クラス定義時に初期化できるのは,staticかつconstな整数or列挙のメンバのみです。


>コンストラクタを使ってください。

クラスのメンバである配列はコンストラクタを利用して初期化できません。
全て,引数無しでのコンストラクタ呼び出しによる初期化又は不定値となります。
#故に,非staticメンバとして組み込み型のconst配列は実質的に利用できない。

唯一,
  • コンストラクタ
  • 非staticのprivate及びprotectedデータメンバ
  • 基底クラス
  • 仮想関数
の全てが無いクラスに関してはオブジェクトの定義時にCと同じように初期化することができるので,
配列も初期化できます。


>全角文字(shift JIS,EUC-JP,UTF-8等の場合)一文字2バイトの
>領域を使います。従って、

UTF-8において,Katakana(U+30A0 - U+30FF)は3バイトになります。
E3 83 81
E3 83 A7
E3 82 AD
\0
00


ちなみに,多バイト文字列としてISO-2022-JPを使うと,
1B 24 42 25 41
25 67
25 2D 1B 28 42
\0
00

のように可変長になります。

No.936

Re:文字列の2次元配列の初期化
投稿者---おでん(2004/01/04 16:47:15)


>>コンストラクタを使ってください。
>
>クラスのメンバである配列はコンストラクタを利用して初期化できません。

失礼、言葉が足りませんでした。
以下のような構文はありですよね?

#include <iostream>

class A{
    int siz ;
    char *hand[3] ;
public:
    A( ):siz(0){
        hand[0]= "グー" ;
        hand[1]= "チョキ";
        hand[2]= "パー";
        siz= 3 ;
    }
    const char * operator[](int pos ){
        return hand[pos] ;
    }
    int size() const { return siz ; }
} ;

int main()
{
    A a;
    
    for( int i= 0 ; i < a.size() ; i++ ){
        std::cout << a[i] << std::endl ;
    }

    return 0 ;
}


No.937

Re:文字列の2次元配列の初期化
投稿者---YuO(2004/01/04 20:02:25)


>失礼、言葉が足りませんでした。
>以下のような構文はありですよね?

「初期化」ではなく,代入はもちろん可能です。
ただ,C++において「初期化」と「デフォルト構築+代入」は全く別の話なので,
ちゃんと区別する必要があります。


問題点があるとすると,文字列リテラルをchar *で受けていることです。
Cと違い,C++において文字列リテラルはconst charの配列とされています。
Cとの互換性のため,文字列リテラルはchar *型に,ワイド文字列リテラルはwchar_t *型に,
それぞれ必要に応じて変換されますが,この動作は非推奨の動作とされています。
#つまり,const char *型を使うべきではないか,ということ。

ちなみに,この動作の差異は,例えば次のようなコード片で問題になります。
char * p = (n > 0) ? "Positive" : "Negative";

Cでは文字列リテラルはchar *型なので三項演算子はchar *型,よって正しい初期化になります。
それに対して,C++では文字列リテラルがconst char *型なので三項演算子はconst char *型,
よってconst char *でchar *を初期化しようとしているのでエラーになります。

個人的には,Cであっても文字列リテラルはconst char *で受けるべきかと。
#文字列リテラルを変更すると未定義動作なので,結局は変更できないから。


No.938

Re:文字列の2次元配列の初期化
投稿者---おでん(2004/01/04 20:45:54)


>
>「初期化」ではなく,代入はもちろん可能です。
>ただ,C++において「初期化」と「デフォルト構築+代入」は全く別の話なので,
>ちゃんと区別する必要があります。
>
はい、以後気をつけます。

No.939

Re:文字列の2次元配列の初期化
投稿者---Nancy(2004/01/05 23:26:33)


元質問者のNancy です。

私にとっては難しい領域に発展しましたが、返ってよい勉強になりました。
すべては理解できませんが、よく考えてみようと思います。

どうもありがとうございました。
また、質問することもあるかと思いますが、よろしくお願いいたします。