拿捏住C字符串,这个烦人程度不亚于指针的小东西

网友投稿 591 2022-05-29

文章目录

字符串处理能力能够反映出一个程序员的技术功底

基础扫盲篇

字符串字面量

难度指数:2 | 细节指数:3 | 重要指数:3

字符串初始化

难度指数:2 | 细节指数:3 | 重要指数:4

君不见 size_t 哪里来?

strlen 与 sizeof的不同

难度指数:2 | 细节指数:4 | 重要指数:3

memset函数

难度指数:2 | 细节指数:2 | 重要指数:3

基本操作函数篇

strcmp:比较字符串

strcpy:复制字符串

strcat:拼接字符串

字符串处理能力能够反映出一个程序员的技术功底

曾几何时,看到过这么一句话:字符串处理能力能够反映出一个程序员的技术功底。

这句话我一直在理解,每到一个阶段,都会有不同的理解。

时至今日,我的理解还是比较浅薄的,在算法题中,字符串的重要程度跟指针等绝对是不能同日而语的。

但是在开发中,IO过程就是核心了。

作为IO过程的组成部分,字符串处理就是这个核心中的核心了、

基础扫盲篇

字符串字面量

字符串字面量一般分配在只读内存中,所以是不可变的。

字符串字面量在哪里使用,是否全局、静态、局部,都无所谓的。

大部分编译器会将字符串字面量看做常量,无法修改字符串,不过有些编译器会不一样,碧如GCC。

#include #include int main() { //char* test = "asdfg"; //直接报错:const char* 类型的值不能为char*类型的实体赋值 /*char* test = (char*)malloc(10); test = "qwr";*/ //依旧不行 const char* test = "asdfg"; //将字符串初始化为常量可以解决一部分问题 //还有一个不错的方法,叫做粘贴上去,后面会讲 //也可以从键盘输入 }

1

2

3

4

5

6

7

8

9

10

11

12

字符串初始化

要说的话都在注释里了:

#include #include int main() { char test[10] = "asdfghjkl"; //记住,这里的位置要留一个给'

#include #include int main() { char test[10] = "asdfghjkl"; //记住,这里的位置要留一个给'\0' //能这样做,说明什么?说明test也是个const? test[3] = 'g'; //显然不是的 //那么上面那个赋值语句是什么意思呢? //可以理解为,将字符串字面量取出遍历,一个一个的放进字符数组中 char test[10]; test = "asdfghjkl"; //报错,表达式必须是可修改的左值 //不能把字符串字面量的地址赋给数组名字 }

' //能这样做,说明什么?说明test也是个const? test[3] = 'g'; //显然不是的 //那么上面那个赋值语句是什么意思呢? //可以理解为,将字符串字面量取出遍历,一个一个的放进字符数组中 char test[10]; test = "asdfghjkl"; //报错,表达式必须是可修改的左值 //不能把字符串字面量的地址赋给数组名字 }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

君不见 size_t 哪里来?

size_t 类型定义在cstddef头文件中,该文件是C标准库的头文件stddef.h的C++版。它是一个与机器相关的

unsigned

类型,其大小足以保证存储内存中对象的大小。

在C++中,设计size_t 就是为了适应多个平台的。size_t的引入增强了程序在不同平台上的可移植性。size_t是针对系统定制的一种数据类型,一般是整型,因为C/C++标准只定义最低的位数,而不是必需的固定位数。而且在内存里,对数的高位对齐存储还是低位对齐存储各系统都不一样。为了提高代码的可移植性,就有必要定义这样的数据类型。一般这种类型都会定义到它具体占几位内存等。当然,有些是编译器或系统已经给定义好的。经测试发现,在32位系统中size_t是4字节的,而在64位系统中,size_t是8字节的,这样利用该类型可以增强程序的可移植性。

strlen 与 sizeof的不同

strlen 是一个

函数

,所以需要进行一次函数调用,它用来计算指定字符串 str 的长度,但

不包括结束字符

(即 null 字符)

关键字 sizeof 是一个

单目运算符

,而不是一个函数。与函数 strlen 不同,它的参数可以是数组、指针、类型、对象、函数等

这里需要特别注意的是,函数 strlen 返回的是一个类型为 size_t 的值,从而有可能让程序导致意想不到的结果,如下面的示例代码所示:

/*判断一*/ if(strlen(x)>= strlen(y)) { } /*判断二*/ if(strlen(x)- strlen(y)>= 0) { }

1

2

3

4

5

6

7

8

拿捏住C字符串,这个烦人程度不亚于指针的小东西

从表面上看,上面的两个判断表达式完全相等,但实际情况并非如此。其中,判断表达式一没什么问题,程序也能够完全按照预想的那样工作;但判断表达式二的结果就不一样了,它将永远是真:

原因很简单,因为函数 strlen 的返回结果是 size_t 类型(即无符号整型),而 size_t 类型绝不可能是负的。

同样,就算表达式中同时包含了有符号整数和无符号整数,还是有可能产生意想不到的结果:

/*判断一*/ if(strlen(x)>= 5) { } /*判断二*/ if(strlen(x)- 5>=0) { }

1

2

3

4

5

6

7

8

9

原因同上、

sizeof 在编译时计算缓冲区的长度。也正是由于在编译时计算,因此 sizeof 不能用来返回动态分配的内存空间的大小。

memset函数

本来这个不应该在这里讲的,但是前面讲漏了,所以这里补一下:

memset 函数的第三个参数 n 的值一般用 sizeof() 获取,这样比较专业。注意,如果是对指针变量所指向的内存单元进行清零初始化,那么一定要先对这个指针变量进行初始化,即一定要先让它指向某个有效的地址。而且用memset给指针变量如p所指向的内存单元进行初始化时,n 千万别写成 sizeof§,这是新手经常会犯的错误。因为 p 是指针变量,不管 p 指向什么类型的变量,sizeof§ 的值都是 4。

基本操作函数篇

strcmp:比较字符串

int strcmp(const char* str1,const char* str2); //str1>str2,返回正数 //str1

1

2

3

4

5

6

strcpy:复制字符串

char* strcpy(char* str1,const char* str2); //其实就是两个指针引用同一个字符串

1

2

strcat:拼接字符串

char* strcat(char* s1,const char* s2); //第一个参数的地址必须足够长,不然越界了,就是会有未知的风险了 //注意,这些函数的参数类型、和返回值类型,别搞错了

1

2

3

4

后期写完C++会补上关于C++字符串的操作,所以各位如果觉得缺了点啥,可以发在评论区,我们一起看看

C++ 数据结构

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:[mongo] 1.1 mongodb基本介绍
下一篇:C/C++ Windows API——文件/文件夹创建、删除、移动及查看时间
相关文章