Bootstrap

字符串的两种定义方式和底层细节

--------------------------------注 :此为 黑马程序员 相关课程笔记

定义字符串有两种方式 :

        一 、 利用字符数组 + 双引号的方式定义字符串

                        eg :     char str1[4] = "abc" ;

         注 :"abcd" 是一个字符串字面量,它实际上是一个字符数组 {'a','b','c','\n'}(注意末尾的空字符 \0,它表示字符串的结束)。

       底层 细节 :

       --------1 . 在底层,实际存储的时候,C语言还是会帮我们把字符串“abc”转换成字符数组进行保存,并且在末尾还要再加上 '\0' ,即 {'a','b','c','\0'} ;
       --------2 . 数组的长度,要么不写,如果要写的话,记得要把结束标记的空间给预留出来 ;

  现在来简单运行一下基本的字符串输出 :

#include<stdio.h>

int main()
{
	char str1[4] = "abc";
	printf("%s\n",str1);
	
	return 0;
}	

                >>>运行结果 : 

abc

--------------------------------
Process exited after 11.15 seconds with return value 0
请按任意键继续. . .


       -------3 . 字符数组 + 双引号 的方式定义字符串,内容是可以发生改变  (可写):

#include<stdio.h>

int main()
{
	char str1[4] = "abc";
	printf("%s\n",str1);
	
	str1[0] = 'Q';
	printf("%s\n",str1);
	
	return 0;
}	

                >>> 运行结果 : 

abc
Qbc

--------------------------------
Process exited after 1.045 seconds with return value 0
请按任意键继续. . .

--------------------------------------------------------------------------------------------------------------------------------                

       二 、利用 指针 + 双引号 的方式定义字符串

                                eg :        char* str2 = "abcd"  ;

                底层 细节 :

              -------1 :  在底层,实际存储的时候,C语言还是会帮我们把字符串“abc”转换成字符数组进行保存,并且在末尾还要再加上 '\0',即  {'a','b','c','d','\0'} ;
              -------2 :  利用 指针 + 双引号 的方式定义字符串,会把
底层的字符数组放在只读常量区;

  现在来简单运行一下基本的字符串输出 :

#include<stdio.h>

int main()
{
	char* str2 = "abcd";
	printf("%s\n",str2);

	return 0;
}

                  >>>运行结果 : 

abcd

--------------------------------
Process exited after 0.4718 seconds with return value 0
请按任意键继续. . .

                              注:此时 return 回的值 为 0,表明 程序是正常结束的;

                       ----------------------------------------------------------------------------------

         # 只读常量区 特点:
                       (1)内容不可以修改 ;
                       (2)里面定义的字符串是
可以复用的 ;

(1)若强行对以指针方式定义的字符串进行修改 :

#include<stdio.h>

int main()
{
	char* str2 = "abcd";
	printf("%s\n",str2);
	
	str2[0] = 'Q';				
	printf("%s\n",str2);

	return 0;
}	

                >>> 运行结果 :

abcd

--------------------------------
Process exited after 1.686 seconds with return value 3221225477
请按任意键继续. . .

       我们会发现,在运行结果中,没有打印出修改之后的第二个 printf() 语句运行的结果,这是为什么呢?  

       这是因为,在上述修改过的代码中,“  str2[0] = 'Q' ;  ”这条语句在 指针 + 双引号 的字符串定义方式中出错了,并且,我们可以发现 :

  # 此时 return 回的值 为 3221225477,表明 程序不是正常结束的,它有真正的错误代码;

                       ----------------------------------------------------------------------------------

       而这也再次说明了,只读常量区里的内容是不可以进行修改的,如果进行了修改,程序就会有问题,并从此处直接停止运行,后面的代码也就不会再执行了;

(2)若再去定义一个指针使使其指向的内容与原先定义的指针所指向的内容相同 :

#include<stdio.h>

int main()
{
	char* str2 = "abcd";
	char* str3 = "abcd";
	
	printf("%p\n",str2);
	printf("%p\n",str3);

	return 0;
}	

通过打印两个指针的内存地址,我们会发现 :

                >>> 运行结果 :

0000000000404000
0000000000404000

--------------------------------
Process exited after 2.575 seconds with return value 0
请按任意键继续. . .

                他们的内存地址是相同的;

        其实,在定义了一个新的指针之后,程序此时会先去检查只读常量区中有没有原先指针所指向的内容如果有,那么只读常量区中便不会创建新的字符串,而是会复用已经存在的字符串

---------------------------------------------------------------------------------------------------------------------------------

那么,这块知识点在程序中注释显示后的整个模样如下:

#include<stdio.h>

int main()
{
	/*		两种定义字符串的方式		*/
	
	//	  1.  利用字符数组 + 双引号的方式定义字符串
	
	char str1[4] = "abc";
	printf("%s\n",str1);
	
	//	  细节1:
	//			在底层,实际存储的时候,C语言还是会帮我们把字符串“abc”转换成字符数组进行保存,并且在末尾还要再加上 '\0'
	//			{'a','b','c','\0'};
	
	
	//	  细节 2:
	//			数组的长度,要么不写,如果要写的话,记得要把结束标记的空间给预留出来
	
	//	  细节 3:
	//			字符数组 + 双引号的方式定义字符串,内容是可以发生改变的
	
	str1[0] = 'Q';
	printf("%s\n",str1);
	
	
	//	   2. 利用指针 + 双引号的方式定义字符串
	
	char* str2 = "abcd";		//		char str[5] = {'a','b','c','d','\0'};    可读,可写(修改)
	char* str3 = "abcd";		//	此时会检查 只读常量区中 有没有 "abcd",如果有,就不会创建新的,而是会复用已经存在的
	
	//	  细节1:
	//	  		在底层,实际存储的时候,C语言还是会帮我们把字符串“abc”转换成字符数组进行保存,并且在末尾还要再加上 '\0'
	//			{'a','b','c','d','\0'};
	
	//	  细节2:
	//			利用指针 + 双引号的方式定义字符串,会把底层的字符数组放在只读常量区
	
	//	只读常量区特点:
	//		内容不可以修改
	//		里面定义的字符串是可以复用的
	
	/*   若强行修改,则会报错
			str2[0] = 'Q';				//		没有运行    程序直接结束,后面代码不会再执行
			printf("%s\n",str2);		//		程序不是正常结束的,它有真正的错误代码
	*/
	
	
	printf("%p\n",str2);				//		打印 str2 和 str3 内存地址,检验是否复用
	printf("%p\n",str3);
	//		 结果是 内存地址相同,进行了复用
	
	printf("%s\n",str2);
	
	return 0;
}

                <<< 运行结果 :

abc
Qbc
0000000000404000
0000000000404000
abcd

--------------------------------
Process exited after 1.041 seconds with return value 0
请按任意键继续. . .

;