文字列について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
kazuoni

文字列について

#1

投稿記事 by kazuoni » 17年前

お邪魔します。基礎的なところで躓きました。まず構造体で、
typedef struct{
	char name;//後に変数の数を増やしていくつもりです
}charname_t;
と宣言し、
charname_t charname[10];
として、charname[0]のなかにひらがな、カタカナ、漢字の文字列を格納したいのですが、まず配列の中に英数字以外のものって入れれるんですか?あと、charname[0]="キャラ"なんてやるとまずいですよね?

自分がやりたいこととしては、この構造体+配列でゲーム中に出てくるすべての文字列(キャラ名や武器名、防具名等)を扱いたいと考えています。

初歩的な質問ですみません。。
言語の参考書っというのはやはり持っていて、一度すべて頭に叩き込んだほうがよいでしょうか^^;なんだか頭に入ってすぐ抜けてしまいそうな気がしますが・・・(汗)
まず今すぐ役に立つのがCなのか、C++なのかよくわかりません^^;今まではだいたいHPめぐりで答えを見つけてきたのですが・・・ポインタはどのページを見てもあいまいにしかわかりませんでした。。文字列についても同様です。。もしよろしければ、この本&HPはおススメっというのがありましたら教えていただけないでしょうか?
よろしくお願いします。

管理人

Re:文字列について

#2

投稿記事 by 管理人 » 17年前

宣言と同時にだけできるわざは

char str[64]="ハローワールド";

こうです。でも、一度宣言してしまうと

char str[64];
str = "ハローワールド"; 

こうは出来ません。宣言した後に入れるときは、コピー関数を使います。
strcpyと言う関数です。

strcpy(①,②);

①=コピー先の配列、②=コピーしたい文字列
です。つまりstrという配列に文字をいれたければ

strcpy(str,"ハローワールド");

となります。

char str[64],str2[64] = "ハローワールド"; 
strcpy(str,str2);

でも同じ結果になります。この関数を使う時は最初にstring.hをインクルードする必要があります。
気をつけるべきは、全角は1文字で2バイト使用します。
そして文字列の最後には終端記号が1バイト入ることから、
文字列の2倍+1バイト要素が必要です。つまり

char str[7]="バイト";

のように、必要となる最小要素数は文字数X2+1この場合7なのです。
コピー先の配列がコピーするのに十分な領域を確保している事に注意が必要です。

サンプルを書いたので実行してみて下さい。


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

int main(){
	char str[64],str2[64]="バイト";

	strcpy(str,"ハローワールド");
	printf("%s\n",str);

	strcpy(str,str2);
	printf("%s\n",str);

	return 0;
}

実行結果

ハローワールド
バイト
 

管理人

Re:文字列について

#3

投稿記事 by 管理人 » 17年前

まず、標準関数としてどんなものがあるのか一通り見てみるのがいいでしょう。

http://always-pg.com/c/runtime_rd/

この辺とか用途別で確認できるので便利です。

tk-xleader

Re:文字列について

#4

投稿記事 by tk-xleader » 17年前

そもそも、文字列はchar型の配列で扱います。「ABC」という文字列を配列に格納するには、
char abc[4];
abc[0]='A';
abc[1]='B';
abc[2]='C';
abc[3]='\0';
のようにします。初期化であれば、
char abc[4]={"ABC"};
でもいけます。

文字列を本格的に扱いたいのであれば、C言語の配列、ポインタあたりを知っておく必要があります。
参考になりそうなURLを載せときます。

http://homepage3.nifty.com/mmgames/c_guide/
http://www9.plala.or.jp/sgwr-t/index.html

オプーナを買う権利を授けよう

Re:文字列について

#5

投稿記事 by オプーナを買う権利を授けよう » 17年前

うわぁ
ワタシもスレ主さんと同じ勘違いしてました><
つまり
char str[64];

str = "ハローワールド";

これしてました

助かりました~

名無し

Re:文字列について

#6

投稿記事 by 名無し » 17年前

#include <stdio.h>

int main(){
char *str;
str="ああ";
printf("%s\n",str);
return 0;
}

これじゃダメなんですか?

フリオ

Re:文字列について

#7

投稿記事 by フリオ » 17年前

> char abc[4]={"ABC"};
> でもいけます。

 これは、"abc"というcha型の配列を、
"ABC"という文字列の先頭のポインタ(char)で
初期化していることになるので、

char abc[4] = "ABC";
または、
char abc[4] = {'A', 'B', 'C', '\0'};

