#include <cstring>
int main()
{
char *pName = new char[10];
char dummy[] = "dummy";
strcpy(pName + 0,dummy);//how this is different from -->this works
strcpy(pName[0],dummy);//this one...--> error C2664: 'strcpy' :
//cannot convert parameter 1
//from 'char' to 'char *'
}
6 に答える
- pName[0] は文字配列の最初の要素 ( 1文字)
- pName は &pName[0] へのショートカットです (配列の最初の要素へのポインター)
エラーが発生する理由は、strcpy が char 値 (pName[0] とは) ではなく、char へのポインター (char*) を想定しているためです。
CまたはC++でポインターと配列を扱う場合、それらを非常に別個の構造として認識するのに役立ちます(この区別を説明する最高の本の1つは、正しく覚えていれば「DeepCSecrets」と呼ばれる本だと思います)。水を濁すのは、配列名からポインターへの一方向のサイレント変換が許可されているという事実です(言語の変数名の処理の不一致)-しかし、この減衰現象の存在を暗示していると解釈しないことが非常に重要です等価。
これについて推論するのを助けるために、「メモリセル」のアイデアを紹介しましょう。「メモリセル」は、次の2つの属性を持つものとしてモデル化されます。
a) value
b) address
次に、単純なC ++変数を2つの属性を持つものとしてモデル化できます(この低レベルの抽象化では型は必要ありません)。
c) name
d) memory cell
ほとんどのモデルと同様に、いくつかの欠点があります(複数の要素を持つ配列は処理しませんが、目的には十分です)。
したがって、たとえば:
// non-array variable: name 'i', and memory cell: value=3, address=0x0A
int i = 3;
// non-array variable: name 'p', and memory cell: value=0x0A, address=0x0B
int *p = &i;
// array variable: name 'a', and memory cell: vale=4, address=0x0C
int a[1] = { 4 };
// non-array variable: name 'b', and memory cell: value=0x0C, address = 0x0D
int (*b)[1] = &a;
// non-array variable: name 's', and memory cell: value=0x0C, address = 0x0E
int *s = &a[0];
// non-array variable: name 't', and memory cell: value=0x0C, address = 0x0F
int *t = a; // Here is the key difference! read on...
ここで、配列変数と非配列(ポインター)C++変数の主な違いは次のとおりです。
C ++の変数名が評価されるとき、1つの例外を除いて、常にそのメモリセルの値に評価されます。変数が配列変数に名前を付ける場合です。
変数が配列の名前である場合、それはメモリセルのアドレスに評価されます。
上記の2行はもう一度読む価値があります。
影響を明確にするのに役立ついくつかの例を次に示します(上記の変数を参照)。
int k = i; // the 'i' name evaluates to the value of its cell, so 'k' is set to 3
int *q = p; // 'p' evaluates to the value of its cell, so 'q' is set to 0x0A
int *r = a; // 'a' evaluates to the *address* of its cell, so 'r' is set to 0x0C
int (*c)[1] = b; // 'c' is set to 0x0D
これは、配列変数がポインター変数と同じであることを意味するものではありません。それらは本質的に異なるタイプを持っており、それらを同じ
ものとして処理しようとすると(つまり、変数名を1つの変換単位では配列として定義し、別の変換単位ではポインターとして定義する)、悪いことが起こります。
したがって、たとえば、これを行わないでください。
// myproj_file1.cpp int array [100] = {0}; //ここで「配列」は最初のメモリセルの*アドレス*に評価されます // myproj_file2.cpp externint*配列; //ここで「配列」は最初のメモリセルの*値*に評価されます //リンカーが2つをリンクすると仮定します //アセンブリを読んだ場合の動作は、次のようになります。 // extern int * array =(int *)array [0]; //ただし、動作が定義されていないため、実行する必要はありません。何でも実行できます。
これがお役に立てば幸いです。それでもさらに説明が役立つと思われる場合は、フォローアップの質問をして、その「Deep CSecrets」の本のコピー(ライブラリ?)を入手することを躊躇しないでください:)
--ps関数の型とその名前、およびそれらの減衰は、この投稿のほとんどとは無関係ですps
また、配列が参照型にバインドされている場合、配列からポインターへの変換は発生しないことも意図的に省略しました
技術的にstrcpy(pName[0], dummy);
は、正しくありません。メモリが割り当てられていても。
これはpName[0]
、タイプが'char'でpName + 0
あるのに対し、タイプはchar*であるためです。どちらも同じメモリを参照しますが、方法が異なります。
コンパイラは、危険な暗黙のキャストにstrcpy(pName[0], dummy);
変わる可能性があります。strcpy((char*) pName[0], dummy);
コンパイラが半分まともな場合は、警告またはエラーが発生します(「エラーC2664」で見られるように)。
pNameは、新しく割り当てられたメモリへのポインタです。char *pName = new char[10];
ダミーは配列/ポインタでもあります。 char dummy[] = "dummy";
pNameはポインタであり、ベースアドレスを指しています。(pName + 0)を追加しても、同じメモリ位置を指しています。0を追加するだけだからです。 strcpy(pName + 0,dummy);
strcpyはポインタ変数を使用し、最初の引数に値を渡すため、エラーが発生します strcpy(pName[0],dummy)
違いはありません。pName にスペースを割り当てていないため、両方ともクラッシュします。:)[編集: クラッシュではなくなりました - 質問が編集されました]
主な違いは文体上のもので、周囲のコードの記述方法 (主に配列アクセスまたは主にポインター アクセス) によって影響を受けることがよくあります。
(編集: ブライアン・ボンディが指摘したように、あなたが本当に &pName[0] を意味していたと仮定します。)
配列は、自動的に割り当てられたメモリ ブロックに (通常は) 自動的に割り当てられる単なるポインタです。あなたの例を挙げると、ダミーを次のように等しく宣言できます。
char dummy[] = "dummy";
char *dummy = "dummy";
そして、配列構文またはポインター構文のいずれかを使用してデータにアクセスできます。
char ch = dummy[0]; // get the first element of the array
char ch = *dummy; // get the data pointed to by dummy
との両方[]
を*
ポインタと配列の再参照に使用できるため、以下は同等です。
array[N];
*(ptr + N);
2 番目の形式を考えると(ptr + N)
、配列のさらに先にあるポインタのままです。これが、あなたの例で構文的に正しい理由です。ptr[N]
ポインターの逆参照であり、char です (このコンテキストでは)。