18

考えていて、[]または*で変数を宣言することの違いは何ですか?私の見立てでは:

char *str = new char[100];
char str2[] = "Hi world!";

..主な違いになるはずですが、次のようなことができるかどうかはわかりません

char *str = "Hi all";

..ポインタは静的メンバーへの参照である必要があるので、それが可能かどうかはわかりませんか?

とにかく、私を本当に悩ませているのは、次の違いを知っていることです。

void upperCaseString(char *_str) {};
void upperCaseString(char _str[]) {};

それで、誰かが私に違いを教えてくれるなら、大いに感謝されますか?いくつかの特別な場合を除いて、両方が同じようにコンパイルされるかもしれないという予感がありますか?

Ty

4

6 に答える 6

42

調べてみましょう (以下については、C++ でも同じであることに注意char constしてください)。const char

文字列リテラルと char *

"hello"は、6 つの const 文字の配列です: char const[6]. すべての配列と同様に、最初の要素へのポインターに暗黙的に変換できchar const * s = "hello";ます。C コードとの互換性のために、C++ では別の変換が許可されchar * s = "hello";ています。これは、C っぽいコードをコンパイルできるようにするための例外ですがchar *、文字列リテラルを指すことは非推奨です。それで、私たちは何のために持っていchar * s = "foo";ますか?

"foo"-> array-to-pointer-> char const*-> qualification-conversion-> char *. 文字列リテラルは読み取り専用で、スタックに割り当てられません。それらを指すポインターを自由に作成し、クラッシュすることなく関数からそのポインターを返すことができます:)。

文字列リテラルを使用した配列の初期化

さて、何char s[] = "hello";ですか?それはまったく別のことです。これにより、文字の配列が作成され、 String で埋められ"hello"ます。リテラルは指されていません。代わりに、文字配列にコピーされます。そして、スタック上に配列が作成されます。関数からポインタを有効に返すことはできません。

配列パラメーターの型。

関数に配列をパラメーターとして受け入れるようにするにはどうすればよいですか? パラメータを配列として宣言するだけです。

void accept_array(char foo[]); 

ただし、サイズは省略します。実際には、無視されるだけなので、任意のサイズで実行できます。標準では、そのように宣言されたパラメーターは次のように変換されると述べています。

void accept_array(char * foo);

エクスカーション: 多次元配列

char配列自体を含む任意の型で置き換えます。

void accept_array(char foo[][10]);

最後の次元のサイズが 10 の 2 次元配列を受け入れます。多次元配列の最初の要素は、次の次元の最初のサブ配列です。では、変形してみましょう。再び最初の要素へのポインタになります。したがって、実際には 10 文字の配列へのポインタを受け入れます: ( []in ヘッドを削除してから、頭に表示される型へのポインタを作成します):

void accept_array(char (*foo)[10]);

配列は最初の要素へのポインターに暗黙的に変換されるため、2 次元配列 (最後の次元のサイズは 10) を渡すだけで機能します。実際、特殊な場合の;を含む、任意のn 次元配列に当てはまります。n = 1

結論

void upperCaseString(char *_str) {}; 

void upperCaseString(char _str[]) {};

最初のものは単なる char へのポインタであるため、これらは同じです。ただし、文字列リテラルをそれに渡したい場合 (引数を変更しないとします)、char const* _str非推奨のことをしないようにパラメーターを に変更する必要があります。

于 2008-11-21T13:18:02.817 に答える
12

3 つの異なる宣言により、ポインタは異なるメモリ セグメントを指すことができます。

char* str = new char[100];

str がヒープを指すようにします。

char str2[] = "Hi world!";

文字列をスタックに置きます。

char* str3 = "Hi world!";

データ セグメントを指します。

二つの宣言

void upperCaseString(char *_str) {};
void upperCaseString(char _str[]) {};

が等しい場合、コンパイラは、同じスコープでそれらを宣言しようとすると、関数が既に本体を持っていることについて不平を言います。

于 2008-11-21T10:02:51.677 に答える
2

さて、私は2つの否定的なコメントを残しました。これはあまり役に立ちません。それらを削除しました。

  • 次のコードは、(ヒープ内で) 動的に割り当てられたメモリ部分の先頭を指す char ポインターを初期化します。

char *str = new char[100];

このブロックは、 を使用して解放できますdelete []

  • 次のコードは、スタックに char 配列を作成し、文字列リテラルで指定された値に初期化します。

char [] str2 = "Hi world!";

この配列は問題なく変更できます。これは素晴らしいことです。そう


str2[0] = 'N';
cout << str2;

標準出力に出力する必要Ni world!があり、特定の騎士は非常に不快に感じます。

  • 次のコードは、文字列リテラルを指す char ポインターをスタックに作成します... ポインターは問題なく再割り当てできますが、ポイントされたブロックを変更することはできません (これは未定義の動作です。たとえば、Linux ではセグメンテーション違反になります)。

char *str = "Hi all";
str[0] = 'N'; // ERROR!
  • 次の 2 つの宣言

void upperCaseString(char *_str) {};
void upperCaseString(char [] _str) {};

には同じように見えますが、あなたの場合(文字列を大文字にしたい場合)、それは本当に問題ではありません。

ただし、これらすべてに疑問が生じます。なぜchar *C++ で文字列を表現するために使用しているのですか?

于 2008-11-21T14:56:29.090 に答える
0

http://c-faq.com/aryptr/aryptr2.htmlもご覧ください。C-FAQ自体が興味深い読み物になるかもしれません。

于 2008-11-21T16:18:25.290 に答える
0

既に与えられた回答の補足として、arrays vs. pointers に関する C FAQを読む必要があります。はい、これは C の FAQ であり、C++ の FAQ ではありませんが、この分野では 2 つの言語の間に実質的な違いはほとんどありません。

また、補足として、先頭にアンダースコアを付けて変数に名前を付けることは避けてください。これは、コンパイラと標準ライブラリによって定義されたシンボル用に予約されています。

于 2008-11-21T13:30:28.640 に答える
-1

最初のオプションは、100 バイトを動的に割り当てます。

2 番目のオプションは、静的に 10 バイト (文字列 + ヌル文字の場合は 9) を割り当てます。

3 番目の例は機能しないはずです。動的アイテムを静的に入力しようとしています。

質問に関してupperCaseString()は、C 文字列が割り当てられて定義されると、配列のインデックス付けまたはポインター表記によって反復処理できます。これは、配列は C でポインター演算をラップするための便利な方法にすぎないためです。


(それは簡単な答えです - 私は他の誰かが仕様外の信頼できる複雑な答えを持っていると思います:))

于 2008-11-21T10:01:41.103 に答える