在以下情况下,指针和数组有什么区别?

4
#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 *'

    }

1
我认为你的意思是strcpy(&(pName[0]), dummy);。 - Brian R. Bondy
6个回答

12
  • pName[0] 是字符数组中的第一个元素(一个字符)
  • pName 是 &pName[0] 的快捷方式(指向数组第一个元素的指针)

你出现错误的原因是因为 strcpy 期望传入一个 char 指针(char*),而不是一个 char 值(这就是 pName[0] 的类型)


指针上的 [] 运算符会做两件事情,即解引用和加法? - yesraaj
3
@yesraaj说:“是的。pName[5]和*(pName + 5)是相同的东西。” - Pedro d'Aquino
1
yesraaj: arrayPointer[1] 和 *(arrayPointer + 1) 是相同的。后者是“增加指针,使其指向数组中位置为1的项,然后取消引用以获取所指向的值”。 - Skurmedel
1
+1,努力争取“好答案”徽章 :) 这对于pName是正确的。一个来自silly litb的注意事项:并非在所有情况下都适用于dummy:“dummy”不是“&dummy[0]”的快捷方式。 - Johannes Schaub - litb

3
当处理C或C++中的指针和数组时,将它们视为非常不同的构造真的有助于理解(我认为最好的解释这种区别的书籍之一是一本叫做“深入C秘密”的书)。让我感到困惑的是,事实上从数组名称到指针允许进行单向无声转换(这是语言处理变量名称的一致性不足)-但是非常重要的是,不要将存在这种衰变现象解释为暗示等价性。
为了帮助我们思考这个问题,让我们引入“内存单元”的概念。我们将“内存单元”建模为具有两个属性:
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 int array[100] = { 0 }; // 这里 'array' 求值为第一个内存单元的*地址*
// myproj_file2.cpp extern int* array; // 这里 'array' 求值为第一个内存单元的*值* // 假设链接器将两个文件链接起来 // 如果你查看汇编代码,它做的事情类似于: // extern int* array = (int*) array[0]; // 但它可以执行任何操作,因为行为是未定义的
希望这可以帮到你。 如果你仍然觉得需要进一步解释,请提出跟进问题,并且不要犹豫去获取那本“深入C语言秘密”的书籍 :) -- p.s. 对于大多数本文内容来说,函数类型及其名称和衰减都是无关紧要的 p.s. 我还有意地省略了当数组绑定到引用类型时,不会发生数组到指针的转换

+1,干得好。我认为你对“变量”的定义也符合C++的定义,即:“变量是通过对象的声明引入的。变量的名称表示对象。”这些是你所定义的变量的两个属性:名称和内存单元(对象=具有相关属性(类型、存储期、是否存活等)的存储区域,内存单元=该区域的起始位置)。 - Johannes Schaub - litb

0

数组只是一个指针,通常自动分配给自动分配的内存块。以您的示例为例,您可以将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

在编程中,[]*都可以用于指针和数组的dereference,因此以下两种写法是等价的:

array[N];
*(ptr + N);

给定第二种形式,(ptr + N)仍然是一个指针,只是在数组中更远的位置。这就是为什么在你的例子中它在语法上是正确的。ptr[N]是对指针的解引用,在这个上下文中是一个字符。

0

没有区别。由于您没有为pName分配任何空间,它们都会崩溃。 :) [编辑:不再崩溃-问题已被编辑]

主要区别是风格上的差异,通常受周围代码编写方式的影响-大多数是数组访问或指针访问。

(编辑:假设您确实意味着&pName [0],如Brian Bondy所指出的那样。)


0

从技术上讲,strcpy(pName[0], dummy); 是不正确的,即使为其分配了内存。

这是因为pName[0]是'char'类型,而pName + 0是char*类型。它们都引用相同的内存,但方式不同。

编译器可以将strcpy(pName[0], dummy);转换为strcpy((char*) pName[0], dummy);,这是一种危险的隐式转换。如果你的编译器足够好,你会得到一个警告或错误(就像你看到的"error C2664")。


0

pName是指向新分配内存的指针。 char *pName = new char[10];

dummy也是一个数组/指针。 char dummy[] = "dummy";

pName是指针并指向基地址,即使你添加(pName + 0)仍然指向相同的内存位置,因为你只是添加了0。 strcpy(pName + 0,dummy);

strcpy使用指针变量,并在第一个参数中传递值,因此您会得到错误 strcpy(pName[0],dummy)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接