#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] 是字符数组中的第一个元素(一个字符)
- pName 是 &pName[0] 的快捷方式(指向数组第一个元素的指针)
您收到错误的原因是因为 strcpy 需要一个指向 char (char*) 的指针,而不是 char 值(这就是 pName[0] 的含义)
在处理 C 或 C++ 中的指针和数组时,将它们识别为非常不同的结构确实很有帮助(如果我没记错的话,我认为解释这种区别的最好的书之一是一本名为“Deep C Secrets”的书)。搅浑水的是这样一个事实,即允许从数组名称到指针的单向静默转换(语言对变量名称的处理不一致) - 但重要的是不要将这种衰减现象的存在解释为暗示等价。
为了帮助我们对此进行推理,让我们介绍一下“记忆细胞”的概念。我们将“记忆单元”建模为具有两个属性:
a) value
b) address
然后我们可以将一个简单的 C++ 变量建模为具有两个属性(在这个低抽象级别我们不需要类型):
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++ 中的变量名被求值时,它总是求值为其内存单元的值,但有一个例外:如果变量命名为数组变量。
如果变量是数组的名称,则它计算为内存单元的地址。
以上两行值得再次阅读。
以下是一些有助于阐明含义的示例(请参阅上述变量):
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
这绝不意味着数组变量与指针变量相同。
它们本质上具有不同的类型,任何将它们视为相同的尝试(即在一个翻译单元中将变量名定义为数组,在另一个翻译单元中定义为指针)都会导致不好的事情发生。
所以例如不要这样做:
// myproj_file1.cpp 整数数组[100] = { 0 }; // 这里 'array' 计算为第一个内存单元的 *address* // myproj_file2.cpp 外部 int* 数组;// 这里 'array' 计算为第一个内存单元的 *value* // 假设链接器链接了两者 // 如果你阅读程序集,它的作用是这样的: // extern int* array = (int*) array[0]; // 但它不是必须的,它可以做任何事情,因为行为是未定义的
我希望这有帮助。如果您仍然觉得进一步的澄清可能会有所帮助,请提出后续问题,并毫不犹豫地获取那本“Deep C Secrets”一书的副本(库?):)
--
ps 函数类型及其名称及其衰减与这篇文章的大部分内容无关
ps 我还故意遗漏了当数组绑定到引用类型时不会发生数组到指针的转换
没有区别。它们都会崩溃,因为您没有为 pName 分配任何空间。:)[编辑:不再崩溃 - 问题已被编辑]
主要区别在于风格,经常受其影响,适合周围代码的编写方式——主要是数组访问或主要是指针访问。
(编辑:假设你真的是 &pName[0] 正如布赖恩邦迪指出的那样。)
从技术上讲,strcpy(pName[0], dummy);
是不正确的。即使为它分配了内存。
这是因为pName[0]
它是 'char' 类型,而pName + 0
它是 char* 类型。它们都引用相同的内存,但方式不同。
然后编译器可以将其strcpy(pName[0], dummy);
转换strcpy((char*) pName[0], dummy);
为危险的隐式强制转换。如果您的编译器是一半体面,您将收到警告或错误(正如您在“错误 C2664”中看到的那样)。
数组只是一个自动(通常)分配给自动分配的内存块的指针。以您的示例为例,您可以将 dummy 声明为:
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);
给定第二种形式,(ptr + N)
仍然是一个指针,只是沿着数组更远。这就是为什么在您的示例中它在语法上是正确的。ptr[N]
是指针的取消引用并且是 char (在此上下文中)。
pName 是指向新分配内存的指针。char *pName = new char[10];
dummy 也是一个数组/指针。 char dummy[] = "dummy";
pName 是指针并指向基地址,即使您添加 (pName + 0) 仍然指向相同的内存位置,因为您只添加了 0。 strcpy(pName + 0,dummy);
strcpy 使用指针变量,并且您在第一个参数中传递值,因此您收到错误 strcpy(pName[0],dummy)