1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <stdio.h>
main ()
{
char * ptr ;
ptr ="hello";
printf("%p %s" ,"hello",ptr );
getchar();
} |
嗨,我正在努力清楚地理解数组如何分配给指针。我注意到当你把一个字符数组赋给一个chars-ptr="hello";的指针时,数组就衰减到指针上,但在这种情况下,我要给数组赋一个字符,它不在一个变量内,也不在一个包含变量的变量内",这种分配方式是不是专门为"Hello"取一个内存地址(显然发生了什么),它是不是可以修改"hello"中每个元素的值,它包含在存储该数组的内存地址中。作为比较,我是否可以为一个指针分配一个数组,例如ints,比如thisint_ptr = 5,3,4,3;,值5、3、4、3和"hello"一样位于内存地址中。如果不是,为什么只有字符串才有可能?提前谢谢。
"hello"是字符串文字。它是char [6]类型的无名称不可修改对象。它是一个数组,其行为与其他数组相同。它是无名的事实并没有真正改变任何事情。您可以将它与[]运算符一起使用,例如在"hello"[3]等中。就像其他数组一样,它可以并且将在大多数上下文中衰减到指针。
不能修改字符串文字的内容,因为它在定义中是不可修改的。它可以物理存储在只读存储器中。如果其他字符串文本包含常见的子字符序列,则它可以重叠。
通过复合文字语法,其他数组类型也有类似的功能。
1
| int *p = (int []) { 1, 2, 3, 4, 5 }; |
在这种情况下,右侧是一个类型为int [5]的无名对象,它衰减到int *指针。不过,复合文字是可以修改的,这意味着您可以执行p[3] = 8,从而用8替换4。
还可以对char数组和do使用复合文字语法
1
| char *p = (char []) {"hello" }; |
在这种情况下,右侧是一个类型为char [6]的可修改的无名称对象。
- 注意,复合文字是c99
- @纽阿克特:是的,但我相信我们已经远远超过了必须明确提及的那一点。
首先,您应该阅读comp.lang.c常见问题解答的第6节。
字符串文字"hello"是char[6]类型的表达式(5个字符表示"hello",另一个字符表示终止'\0')。它是一个具有静态存储持续时间的匿名数组对象,在程序启动时初始化为包含这6个字符的值。
在大多数上下文中,数组类型的表达式被隐式转换为指向数组第一个元素的指针;例外情况如下:
- 当它是sizeof的参数时(sizeof"hello"产生6,而不是指针的大小);
- 当它是EDOCX1(c11的一个新特性)的论点时;
- 当它是一元&的参数时(&arr产生整个数组的地址,而不是第一个元素的地址;相同的内存位置,不同的类型);以及
- 当它是初始化数组对象的初始值设定项中的字符串文字时(char s[6] ="hello";复制整个数组,而不仅仅是指针)。
这些例外都不适用于您的代码:
1 2
| char *ptr;
ptr ="hello"; |
所以表达式"hello"被转换为("decays"to)指向上述匿名数组对象的第一个元素('h')的指针。
所以*ptr == 'h',你可以通过内存推进ptr来访问其它字符:'e'、'l'、'l'、'o'和'\0'。这就是当你给它一个"%s"格式时printf()所做的。
与字符串文字相关联的匿名数组对象是只读的,但不是const。这意味着,任何试图修改该数组或其任何元素的尝试都有未定义的行为(因为标准明确地这么说),但编译器不一定会警告您。(C++使字符串文本EDOCX1为20);在C中做同样的事情会破坏在EDOCX1之前添加的现有代码(20加法被添加到语言中)。因此,不,你不能修改EDOCX1×0的元素——或者至少你不应该尝试。为了使编译器在您尝试时发出警告,您应该将指针声明为const:
1 2
| const char *ptr; /* pointer to const char, not const pointer to char */
ptr ="hello"; |
(GCC有一个选项,-Wwrite-strings,使其将字符串文本视为const。这将导致它警告某些C代码在标准方面是合法的,但这些代码可能应该修改为使用const。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <stdio.h>
main ()
{
char * ptr ;
ptr ="hello";
//instead of above tow lines you can write char *ptr ="hello"
printf("%p %s" ,"hello",ptr );
getchar();
} |
这里您已经将字符串文字"hello"分配给ptr,这意味着字符串文字存储在只读内存中,因此您不能修改它。如果声明char ptr[] ="hello";,则可以修改数组。
说什么?
您的代码分配了6个字节的内存,并用值"h"、"e"、"l"、"l"、"o"和"0"对其进行初始化。
然后它分配一个指针(指针的字节数取决于实现),并将指针的值设置为前面提到的5个字节的开头。
可以使用诸如ptr[1] = 'a'之类的语法修改数组的值。
在语法上,字符串是一种特殊情况。因为C没有特定的字符串类型,所以它提供了一些快捷方式来声明它们等等。但您可以轻松地创建与使用int的字符串相同类型的结构,即使语法必须稍有不同。
- ptr[1] = 'a';可以或不可以执行和/或可以或不可以在字符串中将'e'的值修改为'a'。大多数现代系统(Linux、MacOS X、Windows NT、2K、XP等-在Win98等系统上不确定)在执行此操作时都会出现故障,因为它是"只读内存"。
- 这就是为什么我用更通用的术语"修改数组的值",以避免关于访问的问题,这实际上是一个完全不同的问题。