字符串的数组形式和指针形式声明及其区别 整理版(摘自《C Primer Plus 中文版第六版》第11章及黑马程序员2018C语言提高深入浅出ch1-5 )

本节内容需要掌握内存分区的概念,可以参见:C程序的内存分区(节选自黑马训练营day1)

下面来看例程:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define sTring "I like C!" //定义一个宏字符串

1
void locationOfString() //不同声明形式下,字符串的地址 2 { 3 char arrString[]="I am a freshman!"; //数组形式声明字符串 4 char *p=arrString; //声明指针指向上面字符串 5 char*q="I am a freshman!"; 6 printf("字符串本身的地址是: %p 字符串的内容是: %s","I am a freshman!","I am a freshman! "); 7 printf("字符串数组的地址是: %p 字符串数组的内容是: %s ",arrString,arrString); 8 printf("指向字符串数组的指针的地址是:%p 指向字符串数组的指针的内容是:%s ",p,p); 9 printf("指向字符串的指针的指向地址是:%p 指向字符串的指针的内容是: %s ",q,q); 10 }

程序运行后,输出如下:

   字符串本身的地址是:                  00405064    字符串的内容是:                          I am a freshman!
   字符串数组的地址是:                  0060FEF7    字符串数组的内容是:                  I am a freshman!
   指向字符串数组的指针的地址是:0060FEF7    指向字符串数组的指针的内容是:I am a freshman!
   指向字符串的指针的指向地址是:00405064    指向字符串的指针的内容是:        I am a freshman!

   从上面程序运行的结果可以推断出:
   1、当编程者定义一个字符串的时候,编译器将字符串存放在程序数据区(静态存储区)。
   2、以数组形式声明的字符串,字符串本身在程序数据区(全局区)。程序运行后,编译器拷贝字符串,并将其放在栈区,形成副本。
        字符串数组的地址就是字符串栈区副本的地址,该地址的内存随着函数运行结束被释放。
   3、以指针形式声明的字符串,则在栈上没有副本,指针指向字符串本身在程序数据区的地址。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #define sTring "I like C!" //定义一个宏字符串
 5 
 6 void outputArrayString()
 7 {
 8     char arrString[]=sTring;
 9     printf("数组形式输出字符串数组的第4个字符是:  arrString[3]=%c 
",arrString[3]);
10     printf("指针形式输出字符串数组的第4个字符是:*(arrString+3)=%c 

",*(arrString+3));
11     printf("字符串数组的地址是  :    arrString=%p 
",arrString);
12     printf("字符串数组的首地址是:&arrString[0]=%p 
",&arrString[0]);
13     printf("字符串本身的首地址是:      &sTring=%p 
",&sTring);
14     printf("字符串本身的地址是  :       sTring=%p 

",sTring);
15 }
16 void outputPointString()
17 {
18     char *p=sTring;
19     printf("数组形式输出字符串数组的第5个字符是:  p[4]=%c 
",p[4]);
20     printf("指针形式输出字符串数组的第5个字符是:*(p+4)=%c 

",*(p+4));
21 }


   通过outputArrayString和outputPointString例程的运行,我们可以看出:
     1、只要将字符串与数组或者指针联系起来(以赋值的形式),我们就可以输出字符串中的字符。
     2、无论是用数组还是用指针与字符串联系起来,在定位字符串的位置,以输出字符串的某个字符时,
          用指针偏移或者数组偏移的形式都可以。这时,数组形式和指针形式的定位是通用的,并且可以互换。

 1 #define sTring "I like C!"
 2 void editArrayString()
 3 {
 4     char arrString[] = sTring;
 5     printf("数组字符串=%s  宏字符串=%s
", arrString, sTring);
 6     arrString[0] = 'W';
 7     printf("数组字符串=%s  宏字符串=%s
", arrString, sTring);
 8     *(arrString) = 'I';
 9     printf("数组字符串=%s  宏字符串=%s
", arrString, sTring);
10     //++arrString='h';  当程序运行到这条语句时,提示错误。
11     printf("数组字符串=%s  宏字符串=%s

", arrString, sTring);
12 }

 通过上面例程可以看出:
   1、声明一个数组,并将其与宏字符串关联后,字符串数组可以被修改。
   2、被修改的仅仅是字符串数组,也就是宏字符串在栈上的副本,宏字符串本身并没有改变。
   3、字符串的地址不能被修改,也就是说,字符串数组变量名不能做左值。

 1 void editArrayString2()
 2 {
 3     char arrString[] = "I believe tomorrow to be a better day!";
 4     printf("程序数据区字符串地址=%p	", &("I believe tomorrow to be a better day!"));
 5     printf("程序数据区字符串=%s
", *(&("I believe tomorrow to be a better day!")));
 6     printf("字符串数组地址      =%p 	 字符串数组     =%s
", arrString, arrString);
 7     arrString[0] = 'W';
 8     //*((char*)("I believe tomorrow to be a better day!")) = 'W';  程序运行至此,系统报错!
 9     printf("程序数据区字符串地址=%p	", &("I believe tomorrow to be a better day!"));
10     printf("程序数据区字符串=%s
", *(&("I believe tomorrow to be a better day!")));
11     printf("字符串数组地址      =%p 	 字符串数组     =%s 

", arrString, arrString);
12 }

通过上面例程可以看出:
   1、声明一个字符串数组后,编译器在内存的程序数据区写入一个字符串常量。
   2、声明字符串数组的函数被调用后,编译器在栈区写入一个字符串常量副本作为字符串数组。
   3、字符串数组可以被修改,但被修改的仅仅是字符串数组,也就是字符串在栈上的副本,
   存放在程序数据区的字符串常量并没有改变。
   4、字符串本身不可以被修改,被当作常量处理。

1 void editPonintString()
2 {
3     char *p="persevere in!";
4     printf("指针声明字符串=%s 
",p);
5     //*(p+1)='E';  //程序运行至此,系统报错!
6     printf("指针声明字符串=%s 
",p);
7     p=p+2;
8     printf("指针声明字符串的第3个字符=%c 
",*(p));
9 }

通过上面例程可以看出:
   1、以指针形式声明一个字符串变量后,该字符串不能被修改。
   2、指针的地址可以被修改,也就是说,指针变量名能做左值。

原文地址:https://www.cnblogs.com/GoldCrop/p/11031818.html