c语言中的字符串指针和字符数组
我刚开始学习C,发现一些关于字符串指针和字符串(字符数组)的混淆。谁能帮我清醒一下头脑吗c语言中的字符串指针和字符数组,c,string,pointers,compiler-errors,C,String,Pointers,Compiler Errors,我刚开始学习C,发现一些关于字符串指针和字符串(字符数组)的混淆。谁能帮我清醒一下头脑吗 // source code char name[10] = "Apple"; char *name2 = "Orange"; printf("the address of name: %p\n", name); printf("the address of the first letter of name: %p\n", &(*name)); printf("first letter of na
// source code
char name[10] = "Apple";
char *name2 = "Orange";
printf("the address of name: %p\n", name);
printf("the address of the first letter of name: %p\n", &(*name));
printf("first letter of name using pointer way: %c\n", *name);
printf("first letter of name using array way: %c\n", name[0]);
printf("---------------------------------------------\n");
printf("the address of name2: %p\n", name2);
printf("the address of the first letter of name2: %p\n", &(*name2));
printf("first letter of name2 using pointer way: %c\n", *name2);
printf("first letter of name2 using array way: %c\n", name2[0]);
// output
the address of name: 0x7fff1ee0ad50
the address of the first letter of name: 0x7fff1ee0ad50
first letter of name using pointer way: A
first letter of name using array way: A
---------------------------------------------
the address of name2: 0x4007b8
the address of the first letter of name2: 0x4007b8
first letter of name2 using pointer way: O
first letter of name2 using array way: O
所以我假设name和name2都指向他们自己的第一个字母的地址。那么我的困惑是(见下面的代码)
我创建了一个名为name2的char指针,name2指针指向“Apple”的第一个字母,这很好,然后我创建了另一个char数组,并在内存中分配了10个空间。然后尝试使用name4,它是指向“Apple”的第一个字母的地址。结果,我得到了一个编译错误
我对这种编程语言非常失望。有时它们的工作原理是一样的。但有时他们不会。有人能解释一下原因吗?如果我真的想在分隔行中创建字符串或字符数组。我怎么能做到呢
非常感谢…您不能直接将值重新分配给数组类型(例如,您的十字符数组
char
sname4
)。对于编译器来说,name4
是一个“数组”,您不能使用赋值=
运算符来使用字符串文本写入数组
为了将字符串“Apple”的内容实际移动到分配给它的十字节数组中(name4
),必须使用strcpy()
或类似的东西
您使用的name3
是完全不同的。它被创建为一个char*
,并初始化为垃圾或零(此时您还不能确定)。然后,将静态字符串“Apple”的位置指定给它。这是一个位于只读内存中的字符串,尝试写入name3
指针指向的内存永远不会成功
基于此,您可以推测最后一条语句试图将静态字符串的内存位置分配给表示10char
s集合的其他地方。该语言不为您提供执行此任务的预定义方式
这就是它的力量所在 当你说
char *name3 = "Apple";
char name4[10];
name4 = "Apple";
您正在声明name3
以指向静态字符串“Apple”
。如果您熟悉高级语言,可以将其视为不可变的(我将在本文中对此进行解释,因为它听起来像您以前编程过;关于技术原理,请查看C标准)
当你说
char *name3 = "Apple";
char name4[10];
name4 = "Apple";
出现错误是因为您首先声明了一个包含10个字符的数组(换句话说,“指向”可变内存的10字节部分的开头),然后尝试将不可变值“Apple”
分配给该数组。在后一种情况下,实际的数据分配发生在内存的某个只读段中
这意味着类型不匹配:
error: incompatible types when assigning to type 'char[10]' from type 'char *'
如果希望name4
具有值“Apple”
,请使用strcpy
:
strcpy(name4, "Apple");
c[3] = 'e'; // Now c = "date", or 'd', 'a', 't', 'e', '\0'
strcpy(c, "hi"); // Now c = 'h', 'i', '\0', 'e', '\0'
strcpy(c, "too long!") // Error: overflows into memory we don't own.
如果希望
name4
具有初始值“Apple”
,也可以这样做:
char name4[10] = "Apple"; // shorthand for {'A', 'p', 'p', 'l', 'e', '\0'}
这是因为“Apple”
是char[]
的有效数组初始化器。换句话说,您正在创建一个10字节的字符数组,并将其初始值设置为“Apple”
(剩余位置为0)
如果考虑int数组,这可能更有意义:
int array[3] = {1, 2, 3}; // initialise array
可能我能想到的最简单的口语解释是数组是事物的bucket集合,而静态字符串
“Apple”
是“那边”的单个事物
strcpy(name4,“Apple”)
可以工作,因为它将“Apple”
中的每个东西(字符)逐个复制到name4
中
然而,说“这个桶集合等于那边的那个东西”是没有意义的。用值“填充”存储桶才有意义。尽管指针和数组看起来很熟悉,但它们是不同的。
char*name3
只是一个指向char
的指针,它只占用一个指针的内存。它只在其中存储一个地址,因此您可以为它分配一个字符串,然后将存储在name3
中的地址更改为“Apple”
的地址
但是你的
name4
是一个char[10]
数组,它保存着10个char的内存,如果你想分配它,你需要使用strcpy
或其他东西来写它的内存,但不要给它分配一个像“Apple”
这样的地址,我想这也会有助于清除它:
int main() {
char* ptr = "Hello";
char arr[] = "Goodbye";
// These both work, as expected:
printf("%s\n", ptr);
printf("%s\n", arr);
printf("%s\n", &arr); // also works!
printf("ptr = %p\n", ptr);
printf("&ptr = %p\n", &ptr);
printf("arr = %p\n", arr);
printf("&arr = %p\n", &arr);
return 0;
}
输出:
你好
再见
再见
ptr=0021578C
&ptr=0042FE2C
arr=0042FE1C\\相同!
&arr=0042FE1C/
所以我们看到,arr==&arr
。由于它是一个数组,编译器知道您总是想要第一个字节的地址,不管它是如何使用的
arr
是一个7+1字节的数组,位于main()
的堆栈上。编译器生成保留这些字节的指令,然后用“再见”填充它。没有指针
另一方面,
ptr
是一个指针,也是堆栈上的一个4字节整数。这就是为什么&ptr
与&arr
非常接近的原因。但它指向的是一个静态字符串(“Hello”),它在可执行文件的只读部分处于关闭状态(这就是为什么ptr
的值是一个非常不同的数字)。您可以在声明数组时初始化它,如下所示:
int n[5] = { 0, 1, 2, 3, 4 };
char c[5] = { 'd', 'a', 't', 'a', '\0' };
但由于我们通常将字符数组视为字符串,C允许一种特殊情况:
char c[5] = "data"; // Terminating null character is added.
但是,一旦声明了数组,就不能重新分配它。为什么?考虑一个类似的任务
char *my_str = "foo"; // Declare and initialize a char pointer.
my_str = "bar"; // Change its value.
第一行声明了一个char指针,并将其“瞄准”在foo
中的第一个字母。由于foo
是一个字符串常量,它与所有其他常量一起驻留在内存中的某个位置。当您重新分配指针时,您将