我认为没有图片就无法解释/理解这些。
char z[4];
这为您提供了一个由 4 个字符组成的数组,名称为 z:
+---+---+---+---+
z: | | | | |
+---+---+---+---+
这可以容纳最多三个字符的字符串(为结尾的 \0 留出空间)。
char *s = malloc(5);
char *s 部分为您提供指向char 的指针,它可以指向任何位置的任何字符。 malloc(5) 部分实际上为您提供了内存中某处(更正式地,在“堆”上)的 5 个字符的无名数组。然后=(赋值)运算符将前者指向后者。你可以想象它是这样的:
+---------------+
s: | * |
+-------|-------+
|
V
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
malloc 区域为最多 4 个字符的字符串提供空间。
因为指针可以指向任何地方,所以您可以稍后重新分配它们。例如,您可以让s 指向z 数组的第一个字符,通过说
s = &z[0];
那么你会有这张照片:
+---+---+---+---+
z: | | | | |
+---+---+---+---+
^
|
+-------|-------+
s: | * |
+---------------+
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
但现在我们来到了“有趣”的部分。一开始这听起来很奇怪或荒谬,但一旦你明白了,突然之间,C 对指针和数组(以及字符串)的处理就会变得更有意义。如果你说呢
s = z;
起初这可能没有意义。看起来我们正在尝试获取一个数组(在右侧)并将其分配给一个指针(在左侧)。这看起来像是类型不匹配。你也可能听说过(真的)你不能在 C 中分配数组。所以这看起来是不可能的。 但是,根据丹尼斯·里奇的特殊安排,你可以做到这一点,根据定义,就像你说的一样
s = &z[0];
即:每当你尝试在表达式中使用数组时,你得到的是指向数组第一个元素的指针。也就是说,在这个例子中,就像你说过&z[0].
确实,在 C 语言中存在两种传递字符串的方法:作为数组和作为指针。你可以用数组的方式说
char y[] = "cat";
char z[4];
strcpy(z, y);
或者你可以用指针的方式说
char *s = "bear";
char *t;
t = s;
这两种方法都将一个字符串“分配”给另一个字符串,但其中一种是通过复制字符(使用strcpy)来实现的,其中一种是通过操作指针来实现的。
我还掩盖了一点。当我说
char y[] = "cat";
编译器为我初始化了数组,给了我这个:
+---+---+---+---+
y: | c | a | t | \0|
+---+---+---+---+
但是当我说
char *s = "bear";
编译器在某处匿名内存中为我创建了字符串"bear",有点像(但绝对不完全像)当我调用malloc时:
+---------------+ +---+---+---+---+---+
s: | *-------------->| b | e | a | r | \0|
+---------------+ +---+---+---+---+---+
您也可以在一定程度上混搭。正如我们之前看到的,你可以让一个指针指向一个数组,这样就可以了:
t = z;
但是,当您复制字符串时,您必须确保有足够的空间。如果你说
strcpy(z, "kangaroo");
例如,事情可能会爆炸,因为“kangaroo”的字符数超过了数组z 可以容纳的字符数。
您还必须小心使用常量字符串。如果你刚刚说
char *s = "bear";
你不能说
strcpy(s, "kangaroo");
有两个原因:一是s指向的匿名数组不够大,但也许更重要的是s指向的匿名数组是常量,不允许乱写就可以了。