试图理解指针和数组

时间:2010-10-09 01:24:57

标签: c++ c

  

可能重复:
  What is the difference between char s[] and char *s in C?

我想知道

之间有什么区别
char *p1 = "some string";

char p2[] = "some string";

就记忆而言,这些不能以同样的方式对待吗?

e.g。

void foo(char *p);

...

foo(p1);
foo(p2);

7 个答案:

答案 0 :(得分:4)

这里解释了所有内容:http://c-faq.com/aryptr/aryptr2.html

答案 1 :(得分:0)

p1是一个指针 - 所以你可以做指针算法,比如p1 ++

P2是一个固定长度的数组。你可以做一个sizeof(p2),它将返回12 你不能做p2 ++,即指针算法。

答案 2 :(得分:0)

前者将“some string”放在只读存储器中,将p1作为指向该字符序列的第一个字符的指针。您可以将p1的值更改为指向其他任何位置。

后者为堆栈上的p2保留空间,并将其内容存储为“some string”。您可以更改堆栈中的各个位置,但不能更改p2的值。例如,

p2 = "a new string" ;

是C中的未定义行为。当p2位于赋值语句的右侧时(我忘记了C标准中使用的措辞),它充当数组的第一个元素的地址(类型指向char的指针) )。

  

(第6.3.2.1节,第3段)“除非它是sizeof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则表达式具有''数组' type''转换为类型''指向类型'的指针,指向数组对象的初始元素,而不是左值。“

答案 3 :(得分:0)

char *p1 = "some string";

您正在堆栈上放置一个指向char的指针。这需要大约4个字节的内存(但可能不同)。然后,您将其设置为静态内存位置的地址。 该陈述的正确形式是:

char const *p1 = "some string";

因为这会强制字符串的内容是常量。

char p2[] = "some string";

您正在声明堆栈上的大小为12(字符串长度加nul)的数组。这是12个字节的数据。您可以修改数组的内容,但是当作为参数传递或分配给char *时,您无法更改它降级的指针。

这两个陈述有很大的不同之处:

p1 = new char[50];  // legal
p2 = new char[50];  // illegal

p1[2] = 'a';  // illegal
p2[2] = 'a';  // legal

当作为参数传递给函数时,变量如下所示:

char const *p1;  // this is what p1 is
char *const p2;  // this is what p2 degrades to. It is a const pointer to the first element.

答案 4 :(得分:0)

它们彼此相关,但存在很大差异。

char p2[] = "some string";

请求12个字符的空格,并且名称为p2。另一方面:

char *p1 = "some string";

请求一个包含一个名为p1的指针的地方,它可以指向任何地方。在这种情况下,指针p1指向没有名称的数组,或12个字符的匿名数组。该匿名数组存在于内存中,指针p1正在跟踪其位置。

答案 5 :(得分:0)

在你的第一个案例中,......

char* p1 = "some string";

... p是指针类型char*的变量。它被初始化为指向某个char值序列中的第一个char。那个地方可能在只读存储器中,所以你永远不要这样做: - )。

相反,至少为指针类型添加const,例如......

char const* p2 = "some string";

这样您就已经要求编译器不接受修改尝试,这会将您发送到Undefined Behavior land。 C ++仅接受p1 的声明以向后兼容C.如果你打开C ++编译器的警告级别,你很可能会收到关于它的警告,同时声明{{1完全没问题。

由于p2本身不是p2,您可以修改它,例如增加它,使其指向第二个const或其他任何内容。

无论如何,指针不是很大,通常是4或8个字节。

在你的第二个案例中,......

char

... char a[] = "some string"; 是一个使用指定字符初始化的数组,加上一个终止空字节。根据定义,每个a是一个字节。因此,char将报告sizeof(a)为12个字节,即指定字符的11个字节,加上空字节。

在C和C ++中,当你使用a指向预期的指针时,你会自动转换为指向第一个数组元素的指针,我们非正式地说数组衰减进入指针类型。在C中,这种情况发生在将数组作为参数传递的所有情况下。但是,在C ++中,您可以通过引用传递数组,避免类型衰减。

使用衰减有利,你可以通过...找到数组的元素数量。

a

其中除了sizeof(a)/sizeof(*a) 之外,对于字节数组不需要除法,但对于其他类型的数组通常是必需的。

如果使用指针执行此操作,那么您只需获得以指针对象的大小为单位测量的指针大小,这很少有意义。

在C中没有其他合理的方法来查找数组的元素数,因此上面的表达式通常打包在一个宏中,并且只接受无意中使用带有指针参数的宏的风险(无意义的结果)

在C ++中,您可以使用通过引用传递数组的可能性来定义一个返回数组元素数的函数,例如......

a

使用指针作为实际参数调用typedef ptrdiff_t Size; template< class T, Size N > Size countOf( T const (&)[N] ) { return N; } ,您只会收到编译错误而不是无意义的结果。

对于C ++工作,定义countOfstartOf函数通常也很方便,特别是对于使用标准库中的算法。据我所知,第一个认识到这种三重功能的重要性的是Dietmar Kuhl。您可以在我的Wordpress博客上找到a general implementation,但不幸的是,我记得,我没有在那里提到Dietmar(而且我太懒了,无法解决问题!:-))。

C ++还对C没有的数组提供了一些其他支持。

特别是,作为新手,通常最好使用标准库中的endOf,而不是直接使用“原始数组”。

使用std::vector,您不太可能遇到与原始数组相关的许多陷阱,例如:元素数计算。

干杯&amp;第h。,

- Alf

答案 6 :(得分:0)

p1是一个指针。 p2是一个数组,在表达式中使用时会计算指针。

也许有一个类比:

int x1 = 5;
char x2 = 5;

x1intx2char,在表达式中使用时评估为int

在这两种情况下,当您尝试在对象中存储某些内容时,以及将sizeof运算符应用于它们时,差异就会变得明显。