ページ 11

変数に文字を代入できません

Posted: 2011年4月16日(土) 15:41
by 細胞
c言語のアドレスや文字列について勉強しようと思い、いろいろなサイトから、プログラムをコピペしたりして遊んでいたのですが、少しわからないところがありました。

ーーーーー変数aに文字を代入してprintfで表示させるプログラムーーー
#include <stdio.h>

int main(){
char a;
a = 'む'; /* aに'む'を代入 */
printf("%c\n",&a);
return 0;
}

ーーーーーーーーー実行結果ーーーーーーーーーーー

続行するには何かキーを押してください . . .
ーーーーーーーーーーーーーーーーーーーーーー

ほかの文字を試してみたのですが、でたらめな文字ばかりが出てきます。
どういうことなのか教えてください。よろしくおねがいします。

OSはwindousで
visual c++を使っています

Re: 変数に文字を代入できません

Posted: 2011年4月16日(土) 15:53
by softya(ソフト屋)
幾つか問題があります。
・コンパイラや環境に依存しますが、文字コードとして、ただcharだけの場合は英数字=1バイト文字しか扱えませんので漢字のような多バイト文字は扱えません。
・文字表示なのにアドレスを渡しています。変数をそのまま書いてください。

英数字なら問題ありませんので、下記のようにしてみてください。

コード:

#include <stdio.h>
int main(){
	char a;
	a = 'm'; /* aに'm'を代入 */
	printf("%c\n",a);//aの文字を表示
	return 0;
}
codeタグをご利用下さい。ソースコードが見やすくなります。
詳しくはフォーラムルールを御覧ください。

Re: 変数に文字を代入できません

Posted: 2011年4月16日(土) 16:06
by たかぎ
やりたいことは、もしかしてこういうことなのかも知れませんね。

コード:

#include <stdio.h>
#include <locale.h>

int main(){
  wchar_t a;
  a = L'む';	 /* aに'む'を代入 */
  setlocale(LC_CTYPE, "");
  printf("%lc\n",a);
  return 0;
}

Re: 変数に文字を代入できません

Posted: 2011年4月17日(日) 00:29
by 細胞
つまり、全角文字は2バイト使うから、char型の1バイトしか代入できない変数に代入できないということですね。

あと、これでもできました。

コード:

#include <stdio.h>

int main(){
        char* a;	//ポインタ変数
        a = "む";		/* aに'む'のアドレスを代入 */
        printf("%s\n",a);
        return 0;
}

Re: 変数に文字を代入できません

Posted: 2011年4月17日(日) 08:04
by box
a が char 型の配列である場合はどうなるでしょうか?

Re: 変数に文字を代入できません

Posted: 2011年4月17日(日) 10:32
by 細胞
返信ありがとうございます。(お礼いうの忘れていました)

えーとですね、さっき自分がやったのが、aをポインタ変数にして、’む’のアドレスを代入したのに対して、
aをchar型の配列ってことは、1バイトのchar型変数を置くメモリが、複数確保されたってことですよね

コード:

#include <stdio.h>

int main(){
        char a[10];	//配列変数
        a[0] = 'S';		/* aに'A'を代入 */
        a[1] = 'O';		/* aに'A'を代入 */
        a[2] = 'N';		/* aに'A'を代入 */
        a[3] = 'G';		/* aに'A'を代入 */

        printf("%c%c%c%c\n",a[0],a[1],a[2],a[3]);
        return 0;
}
1バイトの配列でも、ひらがなや漢字などの2バイトの文字は扱えないですよね?

ここまでのことに間違えてることがあったら教えてください。お願いします

Re: 変数に文字を代入できません

Posted: 2011年4月17日(日) 11:08
by softya(ソフト屋)
細胞 さんが書きました:1バイトの配列でも、ひらがなや漢字などの2バイトの文字は扱えないですよね?

ここまでのことに間違えてることがあったら教えてください。お願いします
多バイト文字を扱う方法の一つがたかぎさんが示されたワイド文字を使う方法です。
あと2バイトと決め付けられているみたいですが、文字コードによっては2バイト以上の文字コードもあります。
例えば、UNICODEとSJISは2バイトですがUTF-8は2バイトを超えることがあります。UNICODEの場合は1バイトの文字コードがありません。

ちなみに上のコードは下記のようにすれば文字列として出力できます。

コード:

#include <stdio.h>
 
int main(){
        char a[10]; //配列変数
        a[0] = 'S';     /* aに'A'を代入 */
        a[1] = 'O';     /* aに'A'を代入 */
        a[2] = 'N';     /* aに'A'を代入 */
        a[3] = 'G';     /* aに'A'を代入 */
        a[4] = '\0';	/* 文字列終端	*/
 
        printf("%s\n",a);
        return 0;
}
マルチバイト文字の漢字は次のように代入できます。

コード:

