Array type is not assignable

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main(void) {
char str[4];
str = "abc";

for (size_t i = 0; i < 3; i++) {
printf("%c\n", str[i]);
}

return 0;
}
1
error: array type 'char [4]' is not assignable

第一种

1
char str[4] = "abc";

在变量初始化时,就进行赋值。在长度为4的char数组中,’a’放进str[0],’b’放进str[1],’c’放进str[2],’\0’放进str[3]分别放入a b c 元素

第二种

1
2
char *str;
str = "abc";

这是声明一个char型指针变量 str,然后创建一个字符串常量”abc”,然后char指针 str 指向这个常量的内存,其实你可以试试,你可以通过str输出这个字符串(可以读),但是不能更改它(不能写)。因此在C++11里,对类型加了更强的定义,即指针指向的内容如果不可修改,就建议把该指针确认为const指针类型;如果不加const标志符,就提示一个警告。

第三种

1
2
char str[4];
str = "abc";

这种是有语法错误的,先声明一个char数组str[4],这时候str[4]有一块内存,而str作为数组名,相当于一个指针常量,固定指向str[4]这个数组的第一个元素的地址。
而你使用str=”abc”,相当于想要给一个指针常量赋值,所以显然是有语法错误的。想想你对一个常量赋值,当然会有错误!!

总结

数组名只是代表数组第一个元素的地址的值,比如数组 int a[10],a实际上就是 &a[0],它只是一个值,就像 5 这类东西一样,是不能作为左值的,不能给它赋值。
所谓指针只是一种保存地址的变量,单独用数组名的时候它只是数组第一个元素的地址的值,
并不是保存第一个元素地址的变量

所以在任何时候都不能把数组名直接放在等号的左边,这个问题跟字符串什么的并没有什么关系。

字符串常量修改与赋值

结论

  • 数组c的声明,是将字符串常量“复制”到数组中,复制来的字符串是可以修改的
  • 指针p的声明,指向的是字符串常量的地址,而常量只读不可修改
  • 关键:如果直接赋值字符串(实际上是赋值地址)时,会在字符串常量区开辟对应内存存放字符串,如果赋值给指针p,那么p中的内容就不可修改。因为p是指向常量区的,而常量区中的内容是不可修改的。如果是动态分配,在赋值字符串,同理;但是如果使用strcpy,那么就相当于再堆内存中写入对应的字符串内容,而非直接赋值地址,那么此时p指向的内容就可以修改。
    1
    2
    3
    4
    5
    6
    7
    8
    char* p, *m;
    p = (char*)malloc(30);
    m = (char*)malloc(30);
    p = "hello";
    char* q="hello";
    char c[30] = "hello";
    p[2] = 'A';
    puts(p);

分析

指针p的存储地址为 0x004FFD5C
指针q的存储地址为 0x004FFD44
你会发现他们地址几乎都在一起,因为他们存储的地方是栈内存
要知道p = "hello";意思是将字符串"hello"的地址存储到p内
而p内存储字符串的地址为 0x00667B30
q内存储的字符串的地址为 0x00667B30
你会发现存储的地址是一样的,说明字符串"hello"的地址放在一个地方,也就是我们说的字符串常量区,字符串常量区内的元素,只读不可修改
你们会问,为什么p内的地址为字符串常量的地址呢?
首先,指针p申请动态内存后,p内存储的是申请的内存的起始地址,而之后,p又存储字符串“hello”的地址,所以,最后p内存储的地址为字符串常量“hello”的地址。

1
2
3
4
5
6
7
8
9
10
11
int main() {
char* p, *m;
p = (char*)malloc(30);
m = (char*)malloc(30);
//p = "hello";
strcpy(p, "hello");
char* q="hello";
char c[30] = "hello";
p[2] = 'A';
puts(p);
}

大家又会问:为什么用strcpy(p, "hello");
因为字符串被复制到堆内存中,而不是访问字符串常量区
指针p首先动态申请内存,这时,指针p的值是申请的内存起始地址,所以strcpy是将字符串复制到申请的内存当中。所以使用strcpy后,p中的内容是可以修改的。