ページ 1 / 1
文字列について
Posted: 2008年4月03日(木) 23:32
by kazuoni
お邪魔します。基礎的なところで躓きました。まず構造体で、
typedef struct{
char name;//後に変数の数を増やしていくつもりです
}charname_t;
と宣言し、
charname_t charname[10];
として、charname[0]のなかにひらがな、カタカナ、漢字の文字列を格納したいのですが、まず配列の中に英数字以外のものって入れれるんですか?あと、charname[0]="キャラ"なんてやるとまずいですよね?
自分がやりたいこととしては、この構造体+配列でゲーム中に出てくるすべての文字列(キャラ名や武器名、防具名等)を扱いたいと考えています。
初歩的な質問ですみません。。
言語の参考書っというのはやはり持っていて、一度すべて頭に叩き込んだほうがよいでしょうか^^;なんだか頭に入ってすぐ抜けてしまいそうな気がしますが・・・(汗)
まず今すぐ役に立つのがCなのか、C++なのかよくわかりません^^;今まではだいたいHPめぐりで答えを見つけてきたのですが・・・ポインタはどのページを見てもあいまいにしかわかりませんでした。。文字列についても同様です。。もしよろしければ、この本&HPはおススメっというのがありましたら教えていただけないでしょうか?
よろしくお願いします。
Re:文字列について
Posted: 2008年4月04日(金) 00:20
by 管理人
宣言と同時にだけできるわざは
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:文字列について
Posted: 2008年4月04日(金) 00:23
by 管理人
まず、標準関数としてどんなものがあるのか一通り見てみるのがいいでしょう。
http://always-pg.com/c/runtime_rd/
この辺とか用途別で確認できるので便利です。
Re:文字列について
Posted: 2008年4月04日(金) 00:29
by tk-xleader
そもそも、文字列は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:文字列について
Posted: 2008年4月04日(金) 02:34
by オプーナを買う権利を授けよう
うわぁ
ワタシもスレ主さんと同じ勘違いしてました><
つまり
char str[64];
str = "ハローワールド";
これしてました
助かりました~
Re:文字列について
Posted: 2008年4月04日(金) 06:38
by 名無し
#include <stdio.h>
int main(){
char *str;
str="ああ";
printf("%s\n",str);
return 0;
}
これじゃダメなんですか?
Re:文字列について
Posted: 2008年4月04日(金) 08:10
by フリオ
> 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:文字列について
Posted: 2008年4月04日(金) 08:15
by フリオ
訂正
文字列の先頭のポインタ(char) -> 文字列の先頭のポインタ(char *)
Re:文字列について
Posted: 2008年4月04日(金) 08:18
by box
> char *str;
> str="ああ";
>
> これじゃダメなんですか?
ダメではありません。char型へのポインタを使った、
正しいプログラムです。
char型の配列とは意味合いが異なるだけです。
Re:文字列について
Posted: 2008年4月04日(金) 08:57
by tk-xleader
>フリオさん
あー、ミスってました。{}いりませんね。
Re:文字列について
Posted: 2008年4月04日(金) 09:21
by やそ
> char *str;
> str="ああ";
>
> これじゃダメなんですか?
ほほぉ、この形の代入はあまり使った記憶がないので新鮮でした(笑)
ポインタ変数に直接文字列をぶち込むのか。うむ、お勉強になりますね^^
ん?この場合'\0'はつかないの?
Re:文字列について
Posted: 2008年4月04日(金) 09:49
by バグ
>> char *str;
>> str="ああ";
この場合、"ああ"の為に確保された領域というのはどのタイミングで解放されるんでしょうか?
やはりmain関数が終了した段階での解放になるんですか?
となると、少々のデータならばともかく、あまりに大量なデータになってくると、マズイ事になったりしないのかなぁ…とか思うんですが…
Re:文字列について
Posted: 2008年4月04日(金) 09:51
by YuO
>> 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]内はコンパイラに任せた方が賢いです。
Re:文字列について
Posted: 2008年4月04日(金) 09:52
by box
くだんの例では、文字列終端の'\0'を含めた5バイトを、
どこかのエリアに確保します。
char *型のstrには、その「どこかのエリア」の先頭アドレスが入ります。
Re:文字列について
Posted: 2008年4月04日(金) 10:08
by Mist
> どこかのエリアに確保します。
私の知る限りではプログラムエリアに確保されます。(exeに埋め込まれている)
なので、間違って書き換えないようにするために
const char *str = "ああ";
としています。
Re:文字列について
Posted: 2008年4月04日(金) 10:27
by box
くだんのstrが別の領域を指すようにすることは可能です。
char *str;
str = "12345";
/* strを使った何かの処理 */
str = "abcde";
/* また別の処理 */
というわけで、何が何でもconstでなければならない、
ということはありません。
もちろん、プログラムの仕様上constにする必要があれば、
別の話です。
Re:文字列について
Posted: 2008年4月04日(金) 10:43
by kazuoni
朝起きてものすごい返信があってびっくりしましたwなんだかいろいろ書かれすぎて要点が絞りきれてませんが^^;コピー関数についてはなんとなくわかりました!ありがとうございます^^
管理人さんの書いてくれたコードなんですが、strでは、
str[0]→ハ
str[1]→ロ
str[2]→ー
str[3]→ワ
....
となっていますよね?
これを
str[0]→ハローワールド0
str[1]→ハローワールド1
str[2]→ハローワールド2
str[3]→ハローワールド3
のようにしたいのですが・・・。これはできないでしょうか?
Re:文字列について
Posted: 2008年4月04日(金) 10:49
by Mist
私がconstつけるようにしているのはstrに格納されるアドレスを変えないようにするためではなく
"ああ"のエリアが書き換えられないようにするためです。
const char *str = "ああ";
str[0]='a';
これはコンパイルエラーになる。
プログラムエリアを書き換えるのはご法度ですから、そういったミスコーディングがコンパイル
で見つけられるようにするための一つの手段です。
Re:文字列について
Posted: 2008年4月04日(金) 11:05
by GPGA
まず文字リテラルは、boxが書いたようにどこかのエリアに
展開されるのであって、展開先がプログラムエリアになるかどうかは、
コンパイラの仕様になると思います。
>const char *str = "ああ";
>str[0]='a';
>プログラムエリアを書き換えるのはご法度ですから
ダメなのは、言語仕様で文字リテラルに対する書き込みが未定義動作だからです。
Re:文字列について
Posted: 2008年4月04日(金) 11:18
by Mist
> 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" };
Re:文字列について
Posted: 2008年4月04日(金) 11:19
by YuO
@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:文字列について
Posted: 2008年4月04日(金) 11:20
by バグ
>>kazuoniさん
できますよ。char型の配列ではなく、char型へのポインタの配列に変更すれば動くはずです。
Re:文字列について
Posted: 2008年4月04日(金) 13:38
by 管理人
>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つの領域のデータを使って一つの文字を表現しているので、要素一つのデータだけでは意味不明な値になります。
Re:文字列について
Posted: 2008年4月04日(金) 14:01
by box
>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バイトの領域が必要であることが
よりはっきりすることでしょう。
Re:文字列について
Posted: 2008年4月04日(金) 15:23
by kazuoni
皆様からしたら単純すぎる質問にご回答いただき本当にありがとうございました。
今回の部分は理解&解決できました!
文字と文字列の違い等まだまだ理解できていないので、きちんと基礎つんできます^^;
本当にありがとうございました^^
またよろしくお願いします。