#include <stdio.h>
 
int main(){
        char a[10]; //配列変数
        a[0] = ('む'>>8)&0xff;     /* aに'む'の上位バイトを代入 */
        a[1] = ('む')&0xff;     /* aに'む'を下位バイトを代入 */
        a[2] = '\0';    /* 文字列終端  */
 
        printf("%s\n",a);
        return 0;
}

Re: 変数に文字を代入できません

Posted: 2011年4月17日(日) 15:48
by box
細胞 さんが書きました: 1バイトの配列でも、ひらがなや漢字などの2バイトの文字は扱えないですよね?
1バイトの配列、っていうのが何を指してるのかよくわからないですが、
char a[10];
という配列があるとして、softyaさんが書かれた(ビットシフトあたりは、しきいが高そうな感じがしますね)
のとは別の方法で、配列aに「む」を入れるにはどうすればよいか、
書籍やネットの情報をあさってみてはどうでしょうか。

Re: 変数に文字を代入できません

Posted: 2011年4月17日(日) 20:20
by 細胞
char a='A'; は、変数aを宣言して'あ'を代入するということになってるけど、
実際は、メモリのどこかに1バイト確保して、'あ'の文字コードを代入して、aという名前でアクセスできるようにした。

char a[3];なら、メモリに間隔を置かずに、並べて、3バイト確保して、それぞれa[0]と、a[1]と、a[2]の名前でアクセスできるようにした。

という理解でいいですか?

もし、メモリのことを意識できなかったとしたら、
変数というものは数字や文字を入れる箱で、配列変数は、その箱を数字をつけて、たくさん作るという理解だったとしたら、

コード:

#include <stdio.h>
 
int main(){
        char a[10]; //配列変数
        a[0] = ('む'>>8)&0xff;     /* aに'む'の上位バイトを代入 */
        a[1] = ('む')&0xff;     /* aに'む'を下位バイトを代入 */
        a[2] = '\0';    /* 文字列終端  */
 
        printf("%s\n",a);
        return 0;
}
a[0]とa[1]は別々のものだから、この↑プログラムを見て、「'む'の文字コードを2分割して、2つの箱に入れても、バラバラになってprintf命令が正しく機能しないんじゃない?」ということになりますよね

Re: 変数に文字を代入できません

Posted: 2011年4月17日(日) 21:07
by box
細胞 さんが書きました:char a='A'; は、変数aを宣言して'あ'を代入するということになってるけど、
実際は、メモリのどこかに1バイト確保して、'あ'の文字コードを代入して、aという名前でアクセスできるようにした。
'A'
の話をしてるんだか
'あ'
の話をしてるんだか
よくわからないので退散します。

Re: 変数に文字を代入できません

Posted: 2011年4月17日(日) 21:10
by softya(ソフト屋)
配列は連続したメモリ空間にアクセスできるという規則というか規約があります。なので、char型配列は文字列を格納する事が出来ます。
改めて定義すると
・charは英数字は1文字を格納するための変数です。
・char型配列は英数字が複数連続した文字列を格納する事が出来ます。
・文字列は'\0'で終っていなくてはいけません。'\0'が文字列の終りとして判断されるためです。
なので、"aaa"と書いた場合も"aaa\0"と書いた物とみなされます。

で、Windowsに限定すると英数字は1バイトの文字コードです(コンピュータ・システムによっては1バイトでないシステムが存在します)。
マルチバイト文字(SJIS)では、漢字は2バイトの文字コードです。
'む'と書いた場合は実は2バイトの文字コードとしてちゃんと定義されていますが、
a[0] = ’む';
と書くと上位1バイトが捨てられて下位バイトだけ代入されます。charは1バイトですからね。
なので私は明示的に
a[0] = ('む'>>8)&0xff; /* aに'む'の上位バイトを代入 */
a[1] = ('む')&0xff; /* aに'む'を下位バイトを代入 */
と書きました。

Re: 変数に文字を代入できません

Posted: 2011年4月18日(月) 00:59
by たかぎ
若干softyaさんに補足すると...
softya(ソフト屋) さんが書きました:・文字列は'\0'で終っていなくてはいけません。'\0'が文字列の終りとして判断されるためです。
なので、"aaa"と書いた場合も"aaa\0"と書いた物とみなされます。
(C++ではなく)Cの場合はちょっと違います。

コード:

char s[3] = "aaa";
と書くと、末尾にナル文字は付加されません。
これをどう扱うかは、プログラムしだいです。
softya(ソフト屋) さんが書きました:で、Windowsに限定すると英数字は1バイトの文字コードです(コンピュータ・システムによっては1バイトでないシステムが存在します)。
全角英数字のようなものは別ですが、基本実行文字集合に属している文字であれば、処理系によらずchar型の正の範囲に必ず収まります(ただし、非標準処理系の場合は知らない)。