2017-01-12 13 views
0

こんにちは私はこのコードにしばらく詰まっていて、両方がうまくいくように見えます。構造体 'const char * x' vs 'char x [30]'

struct faveThings{ 

    const char *favFood; 
    const char *faveFriend; 


}; 

struct dog{ 

const char name[20]; 
const char breed[20]; 
int height; 
int weight; 

struct faveThings dogFaves; 

}; 

「文字名[20]」の使用は私に完全な意味を成して構造体の私は完全に犬を理解することができます。しかし、私は 'char * favFood'と闘うfaveThingsを使って、これはポインタであることがわかりますが、これはちょうどcharの場合にどのように文字列を保持できますか?それは文字の配列ではないでしょうか?

const char *favFood[20]; 

何かお手伝いしてくれてありがとうございました。私は何かの違いを見つけようと数時間壁に頭を打っていました。

答えて

6

favFoodは文字列を保持しません。それはどこかを指す。そして、最初の文字を指すようにすることができますの文字列です。慣習的に、cストリングは異なる長さを持つことができるので、'\0'文字で終了します。そうすれば、たとえあなたが持っているものすべてが最初の文字へのポインタであっても、文字列の終わりを見つけることができます。

したがって、strlenのようなライブラリ関数は、NUL文字を見つけるまで、ポインタを最初の文字から次の文字に移動します。

const char *favFood[20];はまったく別の獣です。それは20のポインタの配列です。各ポインタは、異なるものを指すことができます。

+0

私はそれがどこかを指しているが、これは文字列を取得するためにどのように使用できるのか分からない。たとえば、 "肉"を保持し、 'theDog.dogFaves.favFood'これは文字列ではなく、単一の文字 'M'を返しますか? – fdbdcbc

+0

@ MGordon0405 - 'theDog.dogFaves.favFood'は何も返しません。 **は**文字列内の最初の文字のアドレスに評価され、文字自体には評価されません。 – StoryTeller

+0

@ MGordon0405 - 今のところ文字列を忘れる。関数に整数の配列を渡す理由、最初の要素へのポインタ、配列の長さが必要なのは分かりますか? – StoryTeller

1

あなたはconst char *favFood;は、単一のcharを指しない権利ということだが、連続しchar Sを含むメモリのブロック、および最初のものへのポインタポイントがあることが理解されています。したがって、コードはそのポインタを使用して、ブロック内のcharすべてにアクセスできます。

favFoodを使用するコードでは、メモリ割り当てを実行し、そのメモリをchars(およびヌルターミネータ)で埋めて、favFoodがその割り当てを指し示すことも確認します。

const char *favFood[20];は20個のポインタの配列になります。

+0

ああ、ありがとう、ありがとう。助けを感謝します! – fdbdcbc

0

const char * favFood [20]は、カルトデータを指すポインタの配列です。

それは次のようだ

* favFood [1] --------> MemLocationは、(0x001)は= * favFood [2] --------> MemLocation(0x002)= B

などもここで見てみてください。Can I create an Array of Char pointers in C?

を私はそれがあなたの質問

以下
0

は一定の文字の配列である回答を願っています。 C言語は"シンボルで区切られた文字列の最後に '\ 0'を追加するため、実際には5つの要素が含まれています。 Cでは、MEATのような配列オブジェクトは実際には配列の最初の要素へのポインタなので、MEATは実際には文字の配列全体ではなくメモリアドレスです!

const char[] MEAT = "Meat"; 

以下は、const charへのポインタです。 *シンボルはポインタであることを示します。(これは、タイプを指し示しているタイプを変数名で指定するかどうかは関係ありません。これは混乱する可能性があるため、通常はタイプ情報をまとめて名前を付けますが、最も一般的な規則ではありません。)favFood変数は、MEAT配列の最初の文字のアドレスで初期化されます。 (MEATは、メモリ・アドレスであるので、これは別のものを等しくするために、1つのメモリアドレスを設定していることを覚えておいてください。)

const char* favFood = MEAT; 

を将来のある時点で、あなたの動物が突然それが実際に今、それはもはや肉が好きなことを決めていないともビスケットが好きです(猫が犬よりも心を変える可能性が高い、わかりますが、これは単なる例です)。

const char BISCUITS[] = "Biscuits"; 

/* Some code is done here, until you find... */ 

favFood = BISCUITS; 

は今、MEATBISCUITSの両方は、あなたがそれらを変更することはできませんを意味し、一定であるが、favFoodは、文字列定数(とにかく文字列の最初の文字)に一定のが、ポイントそのものではないので、あなたはそれを変更することができます!

あなたはまた、非定数文字列持つことができます。

char nameAndFaveFood[50]; 
sprintf(nameAndFaveFood, "%.26s likes %.9s best.", name, favFood); 

を...しかし、あなたはより多くの文字をコピーしていないことを確認してください - 終端の「\ 0」ヌル文字を含めて - あなたはスペースが割り当てられているよりも、この場合、49文字とターミネータが必要です。このため、sprint関数には、サブ文字列の長さを制限する精度指定子があります。

変更可能なメモリへの固定ポインタを持つことができます。 LIKES_FOODオブジェクトがnameAndFaveFoodアレイの途中を指すように初期化されること

char* const LIKES_FOOD = &nameAndFaveFood[27]; 

注。それは常にそのアドレスを指します。前のコードブロックのルーチンをnamefavFoodのパラメータで呼び出すことができますが、LIKES_FOODは常にnameAndFaveFood配列の28番目の文字を指します。