とすべきではないでしょうか。
 

> char *str;
> str="ああ";
> これじゃダメなんですか?

char str[5] = "ああ";
と、
char *str = "ああ";
は、意味が違います。
前者は、char型の配列"str"を、"ああ"という値で初期化していますが、
後者は、Char型へのポインタ型の変数"str"を、
"ああ"という文字列の先頭のポインタで初期化しています。
ですから、sizeof(str)は、
前者は、sizeof(char) * 5を返しますが、
後者は、sizeof(char *)を返します。
 

フリオ

Re:文字列について

#8

投稿記事 by フリオ » 17年前

 
 訂正
文字列の先頭のポインタ(char) -> 文字列の先頭のポインタ(char *)
 

box

Re:文字列について

#9

投稿記事 by box » 17年前

> char *str;
> str="ああ";
>
> これじゃダメなんですか?

ダメではありません。char型へのポインタを使った、
正しいプログラムです。

char型の配列とは意味合いが異なるだけです。

tk-xleader

Re:文字列について

#10

投稿記事 by tk-xleader » 17年前

>フリオさん

あー、ミスってました。{}いりませんね。

やそ

Re:文字列について

#11

投稿記事 by やそ » 17年前

> char *str;
> str="ああ";
>
> これじゃダメなんですか?

ほほぉ、この形の代入はあまり使った記憶がないので新鮮でした(笑)
ポインタ変数に直接文字列をぶち込むのか。うむ、お勉強になりますね^^
ん?この場合'\0'はつかないの?

バグ

Re:文字列について

#12

投稿記事 by バグ » 17年前

>> char *str;
>> str="ああ";

この場合、"ああ"の為に確保された領域というのはどのタイミングで解放されるんでしょうか?
やはりmain関数が終了した段階での解放になるんですか?
となると、少々のデータならばともかく、あまりに大量なデータになってくると、マズイ事になったりしないのかなぁ…とか思うんですが…

YuO

Re:文字列について

#13

投稿記事 by YuO » 17年前

>> char *str;
>> str="ああ";
> ん?この場合'\0'はつかないの?

付いていますよ。
上記の式は,例えば実行時にShift_JISをエンコーディングとする処理系においては,
char *str;
static char __\u3042\u3042[/url] = { 0x82, 0xA0, 0x82, 0xA0, 0x00 }; // \u3042 : あ
str = __\u3042\u3042;
と同じですから。


あと,@15334
> char str[7]="バイト";
はダメです。
strlen("バイト")が6を返すとは限りません。
実行拡張文字集合の多バイト文字の表現方式 (実行時エンコーディング) がUTF-8の場合,9を返すことでしょう。
char str[/url] = "バイト";
と,[/url]内はコンパイラに任せた方が賢いです。

box

Re:文字列について

#14

投稿記事 by box » 17年前

くだんの例では、文字列終端の'\0'を含めた5バイトを、
どこかのエリアに確保します。
char *型のstrには、その「どこかのエリア」の先頭アドレスが入ります。

Mist

Re:文字列について

#15

投稿記事 by Mist » 17年前

> どこかのエリアに確保します。
私の知る限りではプログラムエリアに確保されます。(exeに埋め込まれている)
なので、間違って書き換えないようにするために

const char *str = "ああ";

としています。

box

Re:文字列について

#16

投稿記事 by box » 17年前

くだんのstrが別の領域を指すようにすることは可能です。

char *str;
str = "12345";
/* strを使った何かの処理 */
str = "abcde";
/* また別の処理 */

というわけで、何が何でもconstでなければならない、
ということはありません。
もちろん、プログラムの仕様上constにする必要があれば、
別の話です。

kazuoni

Re:文字列について

#17

投稿記事 by kazuoni » 17年前

朝起きてものすごい返信があってびっくりしましたwなんだかいろいろ書かれすぎて要点が絞りきれてませんが^^;コピー関数についてはなんとなくわかりました!ありがとうございます^^

管理人さんの書いてくれたコードなんですが、strでは、
str[0]→ハ
str[1]→ロ
str[2]→ー
str[3]→ワ
....
となっていますよね?
これを
str[0]→ハローワールド0
str[1]→ハローワールド1
str[2]→ハローワールド2
str[3]→ハローワールド3
のようにしたいのですが・・・。これはできないでしょうか?

Mist

Re:文字列について

#18

投稿記事 by Mist » 17年前

私がconstつけるようにしているのはstrに格納されるアドレスを変えないようにするためではなく
"ああ"のエリアが書き換えられないようにするためです。

