C言語の配列の初期化に関する質問です。
もし規格によって回答が異なる場合は、ANSIのCということにしてください。

関数の中に、
char str[ ]="ABC"; (イ)
という宣言があるとします。(staticは付きません。)
これは、
char str[ ]={'A', 'B', 'C', '\0'}; (ロ)
と全く同じ意味でしょうか。

 似て非なるものに
char *str="ABC"; (ハ)
というものがあります。この場合は、
strとは違うところに"ABC"('C'の次には'\0'があります。)という領域が確保されていて、
その先頭アドレスでstrが初期化されるのですよね。

(イ)(ロ)(ハ)のいずれの場合も関数の中に書かれているとすれば、
いずれもstrは自動変数で、関数実行時にstrの領域が確保されますよね。

(イ)は配列strの領域が確保されるときに、
配列strとは別のところにある"ABC"という領域の内容を、コピーして設定する、
ということでしょうか。

(ロ)は、配列の領域確保時にstr[0]を'A'で、str[1]を'B'で、str[2]を'C'で、str[3]を'\0'で、初期化する、
ということで、
配列とは別のところには"ABC"という領域はない、
という考えでよろしいでしょうか。

もしそうだとしたら、配列とは別のところに"ABC"という領域があるかどうかという点で(イ)と(ロ)は異なることになりますが、そう考えてよろしいのでしょうか。

それとも、そういうことは処理系に依存することなんでしょうか。

このQ&Aに関連する最新のQ&A

A 回答 (4件)

>この記述は、配列とは別のところに初期値で埋まった領域(質問でいう"ABC")がある、という意味に思えてしまいます。



実行のする度に値が設定されるわけですから、配列と同じ並び順でない可能性はあっても、必ずなんらかの形でどこかに存在します。

>これも、文字列定数の領域(この場合は"ABCD")が配列の領域とは別にあるように読めてしまいます。

これもその通りでしょう。


>配列strとは別のところにある"ABC"という領域の内容を、コピーして設定する、
>ということでしょうか。
基本的にはその通りでしょう。
やろうと思えば"A B C "というところから一つおきにコピーする実装も可能でしょうけど(笑)

また、(イ)と(ロ)はコンパイラ上では同じ扱いだったと思いますし、kaicheさんが書いたやり方は、実質的にコピーと同じですね。
初期化のために代入する値が結局はどこかに必要ですから。

ただ、"ABC"と連続して格納されている領域があるかないかは、実装よるでしょうから、
どちらの場合も連続領域におかないようにするコンパイラの作成は可能でしょう。
ただ、通常は効率上そういう実装はまず無いと思いますが。

ただ、この違いも使う上ではどうでもいいことですけど。

あと、気になるのは、領域というのをどういう意味で考えているかどうかですね.
もし、私が考えているものより、狭い意味で使っているなら、説明も変えないといけないでしょう。


あ、私もコンパイラの実装まではやったことはありませんが、Cのコンパイル結果をアセンブラレベルで見たこととか,OSのメモリ管理とかの知識はそれなりにあります。

この回答への補足

ということはこういうことですね。

(文字配列の初期化に関して)
配列とは別のところに初期化子があり、配列の領域を確保するときにそれをコピーしている。
初期化子がどこかになければ配列を初期化することは出来ない。
しかし、それは
char *str="ABC"; (ハ)
の"ABC"とは異なり、初期化子がどう並んでいるかはわからない。
どう並んでいてもそれを直接触ることは出来ないので関係ない。

つまり
>この違いも使う上ではどうでもいいことですけど。
ということですね。

char str[ ]="ABC"; (イ)

char str[ ]={'A', 'B', 'C', '\0'}; (ロ)
はまったく同じ意味だ。
他方、(ハ)は'A', 'B', 'C'がどこかにあるという点では同じでも、
ぜんぜん意味合いが異なる。

補足日時:2002/01/14 23:07
    • good
    • 0

>ということはこういうことですね。



はい。

