9-6 字符串的连接和复制

1. 如何拼接两个字符串?

        strcat() 函数,传入两个字符,将第二个字符拼接到第一个字符的后面。代码如下。

void TestStrcat(){

  char* string1 = "Hello";
  char* string2 = "World";

  strcat(string1, string2);

  printf("string1: %s\n", string1);  // string1: HelloWorld
  printf("string2: %s\n", string2);  // string2: ld
}

        需要注意的是,使用 msvc 编译器情况下,上述代码可以运行。但 string2 的字符串值会被改变,这是由于 string1 字符串地址与string2 字符串地址连续,拼接后的 string1 字符串占据了string2 字符串的内容。拼接之前:

 拼接后:

         若此时读取 string2,其结果为 "6c 64 00 6c 64 00 00 00",由于 00 是字符串结束标志,所以只能打印 "6c 64" 对应的内容,为 "ld"。

        代码的正确写法如下。此时,string1 存储在栈区,string2 指向的内容存储在常量区。

void TestStrcat(){

  char string1[20] = "Hello";
  char* string2 = "World";

  strcat(string1, string2);

  printf("string1: %s\n", string1);  // string1: HelloWorld
  printf("string2: %s\n", string2);  // string2: World
}

2. 字符串的复制

        strcpy() 函数,会将第二个字符复制到第一个字符的起始位置。代码如下所示。可以发现,最终 string1 和 string2 的输出结果相同,原因是 string2 在复制过程中,将末尾的 '\0' 也复制到了 string1 中,导致二者的打印的结果相同。

void TestStrcpy(){

  char string1[10] = "Hello C++";
  char *string2 = "World";

  strcpy(string1, string2);

  printf("string1: %s\n", string1);  // string1: World
  printf("string2: %s\n", string2);  // string2: World
}

        需要注意的是,复制是从 string1 的起始位置进行复制,但此位置可以进行更改。如下所示,将 string1 复制的起始位置向前移动 5,获得与拼接函数相同的结果。

void TestStrcpy2(){

  char string1[20] = "Hello";
  char* string2 = "World";

  strcpy(string1+strlen(string1), string2);

  printf("string1: %s\n", string1);  // string1: HelloWorld
  printf("string2: %s\n", string2);  // string2: World
}

3. C语言中的 char * 和 char [ ]

        msvc编译器下,char * 定义的字符串,同 char[ ] 一样,可以修改任意位置的值。并且可以按照数组的样式进行修改。gcc 编译器下,此段代码无法运行

        他人博客:char * 定义的指针在栈区,但其指向的地址是字符串常量的地址,字符串常量存储在常量区,是只读区域,一旦写入程序就会崩溃。尽管 msvc 编译器不会警告,但如果使用语法严谨的 Linux 下的 C 编译器 GCC,或者在windows下使用MinGW编译器就会得到警告。相比之下,char [ ] 定义的数组存储在栈区,即数组内部的值均在栈区,为可写区域

        char * 相当于 char const *,指向的区域不可改变(指向的字符串常量不能变)。char[ ] 相当于 char *const,指针变量不能改变(即数组名不能被改变),但其指向的值可以改变(即数组内部的值可以发生变化)。

void TestChar(){

  char *string1 = "hello";

  *(string1) = 'a';
  string1[1] = 'b';

  printf("%s", string1);  // abllo
}

4. 数组名 a 和 数组名取地址 &a 的关系

        简单来说,a 的本质是 &a[0],即数组 a 中第一个元素的地址。&a 并不是 a 变量的地址,而是数组 a 的起始地址。数组名 a 在内存中并没有分配空间,仅仅对数组 a 的各个元素分配了存储空间,故数组名 a 不是普通的变量,&a 不意味着 a 的存储地址。

        a 和 &a 的值相同,但是两者后续的含义不同。a+1 是在一个数组元素大小的基础上加 1,而 &a + 1 是在一个数组大小的基础上加 1。代码如下,可以发现,a 的值为 682621096,a+1是前进一个 int(4个字节),故结果为 682621100。而 &a + 1 是前进一个数组大小,即 20个字节,其结果为 682621116。

void Test2(){

  int a[] = {1,2,3,4,5};

  printf("a: %d\n", a);         // 682621096
  printf("a+1: %d\n", a+1);     // 682621100
  printf("&a+1: %d\n", &a+1);   // 682621116

}

char* 和 char[ ]:https://blog.csdn.net/u012611878/article/details/78291036

数组名 a 和 数组名取地址 &a:https://blog.csdn.net/loongkingwhat/article/details/78910921

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值