逝者如斯,不舍昼夜

尘世中一个迷途小书童,读书太少,想得太多
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C语言中的数组和指针以及字符串

Posted on 2016-03-13 14:54  SteveWang  阅读(1825)  评论(0编辑  收藏  举报

 

  数组名同时也是该数组首元素的地址,而指针提供了一种用来使用地址的符号方法,因此指针能够很有效地处理数组。

  将一个整数加给指针,这个整数会和指针所指类型的字节数相乘,然后所得的结果会加到初始地址上

date + 2 == &date[2];        // 相同的地址
*(date + 2) == date[2];      // 相同的值

 

  在函数原型或函数定义头的场合中(并且也只有在这两种场合中),可以用int ar[]代替int* ar,处理数组的函数实际上是使用指针做为参数的

int sum(int* ar, int n); 
int sum(int ar[], int n);     // 二者在此处等价

 

  无论在任何情况下,形式int* ar都表示ar是指向int的指针。形式int ar[]也可以表示ar是指向int的指针,但只是在声明形式参量时才可以这样使用。使用第二种形式可以提醒读者ar不仅指向一个int数值,而且它指向的这个int是一个数组中的元素。

 

C语言中的字符串

  字符串是C里面最有用、最重要的数据类型之一。C语言中的字符串是以空字符('\0')结尾的char数组。

  下面两个都声明str是一个指向给定字符串常量的指针:

char str[] = "Klingon";
const char* str = "Klingon";

 

  在两种情况下,都是被引用的字符串本身决定了为字符串预留的存储空间大小。尽管如此,这两种形式并不完全相同。

  数组形式(str[])在计算机内存中被分配一个有8个元素的数组(其中每个元素对应一个字符,还有一个附加的元素对应结束的空字符'\0'),每个元素都被初始化为相应的字符。通常,被引用的字符串存储在可执行文件的数据段部分;当程序被加载到内存中时,字符串也被加载到内存中,位于静态存储区;在程序开始运行后才为数组分配存储空间,这时候把被引用的字符串复制到数组中。

  指针形式(* str)也在静态存储区为字符串预留8个元素的空间。一旦程序开始运行,还要为指针变量str另外预留一个存储位置,以在该指针变量中存储字符串的地址,指针变量str初始时指向字符串的第一个字符。

   总之,数组初始化是从静态存储区把一个字符串复制给数组,而指针初始化只是复制字符串的地址。

char* str = "Klingon";
str[0] = 'F';    // 是否允许?

  

  您的编译器可能会允许上面的情况,但按照当前的C标准,编译器不应该允许这样做。这种语句可能会导致内存访问错误。原因在于编译器可能选择内存中的同一个单个的拷贝,来表示所有相同的字符串常量。代码如下:

char* str = "Klingon";
str[0] = 'F';    // ok?
printf("Klingon");
printf(":Beware the %ss!\n","Klingon");

  

  如果编译器使用这种单个拷贝表示法并且允许把str[0]改为'F'的话,那将会影响到所有对这个字符串的使用。于是打印字符串"Klingon"的语句实际将会显示"Flingon",上述代码运行结果如下:

Flingon:Beware the Flingons!

  

  实际上,有些个编译器确实是按这种容易混淆的方式工作,而其他的一些则会产生程序异常中断(如Microsoft Visual Studio)

  因此,建议的做法是初始化一个指向字符串常量的指针时使用const修饰符:

const char* str = "Klingon";    // 推荐用法

 

  而用一个字符串常量来初始化一个非const的数组,则不会导致此类问题,因为数组从最初的字符串得到了一个拷贝

char str[] = "Klingon";
str[0] = 'F';    // 合法