const char *str = "ああ";
str[0]='a';

これはコンパイルエラーになる。
プログラムエリアを書き換えるのはご法度ですから、そういったミスコーディングがコンパイル
で見つけられるようにするための一つの手段です。

GPGA

Re:文字列について

#19

投稿記事 by GPGA » 17年前

まず文字リテラルは、boxが書いたようにどこかのエリアに
展開されるのであって、展開先がプログラムエリアになるかどうかは、
コンパイラの仕様になると思います。

>const char *str = "ああ";
>str[0]='a';
>プログラムエリアを書き換えるのはご法度ですから
ダメなのは、言語仕様で文字リテラルに対する書き込みが未定義動作だからです。

Mist

Re:文字列について

#20

投稿記事 by Mist » 17年前

> str[0]→ハ
> str[1]→ロ
> str[2]→ー
> str[3]→ワ
> となっていますよね?
なってません。
管理人さんのレスをよく読みなおしてください。
>> 気をつけるべきは、全角は1文字で2バイト使用します。
この辺り。

> str[0]→ハローワールド0
> str[1]→ハローワールド1
> str[2]→ハローワールド2
> str[3]→ハローワールド3
> のようにしたいのですが・・・。これはできないでしょうか?
2次元配列を使えば出来ます。

char str[/url][64] = { "ハローワールド0", "ハローワールド1", "ハローワールド2", "ハローワールド3" };

YuO

Re:文字列について

#21

投稿記事 by YuO » 17年前

@15347
>> どこかのエリアに確保します。
> 私の知る限りではプログラムエリアに確保されます。(exeに埋め込まれている)

どこにリテラルを確保するかは規格で定められていません。
ISO/IEC 9899:1999 6.4.5のString literalsに,
> The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence.
と定めがあるのみです。
# なので,static char __\u3042\u3042[/url]のような記述にした。


@15349
> これを
> str[0]→ハローワールド0
> str[1]→ハローワールド1
> str[2]→ハローワールド2
> str[3]→ハローワールド3
> のようにしたいのですが・・・。これはできないでしょうか?

文字と文字列の違いを勉強しましょう。
charは「文字」を扱うためのものです。
文字列を扱うにはcharの配列 (or char *)を使います。

ここでは文字列を複数扱いたいわけですから,文字列の配列が必要になります。
const char * str[/url] = { "ハローワールド0", "ハローワールド1", "ハローワールド2", "ハローワールド3" };
のようにすればよいです。
# 文字列リテラルの変更は未定義動作なので,それを避けやすくするためにchar *の配列ではなくconst char *の配列としている。

バグ

Re:文字列について

#22

投稿記事 by バグ » 17年前

>>kazuoniさん
できますよ。char型の配列ではなく、char型へのポインタの配列に変更すれば動くはずです。

管理人

Re:文字列について

#23

投稿記事 by 管理人 » 17年前

>YUOさん、

>>>char str[7]="バイト";
>はダメです。
>strlen("バイト")が6を返すとは限りません。
>実行拡張文字集合の多バイト文字の表現方式 (実行時エンコーディング) がUTF-8の場合,9を返すことでしょう。

そうでしたか、失礼しました。


>Kazuoniさん

str[0]→ハ
str[1]→ロ
str[2]→ー
str[3]→ワ

ではなく、

str[0]→ハ
str[2]→ロ
str[4]→ー
str[6]→ワ

です。全角1文字は2バイトで表現するので。
では要素一つ分に何が入ってるの?と思うかもしれませんが、2つの領域のデータを使って一つの文字を表現しているので、要素一つのデータだけでは意味不明な値になります。

box

Re:文字列について

#24

投稿記事 by box » 17年前

>str[0]→ハ
>str[2]→ロ
>str[4]→ー
>str[6]→ワ

もっと正確に、

str[0], str[1]→ハ
str[2], str[3]→ロ
str[4], str[5]→ー
str[6], str[7]→ワ

と書く方が、ある種の環境においては
いわゆる全角文字1文字分のために
2バイトの領域が必要であることが
よりはっきりすることでしょう。

kazuoni

Re:文字列について

#25

投稿記事 by kazuoni » 17年前

皆様からしたら単純すぎる質問にご回答いただき本当にありがとうございました。

今回の部分は理解&解決できました!

文字と文字列の違い等まだまだ理解できていないので、きちんと基礎つんできます^^;

本当にありがとうございました^^

またよろしくお願いします。

閉鎖

“C言語何でも質問掲示板” へ戻る