我读到了:
char a[] = "string";
是a: "string"
,而
char *ptr = "string"
是ptr: [__] ---> "string"
如果是阵列?如何清楚地区分char
指针和char
数组?
答案 0 :(得分:5)
图表可能有所帮助。
char *ptr = "string";
+-------+ +----------------------------+
| ptr |--------->| s | t | r | i | n | g | \0 |
+-------+ +----------------------------+
char a[] = "string";
+----------------------------+
| s | t | r | i | n | g | \0 |
+----------------------------+
这里,ptr
是一个变量,它包含指向某些(常量)数据的指针。您可以随后通过为ptr
分配新值来更改其指向的内存地址,例如ptr = "alternative";
- 但您无法合法地更改持有"string"
的数组的内容(它是正式只读或const
,并尝试修改它可能会使程序崩溃,或以其他方式意外破坏事件。)
相比之下,a
是使用值"string"
初始化的7字节数据的第一个字节的常量地址。我没有为地址显示任何存储空间,因为与指针变量不同,没有一个可更改的存储空间来保存地址。您无法更改a
指向的内存地址;它总是指向同一个空间。但您可以更改数组的内容(例如,strcpy(a, "select");
)。
调用函数时,差异消失:
if (strcmp(ptr, a) == 0)
…string is equal to string…
strcmp()
函数接受两个指向常量字符数据的指针(因此它不会修改给予仔细检查的内容),并且ptr
和a
都被传递为指针值。有一种强有力的理由说只有指针传递给函数 - 从不传递数组 - 即使函数是使用数组符号编写的。
然而,这是至关重要的,数组(在参数列表之外)不是指针。断言的其他原因包括:
sizeof(a) == 7
sizeof(ptr) == 8
(对于64位)或sizeof(ptr) == 4
(32位)。答案 1 :(得分:2)
如果是字符指针,它会存储哪个地址?这个块代表什么(我指向字符串的块)。它是"字符串"的起始地址。
此块表示WORD或DWORD(依赖于体系结构),此块的内容是内存地址,是在编译时定义的随机位置。该内存地址是字符串第一个字符的地址。
实际上,不同之处在于它使用了多少堆栈内存。
例如,当为微控制器编程时,为堆栈分配的内存非常少,会产生很大的不同。
char a[] = "string"; // the compiler puts {'s','t','r','i','n','g', 0} onto STACK
char *b = "string"; // the compiler puts just the pointer onto STACK
// and {'s','t','r','i','n','g',0} in static memory area.
也许这会帮助你理解。
assert(a[0] == 's'); // no error.
assert(b[0] == 's'); // no error.
assert(*b == 's'); // no error.
b++; // increment the memory address, so points to 't'
assert(*b == 's'); // assertion failed
assert(*b == 't'); // no error.
答案 2 :(得分:2)
char a[] = "string";
使用值char
初始化名为a
的{{1}}数组的值。以及string
的大小。
a
在内存中的某处创建一个未命名的char *a = "string";
静态数组,并将此未命名数组的第一个元素的地址返回给char
。
在第一个中,a
存储数组的第一个元素的地址。因此,当我们索引像[4]这样的东西时,这意味着“采取”#39;名为a。
在第二部分中,a
表示“采取”#39;指向对象后面的第4个元素。
关于你的上一个问题:
char数组是一个'块' char类型的连续元素char指针是对char类型元素的引用。
由于指针算术,指针可用于模拟(和访问)数组。
也许这3个链接有助于更清楚地区分:
http://c-faq.com/decl/strlitinit.html
答案 3 :(得分:1)
您可能会发现有用的想法:
char * a = "string";
与:
相同char SomeHiddenNameYouWillNeverKnowOrSee[] = "string"; /* may be in ReadOnly memory! */
char * a = &SomeHiddenNameYouWillNeverKnowOrSee[0];
答案 4 :(得分:1)
你有没有试过用文本编辑器打开一些可执行文件?它看起来只是垃圾,但在垃圾的中间你可以看到一些可读的字符串。这些都是您程序中定义的所有字符串。
printf("my literal text");
char * c = "another literal text"; // should be const char *, see below
如果您的程序包含上述代码,您可以在程序的二进制文件中找到my literal text
和another literal text
(实际上它取决于二进制格式的详细信息,但它通常有效)。如果您是Linux / Unix用户,也可以使用strings命令。
顺便说一句,如果你编写上面的代码,C ++编译器会发出一些警告(g ++说:warning: deprecated conversion from string constant to ‘char*’
因为这些字符串不是char *
类型而是const char []
(const char数组)当分配给指针时衰减到const char *
。
C编译器也是这种情况,但上述错误非常常见,通常会禁用此警告。 gcc甚至不包含在-Wall中,你必须通过-Wwrite-strings
明确地启用它。警告为warning: initialization discards ‘const’ qualifier from pointer target type
。
它只是提醒你理论上不允许你通过指针改变文字文本。
可执行文件可以在数据段内存的只读部分加载此类字符串。如果您尝试更改字符串的内容,则可能会引发内存错误。此外,允许编译器通过合并相同的字符串来优化文本文本存储。指针只包含(只读)内存中将加载文字字符串的地址。
另一方面
char c[] = "string";
仅仅是char c[7] = {'s', 't', 'r', 'i', 'n', 'g', 0};
的语法糖如果在代码中执行sizeof(c)
,它将是7个字节(数组的大小,而不是指针的大小)。这是一个带有初始化器的堆栈数组。在内部,编译器可以执行它喜欢初始化数组。它可以是在数组中逐个加载的字符常量,也可以包含一些hiden字符串文字的memcpy。问题是你没有办法区分你的程序并找出数据的来源。只有结果很重要。
顺便说一下,有点令人困惑的是,如果你定义类型char c[]
的某个函数参数,那么它将不是数组而是char * c
的替代语法。
答案 5 :(得分:0)
在您的示例中,ptr包含字符串中第一个char的地址。
至于char数组和字符串之间的区别,在C术语中除了按照惯例我们称之为“string”的事实是最终char为NULL的char数组之外没有区别,以终止字符串。
即。即使我们有一个包含256个潜在元素的char数组,如果第一个(第0个)char为null(0),则字符串的长度为0.
考虑一个变量 str ,它是一个char 数组,包含5个字符,包含字符串'foo'。
*ptr => str[0] 'f'
str[1] 'o'
str[2] 'o'
str[3] \0
str[4] ..
此数组的 char * ptr 将引用第一个元素(index = 0),第4个元素(index = 3)将为null,标记'string'的结尾。第5个元素(index = 4)将被符合null终止符的字符串处理例程忽略。
答案 6 :(得分:-1)
如果您在询问每种情况下包含的内容,那么:
char a[] = "string";
// a is a pointer.
// It contains the address of the first element of the array.
char *a = "string";
// Once again a is a pointer containing address of first element.
正如rnrneverdies在他的回答中所解释的那样,区别在于元素的存储位置。