あとちょっと気になったのは,
>strとは違うところに"ABC"('C'の次には'\0'がありま
す。)という領域が確保されていて、
の領域ですが、ここは定数領域であって変数の領域では無く、
書き換えることはできないということを把握しているかです。
確か,ANSIの規格では書き換えできないとなっていたと
思います。
ただ、古いコンパイラやOSによっては、書き換え可能な4byteの領域として扱えたケースもありました。
で、動いてしまったので間違って覚えると(^^;;


それと本の記述に戻りますが,
>配列の領域の確保および初期化が行われることになるので、非常にムダがあります(まず文字列定数
ですが、内容が不変の場合はそうですが、
ケースによってはそうすることが必要な場合もありますから、
一概に無駄というのは正確ではありません。
もしかすると、引用されない部分に記述があるのかも知れませんが。
あと、メジャーではないと言い切っている辺りも気になります。
その本の内容は少し注意したほうがいいかも知れません。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

char *str="ABC"; (ハ)
についてですが、、
>>strとは違うところに"ABC"('C'の次には'\0'がありま
>す。)という領域が確保されていて、
>の領域ですが、ここは定数領域であって変数の領域では無く、
>書き換えることはできないということを把握しているかです。
>確か,ANSIの規格では書き換えできないとなっていたと
>思います。

この件については、今 私の手元にある書籍ですと、以下に書かれています。
#本の名前を挙げたところで、同じ本を持っていない人にとっては意味ないですが( ;^^)ヘ..
『プログラミング言語C 第2版(訳書訂正版)』p.236
『新ANSI C言語辞典』(平林雅英著、技術評論社)の"文字列リテラル"の項
『C言語プログラミングの落とし穴』(柴田望洋著、ソフトバンク)p.77

あと、本の記述に関することはナルホドそうだと私も思います。

お礼日時:2002/01/19 10:56

(No.1の回答に対する補足を読んで)


了解、そういった背景があったのですね。
初期化するためのデータをあらかじめどこかに持っているのでは?と言う話ですね。

…と、なると、処理系に依存すると思います。

ただし、その元データに対してどうこうする事は出来ません。
writeはもちろんのこと、readもです。
…って、これはあまり自信がないなぁ…コンパイラの実装なんてやったことないから…

この回答への補足

(文字配列の初期化に関して)
>ただし、その元データに対してどうこうする事は出来ません。

なるほど、つまり、たとえ初期化の元のデータが配列と別のところにあろうと さわることはできないのだから、
結局 無いのといっしょだ、ということですね。

補足日時:2002/01/14 22:16
    • good
    • 0

>関数の中に、


>char str[ ]="ABC"; (イ)
>という宣言があるとします。(staticは付きません。)
>これは、
>char str[ ]={'A', 'B', 'C', '\0'}; (ロ)
>と全く同じ意味でしょうか。
はい、そのとおりです。

>似て非なるものに
>char *str="ABC"; (ハ)
>というものがあります。この場合は、
>strとは違うところに"ABC"('C'の次には'\0'があります。)という領域が
>確保されていて、
>その先頭アドレスでstrが初期化されるのですよね。
これもそのとおりです。

>(イ)(ロ)(ハ)のいずれの場合も関数の中に書かれているとすれば、
>いずれもstrは自動変数で、関数実行時にstrの領域が確保されますよね。
(ハ)の場合はそのとおりですが、(イ)(ロ)の場合はちがいます。
確保されるはchar配列領域です。strはそのアドレスを指す定数と考えたほうがいいでしょう(この辺ちょっと自信なし)。

>(イ)は配列strの領域が確保されるときに、
>配列strとは別のところにある"ABC"という領域の内容を、コピーして設定する、
>ということでしょうか。

>(ロ)は、配列の領域確保時にstr[0]を'A'で、str[1]を'B'で、str[2]
>を'C'で、str[3]を'\0'で、初期化する、
>ということで、
>配列とは別のところには"ABC"という領域はない、
>という考えでよろしいでしょうか。
どちらも、後者の方法で初期化が行われます。したがって、どちらも配列とは別のところには"ABC"という領域はありません。

「もしそうなら…」以降は仮定が成り立たないので回答を省略します。

この回答への補足

(ご回答No.1を拝見した上で書きます。)

ご回答有難うございます。(イ)と(ロ)について、
>どちらも、後者の方法で初期化が行われます。したがって、どちらも配列とは別のところには"ABC"という領域はありません。

明快な答えで、よくわかりました。


でも、私、いろいろ本で調べたんですが、アレレと思う記述を見つけてしまいました。
(人が書いた本まで聞かれても困る、と思われるかもしれませんが。)

「ANSI Cでも、集成体型の初期化子には、定数しか書けないという制限があります。
(中略)
 集成体の初期化子に定数しか書けないことにすることで、コンパイラをちょっとばかり簡単にすることができます。あらかじめ初期値で埋めた領域をどこかに作っておいて、ブロックに突入した時点でスタックにコピーすればよいからです。」(※1)
(同じページに、「実行中に、配列などの集成体型を初期化しようと思ったら」という記述があるので、集成体型には「配列」も含まれると思います。)
 この記述は、配列とは別のところに初期値で埋まった領域(質問でいう"ABC")がある、という意味に思えてしまいます。


また別の本には、こんな記述があります。
「K&Rでは、自動的な配列を初期化することは不可能でした。ですから、関数の中で
 char str[ ] = "ABCD"; (1)
という定義はできませんでした。
(中略)
 (1)はANSIで認められた新しい方法であり、あまりメジャーではありません。実際、関数が呼び出されるたびに、配列の領域の確保および初期化が行われることになるので、非常にムダがあります(まず文字列定数"ABCD"という領域がどこかに取られます。さらに関数が呼び出されるたびに、これとは別にstrという配列の領域が確保され、その各要素が 'A', 'B', 'C', 'D', '\0' で初期化されることになります)。」(※2)

これも、文字列定数の領域(この場合は"ABCD")が配列の領域とは別にあるように読めてしまいます。


はっきり言って、これらは誤りですよね。


(※1)『C言語ポインタ完全制覇』(前橋和弥著、技術評論社)p.113
(※2)『新版秘伝C言語問答ポインタ編』(柴田望洋著、ソフトバンク パブリッシング)p.63

補足日時:2002/01/14 20:46
    • good
    • 0
この回答へのお礼

(この質問を締め切る前に)

No.1の補足に、
>はっきり言って、これらは誤りですよね。
なる記述がありますが、基本的にはこれらの本の記述は誤りではないようです。
(ただし、柴田望洋氏の本について、注意して読んだほうがよいとのご指摘が回答No.4にあります。)

お礼日時:2002/01/19 19:43

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aと関連する良く見られている質問

Qchar *str; と char* str;

char *str; と char* str;
どっちも同じことを意味しているんですか?

Aベストアンサー

同じことを指している、というのは、先の回答の通りです。

また、ひとつの宣言で変数を複数宣言したときに、char* str という表記は間違い
易いじゃないか、ということが言われているのも事実です。実際、いろいろな C のソースを
見ていても、まずアスタリスクを型につけて書くのは、まずお目にかかれません。

ただ C++ では、char* str という宣言も良く使われています。

C++ に限らずオブジェクト指向の言語は、強く型を意識するので、「文字のポインタ型」と
いう意味で、まとめて書く方が馴染むのでしょう。ちなみにそういう風な人たちは

char *str1, *str2;

とは、書けない体になっています。

char* str1;
char* str2;


変数の宣言だと、C に慣れていれば、char* str というのはちょっと違和感があるのは
私も分かりますが、関数のプロトタイプ宣言だと、どちらの方がすっきりしますか?

extern char *memcpy(char *, const char *);

extern char* memcpy(char*, const char*);


# まあ、どっちが正しい、っていうんじゃ無いんですよね

同じことを指している、というのは、先の回答の通りです。

また、ひとつの宣言で変数を複数宣言したときに、char* str という表記は間違い
易いじゃないか、ということが言われているのも事実です。実際、いろいろな C のソースを
見ていても、まずアスタリスクを型につけて書くのは、まずお目にかかれません。

ただ C++ では、char* str という宣言も良く使われています。

C++ に限らずオブジェクト指向の言語は、強く型を意識するので、「文字のポインタ型」と
いう意味で、まとめて書く方が馴染む...続きを読む

Qchar str[256]の256の意味は?

よく入門者などにchar str[256]という記述があります。

この256という数字には何か特別な意味があるのですか?
勿論2の8乗から来ているのでしょうが。

charって1バイト=8ビット=256ですよね。
str[256]というのを良く見かけるので、最初strは最大256個しか確保できないと思っていました。
でも、実際は1000でも良いのですよね。


ということで、どうして256という数字を使うのですか?
意味ありげな数字を使われると、初心者は混乱するので100とか200とかの方が良いと思うのですが。
特別な理由があるのでしょうか?

Aベストアンサー

ちょっと一言。

1バイト(8ビット)で表現できるのは、
符号なしの場合
 0(00000000)~255(11111111)
符号ありの場合
 -128(10000000)~127(01111111)
です。
256は表せません。

ついでにもう一言。
char str[256];
って「ファイルの名前」とか「ファイル中の1行」を
格納するために定義されることが多いでしょう。
私の場合は、
「名前(or 1行の文字数)が256文字もあるファイルは滅多に無いだろう」
「でも128文字ぐらいならあるかも。ちょっと不安」
「かといって512文字は多すぎるかな」
ってことで256にしてます。
はじめから文字数がわかってるときは32とか64にしたりもしますが。
(なんで2のべき乗なのかはNo.1の通りです。)

Q副プログラム内(void mystery(char s1[],char s2[]))の動作確認文 

お忙しい中失礼します。
下記のプログラム内の動作について質問があります。宜しければご回答願います。

void mystery(char s1[],char s2[])
{
int i=0;
while(s2[i]!='\0'){ //s2[i]内に文字が入力され、エンターキーが入力されるまで{s1[i] = s2[i]; ++i;}内の動作を行う。
s1[i] = s2[i];    //s1[i] を基準にs2[i]の文字数を++iを使い、カウントする。
++i;         //++iはただs1[i] とs2[i]の文字が合致してるか確認を行う。s1[]=”Good”なら s2[]=”Good”の各文字が合致してるかどうか。
}

s1[i] = '\0';    //s1[i]にエンターキーが入力されて、void mystery(char s1[],char s2[])内のループを抜ける。
return;       //s1[i] = '\0'で'\0'が定義されているのでreturn 0;でない?
}

↑上記動作質問://より右側の文章は文章的に正しいでしょうか?
void mystery(char s1[],char s2[])内でどんな動作をしてるのかが、イマイチよく分からないのです。




↓下記のプログラム
#include <stdio.h>
#include <stdlib.h>
void mystery(char [], char[]);

int main()
{
char m1[81],m2[81];
int i;
printf("Message?");
gets(m1);
mystery(m2,m1);
puts(m2);

system("PAUSE");
return 0;
}

void mystery(char s1[],char s2[])
{
int i=0;
while(s2[i]!='\0'){
s1[i] = s2[i];
++i;
}

s1[i] = '\0';
return;
}

お忙しい中失礼します。
下記のプログラム内の動作について質問があります。宜しければご回答願います。

void mystery(char s1[],char s2[])
{
int i=0;
while(s2[i]!='\0'){ //s2[i]内に文字が入力され、エンターキーが入力されるまで{s1[i] = s2[i]; ++i;}内の動作を行う。
s1[i] = s2[i];    //s1[i] を基準にs2[i]の文字数を++iを使い、カウントする。
++i;         //++iはただs1[i] とs2[i]の文字が合致してるか確認を行う。s1[]=”Good”なら s2[]=”Good”の...続きを読む

Aベストアンサー

うーん。。。
動作の説明としては全て間違いです。

>while(s2[i]!='\0'){
s2のi番目の要素が終端文字で無い間繰り返し処理します。
#エンターキー云々は関係ありません。

>s1[i] = s2[i];
s1のi番目の要素にs2のi番目の要素をコピーしています。
#比較ではなく代入です。

>++i;
ここでのiは文字列の要素を表す要素番号に過ぎません。
#次の文字へ進むだけで、カウントなどしていません。

>s1[i] = '\0';
s2が文字列の終わりを検出したので、
ループを抜けてs1にも文字の終端を書き込んでいます。
#ここでは既にループを抜けた後です。

>return; 
関数の戻り値はvoidつまり「無し」なので
returnで評価される式も在りません。
#疑問系でコメントを書くなら書かない方が良いです。
#混乱のもとですから。。。

短くすると・・・:-p
void mystery(char *s1, const char *s2){
  while (*s1++ = *s2++);
}

うーん。。。
動作の説明としては全て間違いです。

>while(s2[i]!='\0'){
s2のi番目の要素が終端文字で無い間繰り返し処理します。
#エンターキー云々は関係ありません。

>s1[i] = s2[i];
s1のi番目の要素にs2のi番目の要素をコピーしています。
#比較ではなく代入です。

>++i;
ここでのiは文字列の要素を表す要素番号に過ぎません。
#次の文字へ進むだけで、カウントなどしていません。

>s1[i] = '\0';
s2が文字列の終わりを検出したので、
ループを抜けてs1にも文字の終端を書き込んでいま...続きを読む

Qchar gyou[1024];でcharの表現範囲は-128~127間でと!gyou[1024]の

#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
char gyou[1024];
int gyousuu = 0;
if ( argc < 2 ){
printf("file mei ga nai\n");
return -1;
}
fp = fopen(argv[1], "r");
if ( fp == NULL ){
printf("fopen dekinai\n");
return -2;
}
while(fgets(gyou, sizeof(gyou), fp) != NULL){
gyousuu++;
}
fclose(fp);
printf("gyousuu=%d\n", gyousuu);
return 0;
}
 以上のプログラムは行数を計算してくれるプログラムです。
  計算結果が
  gyousuu=22 とでます。
 さて、char gyou[1024];でcharの表現範囲は-128~127間ですが、
 gyou[1024]の[1024]とは関係はありますでしょうか!?
  [1024]の意味は”要素数”と参考書に鉛筆書きがありました。
 charの表現範囲である1024は、はるかに超えているみたいですが?
  dharの表現範囲を1024が超えたとしても特に問題はなさそうです!
  このプログラムは動いていますのでは正常です。
  私の
  考え方としまして、何か誤りがありますでしょうか?
  よろしくお願いいたします。

#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
char gyou[1024];
int gyousuu = 0;
if ( argc < 2 ){
printf("file mei ga nai\n");
return -1;
}
fp = fopen(argv[1], "r");
if ( fp == NULL ){
printf("fopen dekinai\n");
return -2;
}
while(fgets(gyou, sizeof(gyou), fp) != NULL){
gyousuu++;
}
fclose(fp);
printf("gyousuu=%d\n", gyousuu);
return 0;
}
 以上のプログラムは行数を計算してくれるプログラムです。
  計算結果が
...続きを読む

Aベストアンサー

> さて、char gyou[1024];でcharの表現範囲は-128~127間ですが、
> gyou[1024]の[1024]とは関係はありますでしょうか!?
ない。
1024 のほうはただ単に領域の個数を表しているだけで、読み込もうとするファイルの 1 行のバイト数がこれを超えない限り別に 1000 でも 3327 でも構わない(ある程度以上大きくなると別の問題が出てくるが)。
ただ単に 1024 = 2^10 でプログラマにはよく見る数字、かつ、普通のテキストなら 1 行が収まりそうな長さなだけ。

Qchar *abc[20]

基本的なことかもしれませんが、ポインタのことを理解していたとおもいきや、また混乱しはじめたので質問させていただきます。

char *abc[20];
この意味は、
char型のポインタを要素とする配列。
char型の要素数20個の配列へのポインタ。
という2つの解釈ができそうなのですが、どちらでしょうか??この2つは違ういみですよね?

Aベストアンサー

> char型のポインタを要素とする配列。

こちらです。


> char型の要素数20個の配列へのポインタ

は、char abc[20]; と記述したときのabcで表します。


人気Q&Aランキング

おすすめ情報