2021-06-13

                                                                                                                             字符串和字符串函数

字符串末尾以\0结束。用双引号括起来的属于静态存储类别。只会被存储一次,在整个程序生命周期内存在。被视为指向该位置的指针。特别注意的是\0是char形式的空字符。不是数字字符0。

字符串有两种创建方式,见程序

 11 int main(int argc, const char *argv[])
 12 {
 13 ¦   char *name = "Jack";
 14 
 15 ¦   char arr_name[] = "Jack";                                                                                                       
 16 
 17 
 18 ¦   return 0;
 19 }

这两种方式有什么不同呢?

指针形式是把字符串常量的地址赋给了指针,数组形式是对字符串常量创建了一份新的拷贝。下面用程序来验证一下。

 12 int main(int argc, const char *argv[])
 13 {
 14 ¦   char *name = "Jack";
 15 
 16 ¦   char arr_name[] = "Jack";
 17 
 18 ¦   printf("name = %p\n",name);
 19 ¦   printf("arr_name = %p\n",arr_name);
 20 ¦   printf("Jack = %p\n","Jack");
 21 ¦   
 22 ¦   return 0;
 23 }

name = 0x8048590
arr_name = 0xbfb29d57
Jack = 0x8048590

程序很好的验证了上面的推论。由此可以得出,指针形式是字符串常量的地址,数组形式是新的拷贝。

那这两者使用上有什么区别呢,很容易就能看出,指针形式无法修改字符串,因为是在常量区,而数组形式可以进行修改,因为是新的拷贝,数组创立的空间,并不在常量区。如果想修改一个字符串,那就用数组形式,如果不想那就用指针形式。

指针形式是否就真的不能修改呢?我还是有点疑问,再做个实验。

 12 int main(int argc, const char *argv[])
 13 {
 14 ¦   char *name = "Jack";
 15 
 16 ¦   char arr_name[] = "Jack";
 17 
 18 ¦   printf("name = %p\n",name);
 19 ¦   printf("arr_name = %p\n",arr_name);
 20 ¦   printf("Jack = %p\n","Jack");
 21 ¦   
 22 ¦   *name = 'P';
 23 ¦   
 24 ¦   return 0;                                                                                                                       
 25 }
name = 0x80485a0
arr_name = 0xbf8ffd97
Jack = 0x80485a0
Segmentation fault

可以明显的看到,段错误了,编译器不允许这么做,其实也不难想为什么编译器不允许这么做了,因为字符串常量只是个地址,可以多出引用,如果这里允许修改的话,别处引用的值也发生变化了,对程序会有不可预知的影响。

由上面同样可以推断出字符串数组的情况了。那再来看看又有啥不同。

 12 int main(int argc, const char *argv[])
 13 {
 14 ¦   char *name[2] = {"Jack", "Tom"};
 15 
 16 ¦   char arr_name[][5] = {"Jack", "Tom"};
 17 
 18 ¦   printf("name = %p\n",name);
 19 ¦   printf("arr_name = %p\n",arr_name);
 20 
 21 ¦                                                                                                                                   
 22 ¦   printf("sizeof name %d\n",sizeof(name));
 23 ¦   printf("sizeof arr_name %d\n",sizeof(arr_name));
 24 ¦   return 0;
 25 }
name = 0xbfed8238
arr_name = 0xbfed822e
Jack = 0x8048560
sizeof name 8
sizeof arr_name 10

可以看出,name指针和 arr_name 地址并不相同,和字符串一样,指针是指向常量区的,而数组是创建的拷贝。那再验证一下是否再常量区,是否可以修改。要特别注意的是这里的name是一个二级指针。

 12 int main(int argc, const char *argv[])
 13 {
 14 ¦   char *name[2] = {"Jack", "Tom"};
 15 
 16 ¦   char arr_name[][5] = {"Jack", "Tom"};
 17 
 18 ¦   printf("name = %p\n",name);
 19 ¦   printf("arr_name = %p\n",arr_name);
 20 
 21 ¦   
 22 ¦   printf("sizeof name %d\n",sizeof(name));
 23 ¦   printf("sizeof arr_name %d\n",sizeof(arr_name));
 24 ¦   
 25 ¦   *name = "Tom";                                                                                                                  
 26 ¦   
 27 ¦   printf("%s\n",*name);
 28 ¦   return 0;
 29 }
name = 0xbfea1618
arr_name = 0xbfea160e
sizeof name 8
sizeof arr_name 10
Tom

很奇怪吧,不是说不能修改吗?这里Jack  明明被替换了啊,哈其实这个不是修改,是指针改变了指向,指向了另外一个字符串常量 Tom.这里要具体修改的话就得用到二级指针了,下面来验证下是否可以修改。

 12 int main(int argc, const char *argv[])
 13 {
 14 ¦   char *name[2] = {"Jack", "Tom"};
 15 
 16 ¦   char arr_name[][5] = {"Jack", "Tom"};
 17 
 18 ¦   printf("name = %p\n",name);
 19 ¦   printf("arr_name = %p\n",arr_name);
 20 
 21 ¦   
 22 ¦   printf("sizeof name %d\n",sizeof(name));
 23 ¦   printf("sizeof arr_name %d\n",sizeof(arr_name));
 24 ¦   
 25 ¦   **name = 'T';
 26 ¦   
 27 ¦   printf("%c\n",**name);
 28 ¦   return 0;
 29 }

name = 0xbfde3368
arr_name = 0xbfde335e
sizeof name 8
sizeof arr_name 10
Segmentation fault

哈,段错误,验证了常量区,不可修改。

另外,指针指向的字符串常量是否是连续的地址呢?来验证下看看。

 12 int main(int argc, const char *argv[])
 13 {
 14 ¦   char *name[2] = {"Jack", "Tom"};
 15 
 16 ¦   char arr_name[][5] = {"Jack", "Tom"};
 17 
 18 ¦   printf("name = %p\n",name);
 19 ¦   printf("arr_name = %p\n",arr_name);
 20 
 21 ¦   
 22 ¦   printf("sizeof name %d\n",sizeof(name));
 23 ¦   printf("sizeof arr_name %d\n",sizeof(arr_name));
 24 ¦   
 25 ¦   printf("name[0] = %p, name[1] = %p\n",name[0],name[1]);
 26 ¦   
 27 ¦   ¦                                                                                                                               
 28 ¦   return 0;
 29 }
name = 0xbf920fa8
arr_name = 0xbf920f9e
sizeof name 8
sizeof arr_name 10
name[0] = 0x8048560, name[1] = 0x8048565

jack字符串加上\0正好是5个字节,貌似是连续的。其实细想一下不是必须是连续的,上面做过一个实验改变指针的指向的,就明白了,这里指向的地址不一定是连续的。另外还可以看出,字符串指针的存储效率更高,因为指向的是单个字符串,不浪费空间。而字符串数组的话每个字符串都只能以数组内最大的元素算,浪费了空间。

来总结一下吧,字符串数组和字符串指针的区别,字符串数组是单独字符串的拷贝,可以修改内容,字符串指针是字符串常量的地址,不可以修改内容。想修改内容的话用字符串数组,不用修改用指正,指针的存储效率高于数组。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值