&str
和之间的区别str
,何时str
声明为char str[10]
?
读取 sizeof
运算符:
6.5.3.4 sizeof 运算符,1125:
将sizeof
运算符应用于数组类型时,结果是数组中的总字节数。
因此,根据您的声明,sizeof(str2)
给出的完整数组大小为 10 个字节(因为 N 定义为 10,而 char 大小为 1 个字节)。
而在表达式sizeof(&str2)
中,&str2
是一个数组的地址,并且该地址的大小在您的系统上是 4 个字节。(在某些系统中,地址大小可能为 8 个字节,例如 64 位)。
另外,&str2
也是 arr 中第一个元素的地址str2
吗?
不,在价值方面两者 &str2
和str
是相同的,但在语义上两者是不同的。一个是 10 个字符的数组的地址,而另一个是一个字符的地址。
您在自己的示例中看到它们之间的一个区别是(@ouah 在答案中对此进行了解释)。
- 类型
str
是char[10]
- 类型
&str
是char(*)[10]
第二:
按照图表将帮助您观察其他差异。
for declaration:
#define N 10
char str2[N] = {"Hello"};
str2 Array in memory is something like:
----------------------------------------
str
+----+----+----+----+----+----+----+----+----+----++----+
|'H' |'e' |'l' |'l' |'o' |'\0'|'\0'|'\0'|'\0'|'\0'|| '@'|
+----+----+----+----+----+----+----+----+----+----++----+
201 202 203 204 205 206 207 208 209 210 211
▲ ▲ ▲ ▲
| | | |
|(str2) (str2 + 1) |
| |
|-----------------------------------------------------|
|201 |
| |
| |
(&str2) = 201 (&str2 + 1) = 211
* assuming str address start from 201
* str[N] is 10 char long 201-210, partially initialized
* at uninitialized position, str2[i] = '\0'
* location 211 is unallocated, having garbage value,
access to this location is illegal-Undefined Behavior
对于上图,您可以编写如下代码:
#include <stdio.h>
#define N 10
int main(){
char str2[N]={"Hello"};
printf("\n %p, %p\n",str2, str2+1);
printf("\n %p, %p\n",(&str2), (&str2+1));
}
输出:
0xbf67e142, 0xbf67e143
0xbf67e142, 0xbf67e14c
键盘链接:
请注意,在第一行,输出地址相差一个字节,但在第二行,相差 10 个字节,因为它是数组的指针(如上图所示)。
根据指针算术规则,当你给一个指针变量加 1 时,它就开始指向它自己类型的下一个元素。这就是 10 字节差异的原因,因为&str2
是指向数组的地址。
第三个区别:
通过这样做*str2
,您可以访问第一个元素。而不*(&str2)
会给你第一个元素,相反,它会给出第一个元素的地址。
一个例子在这里会有所帮助:
#include <stdio.h>
#define N 10
int main(){
char str2[N]={"Hello"};
printf("\n%p %c, %p %c\n",str2, *(str2), *(&str2), **(&str2));
}
输出:
0xbf587046 H, 0xbf587046 H
键盘链接
在输出
str2 gives 0xbf587046
*(str2) H
*(&str2) 0xbf587046
**(&str2) H
这意味着*(&str2) == str2
和价值是地址。因此*(str2) = **(&str2)
值为H
。
编辑:上面我显示了 type 数组之间的 区别&str
和str
where 。str
char[10]
char *str
两者之间以及char str[]
如何存储在内存中的区别
假设我们有两个如下声明:
char *str1 = "hello";
char str2[] = "hello";
在上面的声明str1
中是一个指向 的指针char
,它指向一个常量字符串文字(通过保存字符串中第一个字符h
的地址"hello"
)。
C 中的字符串属于char[N]
(array) 类型,这就是为什么sizeof("hello")
给出 6 的原因,因为"hello"
字符串是 6 个字符长的数组(包括\0
nul、字符串终止、hello 的类型char[6]
)。
在内存中,您的"hello"
字符串存储如下:
str1 23 24 25 26 27 28
+----+ +----+----+----+----+----+----+
| 23 | | h | e | l | l | o | \0 |
+----+ +----+----+----+----+----+----+
+-----------▲
here the address of the hello string is the first address = 23.
str1: is a pointer capable of storing an address.
"hello" consists of 6 chars
char* str1 = "hello";
基本上将字符串 hello 的地址存储到指针变量str1
中,如上图所示。
注意:如果需要,您可以更改str1
为指向其他字符串。但是你不能修改hello
字符串。例如以下代码是有效的:
char* str1 = "hello"; // str1 points to hello str1-->"hello"
str1 = "world"; //Now, str1 points to world str1-->"world"
现在str1
指向其他常量字符串世界。
str1 93 94 95 96 97 98
+----+ +----+----+----+----+----+----+
| 93 | | w | o | r | l | d | \0 |
+----+ +----+----+----+----+----+----+
+-----------▲
here address of world string is first address = 93.
str1: value change to point string world.
需要注意的重要一点:str1
指向常量字符串,因此您不能通过访问/索引内存位置来修改字符串str1[i] = 'A'
;将是非法的,因为您正在只读内存上写入,并且此行为在运行时未定义(尽管没有编译错误,因为在语法上它是正确的)。
同样,因为str1
is 一个指针sizeof(str1)
将在同一台机器上给出 4。
我的以下代码及其运行:
#include <stdio.h>
int main(){
char* str1="Hello";
printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));
str1 = "world";
printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));
return 1;
}
输出:
str1: Hello, address: 0x80485e8, sizeof(str1): 4
str1: world, address: 0x8048619, sizeof(str1): 4
键盘链接
因此,要分配一个新字符串,我只需分配一个新字符串的地址。但我不能称strcpy()
它会尝试在只读内存位置上写入,这是非法的。
在第二个声明char str2[] = "hello";
中,str2[]
是一个\0
终止的字符(或字符串)数组,但不是指针。注意,因为在这个声明中 size 没有给出默认大小,我们看到常量字符串“hello”的大小是 6。类型str2
是char[6]
。
当我们char str2[] = "hello";
创建一个 char 数组时,hello 字符串将被复制到该数组中。所以str2
不仅仅是一个指针,而是一个存储完整字符串的数组。
从概念上讲,它就像
str2:
103 104 105 106 107 108
+----+----+----+----+----+----+
| h | e | l | l | o | \0 |
+----+----+----+----+----+----+
在这种情况下,最近在您的代码中您不允许这样做str2[] = "world";
or str2 = "world"
,这将是编译时错误。
示例代码:
#include<stdio.h>
int main(){
char str2[] = "hello";
str2[] = "world";
str2 = "world";
return 1;
}
编译错误:
In function 'main':
Line 4: error: expected expression before ']' token
Line 5: error: incompatible types in assignment
Codescape 链接
如果这个数组str2
不是一个常数,我们可以修改它的内容,例如做str2[2] = 'A'
是完全有效的。我们也可以调用strcpy来改变内容(地址空间不会改变)
strcpy(str2, "world");
str2:
103 104 105 106 107 108
+----+----+----+----+----+----+
| w | o | r | l | d | \0 |
+----+----+----+----+----+----+
Note that when "world" is copied into a same memory space, the addresses of both "world" and "hello"
string are the same.
代码示例:
#include<stdio.h>
int main(){
char str2[] = "hello";
printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
str2[2] = 'A';
printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
strcpy(str2, "world");
printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
return 1;
}
输出:
str2: hello, address: 0xbf58d056, sizeof(str2): 6
str2: heAlo, address: 0xbf58d056, sizeof(str2): 6
str2: world, address: 0xbf58d056, sizeof(str2): 6
键盘链接
注意:相同地址空间上的字符串值不同。sizeof(str2)
= 6 从较早的答案中可以完全理解,即数组的大小(以字节为单位)。
要阅读关于二维数组的类似描述,请阅读:两者在内存中存储的区别char* str[]
和方式?char str[][]