char*s = “hello world” 是不是字符串?
用C/C++的老铁们可能对这个都比较熟悉。char* s = "Hello World";这样定义字符串很简单呀,很方便。不用去考虑大小呀什么的,简单快捷。是,这样子是挺方便,而且编译也不会报错会通过,程序也能跑,但是实际上,这样子做是不好的,严格意义上来讲,这样其实是定义了一个野指针。下面我们就用一段代码来阐述这件事情。
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main() 5 { 6 7 char* s = "hello world"; 8 char* s1 = "hello world"; 9 printf("s = %s\n", s); 10 printf("s1 = %s\n", s1); 11 printf("addr_s = %p\n", s); 12 printf("addr_s1 = %p\n", s1); 13 }
我们按照这种方式定义了两个“字符串”,我们通过printf函数看一下这个字符串能否正常的输出,并且我们也看一下s和s1在内存中的地址。
最终我们看到虽然程序报了两个warning,但是程序依然可以继续运行。通过程序的输出我们可以看到,s和s1都能够正常的输出我们想要的hello world字符串。但是有一个地方值得注意,s和s1拥有着相同的地址。那么是不是所有的字符串都是这样的呢,我们换一种方式去定义。
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main() 5 { 6 7 char* s = "hello world"; 8 char* s1 = "hello world"; 9 printf("s = %s\n", s); 10 printf("s1 = %s\n", s1); 11 printf("addr_s = %p\n", s); 12 printf("addr_s1 = %p\n", s1); 13 char s2[12] = "hello world"; 14 char s3[12] = "hello world"; 15 printf("s2 = %s\n", s2); 16 printf("s3 = %s\n", s3); 17 printf("addr_s2 = %p\n", s2); 18 printf("addr_s3 = %p\n", s3); 19 20 }
我们通过数组的形式又去定义了两个字符串,这下我们再去看一下程序的输出。
我们看到,这次s2和s3并没具有相同的地址,而且值得注意的是,s、s1和s2、s3的内存地址相差较大。这是为什么呢?其实这是因为char* s = "hello world",这个操作是操作系统帮你完成的。本事char*s是一个野指针,我们并不知到“hello world”这个内容在哪,但是却让一个指针去指向它。那么不知道该指向谁的指针要怎么做呢?操作系统就会在特定的一个区域去帮它创建出这样的一块内存去存放“hello world”然后让这个指针去指向它。而且这块特殊的内存并不是属于程序本身的,而是属于操作系统的,那么这样就会造成你只可以去读这块区域,他不会允许你去修改这一块区域。这就是操作系统的保护机制,任何操作系统都是这样。
所以我们在定义字符串的时候就要有所考虑,什么时候用char* s 这样的字符串,什么时候用char s[12]这样的字符串。简单的说,如果你只是定义了一个字符串,后来并不会对他进行一些操作,那么你可以用这种char* s形式字符串,或者你想定义一个函数去接收一个字符串类型的参数也可以用这种字符串。如果想要后续的对字符串进行大量的操作,最好用数组类型的字符串,因为它不会去占用系统的内存,这样你就对这个字符串拥有了相对较高的权限。
所以char* s是一个字符串,只不过是一种权限比较低的字符串,它的使用并不安全,也并不完美——因为相同的字符串会占用同一个内存地址,所以在使用的过程中要多加考虑。