本专栏目的
- 更新C/C++的基础语法,包括C++的一些新特性
前言
- 无论什么语言,字符串都是最重要、最基础的数据类型,他对二进制有很好的对应关系
- 在C语言中没有提供专门的处理字符串的类型,但是我们可以通过字符数组、开辟内存地址来处理字符串
- 本文将从字符串与字符数组的关系、字符串与内存的关系、字符串处理函数来讲解字符串。
- 制作不易,欢迎收藏+点赞+关注,本人会持续更新
文章目录
- 字符串与字符数组
- 字符和字符串
- 字符串与字符数组
- 特点
- 创建字符串两种形式
- 字符串内存区域
- 字符数组输入/输出
- 输入
- scanf
- gets_s
- getchar
- 输出
- 字符串处理函数(常用)
- strlen
- strcpy/strncpy
- strcmp/strncmp/stricmp
- strcat/strncat
- strchr/strrchr
- strstr
- 其他(了解)
- 内存相关的处理函数(常用)
- memcmp
- memcpy
- memset
字符串与字符数组
字符和字符串
字符
- 普通字符:‘a’,‘1’
- 转义字符:‘\a’,‘\n’…
字符串
- “Boy”,”Wy”
字符与字符串的区别
1,形式上不同
2,本质上:字符串有结束符 ‘\0’
字符A和字符串A所占内存空间不一样,以下代码输出分别是多少呢?
printf("%d %d", sizeof('a'),sizeof("a"));
答案:
1 2
解释:
- char:内存是一字节,代表一个字符
- ”a“,代表一个字符串,它含有一个字符’\0’,代表字符串结束,故等于2
- 那请问:如果用strlen(“a”),又会输出多少呢??? 请看后面分析
字符串与字符数组
在各种编程语言中,字符串的地位都十分重要,C语言中并没有提供“字符串”这个特定类型,而是以特殊字符数组的形式来存储和处理字符串,这种字符数组必须以空字符’\0’结尾
特点
- 字符数组
可以没有'\0'
- 字符串
必须要有'\0'
- 字符数组可以
存储
字符串
注意:字符串一定是字符数组,字符数组不一定是字符串
下列字符数组存储的是不是字符串:
char str[10] = {'1','b','c'}; //并不是字符串,没有\0
char str[1] ={'\0'}; //是字符串 等价于””
“abcdedf”; //也是字符串,编译器会自动的在双引号最后加,上\0
char str[10] =“abcdef"; //字符串可以用字符数组表示{'a','b'...'\0'}
char str[10]={''a,”,”b”,”c”,'\0'} //不是字符串
char *p=”maye”; //一个字符指针指向字符串
总结:
-
编译器不会给字符数组自动添加’\0’
-
编译器会自动给双引号的字符串字面值加上’\0’
-
指针指向的字符串是常量,是没法修改的。
创建字符串两种形式
- 字符数组形式:char str[20];
- 字符指针形式:char* pc;
区别:
- str是一个字符数组,字符串中的每个字符逐个存放,且可以随意修改
- pc是一个字符指针,指向的是常量区的字符串,不能修改,只能访问
char str[20]; str=“I love China!”; //(X) str是常量不能改变指向
char *pc; pc=“I love China!”; //(√) pc是变量,可以改变指向
- 因此pc接受输入字符串时,要么指向一个字符串,要么开辟内存空间,
字符串内存区域
我们知道内存可以分为四区:
- 栈区
- 堆区
- 全局区(静态区)
- 代码区:存放二进制代码
其实在代码区和全局区之间还有一层文字常量区,用来存储字符串常量,生命周期随程序周期。
一下是某一位大佬写的,通过对比p1、p2、p3的内存区域
,可以很明确的区别不同区的不同。
//main.cpp
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main()
{
int b; //栈
char s[] = "abc";// 栈
char *p2;// 栈
char *p3 = "123456";// 123456\0在常量区,p3在栈上。
static int c =0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
//分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
字符数组输入/输出
输入
scanf
- 使用scanf输入字符串时,遇到空格会自动截断,遇到回车结束,自动添加’\0’
- 输入超出范围时,不会进行越界检查,甚至能完全输出
gets_s
- 能读取空格,遇到回车结束,自动添加’\0’
- 输入超出范围时,会进行越界检查,如下图
getchar
char str[10];
for(int i=0;i<10;i++)
{
str[i] = getchar();
}
puts(str); //如果结尾没有'\0',输出结果将不可预料,可以改为逐个字符输出
- 在结尾自动加上’\0‘,养成良好习惯,否则在很多情况会出现很多问题
for(int i=0;i<10;i++)
{
str[i] = getchar();
if(str[i] == '\n')
{
str[i] = '\0';
break;
}
}
输出
由于C语言中没有真正的字符串类型,可以通过字符数组表示字符串,因为它的元素地址是连续的,这就足够了。
1. 从首地址开始逐字节寻址,把存储单元(一个字节)内的数据转换为ASCII字符格式输出。
2. 直到某一个字节内存的元素为字符'\0'时,输出此字符并且寻址结束。
如果字符数组里没有’\0’,那么使用printf (%s) 输出时,就找不到正确的结束标志,就会多输出一些乱码。
字符串处理函数(常用)
C语言提供了丰富的字符串处理函数,大致可分为字符串的输入、输出、合并、修改、比较、转换、复制、搜索几类。 使用这些函数可大大减轻编程的负担。用于输入输出的字符串函数,在使用前应包含头文件"stdio.h",使用其它字符串函数则应包含头文件"string.h"。
strlen
求字符串长度**(不包括\0)**,包括可以用 sizeof
关键字
strlen("hello maye");
strcpy/strncpy
把一个src拷贝到dest中去,要保证dst缓冲区有足够的内存。
- strcpy 会在dest结尾添加\0
- strncpy 不会在dest结尾添加\0
char dest[10];
strcpy(dest, "maye");
puts(dest);
strcmp/strncmp/stricmp
比较str1和str2,str1 > str2 返回1,str1==str2 返回0,否则返回-1
int res = strcmp("maye", "maye");
printf("res:%d\n", res);
strcat/strncat
- 把src连接到dest的末尾(\0的位置)
char dest[20]="hello ";
strcat(dest, "maye");
puts(dest);
strchr/strrchr
- 在字符串string中查找字符val,存在返回val的开始位置,否则返回NULL
char words[] = "hello every one,My name's maye";
puts(strchr(words, 'o'));
strstr
char* strstr(char* _String, char * _SubString)
- 在字符串string中查找子串substr,存在返回substr的开始位置,否则返回NULL
char words[] = "hello every one,My name's maye";
puts(strstr(words, "one"));
其他(了解)
算法:刷题的时候很常用
-
strlwr 把字符串转成小写
-
strupr 把字符串转成大写
-
strset/strnset 把字符串s中的所有字符都设置成字符c
-
strrev 反转字符串
-
strdup 拷贝字符串,返回动态分配的内存,使用完毕后需要手动free
内存相关的处理函数(常用)
memcmp
- 内存比较,不仅可以比较字符串,还可以比较其他的内存
- 返回值为三种情况 >0, <0 , =0
int arr[5] = { 1,2,6,4,5};
int arr1[5] = { 1,2,5,4,5 };
int ok = memcmp(arr, arr1, sizeof(int) * 5);
int ok1 = strcmp(arr, arr1);
printf("%d %d\n", ok,ok1);
memcpy
- 内存拷贝
int temp[5];
memcpy(temp, arr,sizeof(int)*5);
//strcpy(temp, arr); //复制整型数组会有问题
for (int i = 0; i < 5; i++)
{
printf("%d ", temp[i]);
}
memset
- 按字节对内存进行初始化
char num[5];
memset(num, 127, sizeof(char) * 5);
for(int i = 0; i < 5; i++)
{
printf("%d ", num[i]);
}
nt temp[5];
memcpy(temp, arr,sizeof(int)*5);
//strcpy(temp, arr); //复制整型数组会有问题
for (int i = 0; i < 5; i++)
{
printf("%d ", temp[i]);
}
### memset
+ 按**字节**对内存进行初始化
```cpp
char num[5];
memset(num, 127, sizeof(char) * 5);
for(int i = 0; i < 5; i++)
{
printf("%d ", num[i]);
}