397 lines
12 KiB
Markdown
397 lines
12 KiB
Markdown
# 一、C语言函数库
|
||
|
||
- 概念:在C语言发展过程中收录了很多经典的数据操作方法----函数,将这些函数收录归纳汇总为开发人员方便使用的API接口(函数),如下图所示的各种操作接口库。
|
||
|
||

|
||
|
||
# 二、字符串操作函数
|
||
|
||
- 使用三部曲
|
||
|
||
- 确认头文件
|
||
|
||
- 确认函数功能
|
||
|
||
- 确认函数的参数与返回值
|
||
|
||
- C语言标准字符串函数库,头文件"#include <string.h>"
|
||
|
||

|
||
|
||
- **函数strlen**
|
||
|
||

|
||
|
||
```c
|
||
char *p = "www.yueqian.edu.com.cn";
|
||
printf("粤嵌官网的地址长度是:%d\n", strlen(p));
|
||
```
|
||
|
||
- **函数strcat与strncat**
|
||
|
||

|
||
|
||
- 注意:
|
||
|
||
- 这两个函数的功能一样,都是将src字符串复制到dest的末尾。
|
||
|
||
- strcat()没有边界控制,因此可能会由于src字符串过长导致dest无法保存从而导致内存溢出。
|
||
|
||
- strncat()有边界控制,可以限制拼接字符的格式,保证dest不会因为越界而导致内存溢出。
|
||
|
||
- 更加值得推荐的字符串拼接函数sprintf()与snprintf(),头文件"#include <stdio.h>"
|
||
|
||

|
||
|
||

|
||
|
||
- 要点:sprintf与snprintf不光可以拼接字符串还可以实现将其他数据类型也添加到字符串中,sprintf对目标字符串的长度没有现在条件又内存溢出风险,但snprintf没有。
|
||
|
||
```c
|
||
char str1[10] = "温度:";
|
||
int temp = 27;
|
||
char buf[50];
|
||
// sprintf(buf,"%s%d随机数据啊科技时代粉红色大家发货的撒扩大飞机和\r\n", str1, temp); // 无长度控制
|
||
// printf("buf:%s", buf);
|
||
snprintf(buf,sizeof buf,"%s%d随机数据啊科技时代粉红色大家发货的撒扩大飞机和\r\n", str1, temp); // 有长度控制
|
||
printf("buf:%s", buf);
|
||
```
|
||
|
||
- **函数strtok**
|
||
|
||

|
||
|
||
- 注意:
|
||
|
||
- 该函数会将改变原始字符串 str,使其所包含的所有分隔符变成结束标记 ‘\0’ 。
|
||
|
||
- 由于该函数需要更改字符串 str,因此 str 指向的内存必须是可写的。
|
||
|
||
- 首次调用时 str 指向原始字符串,此后每次调用 str 用 NULL 代替。
|
||
|
||
```c
|
||
char s[20] = "www.yueqian.com.cn";
|
||
|
||
char *p = strtok(s, "."); // 首次调用时,s 指向需要分割的字符串
|
||
while(p != NULL)
|
||
{
|
||
printf("%s\n", p);
|
||
p = strtok(NULL, "."); // 此后每次调用,均使用 NULL 代替。
|
||
}
|
||
```
|
||
|
||
***注:上述代码的运行结果就是将字符串 s 拆解为"www"、“yueqian”、“com” 和 “cn”***
|
||
|
||
- 其他子串提取:sscanf()按照格式提取字符串中的内容
|
||
|
||

|
||
|
||
```c
|
||
char str[] = "www yueqian-edu com cn";
|
||
char str1[4];
|
||
char str2[20];
|
||
sscanf(str,"%s %s",str1,str2);
|
||
printf("str1:%s\n", str1);
|
||
```
|
||
|
||
- **函数strstr**
|
||
|
||

|
||
|
||
```c
|
||
char *str = "正午十二点,柏油路面被晒得发软。便利店的冷柜吐出白雾,穿校服的女孩咬着冰棒跑过,"
|
||
"塑料包装纸在风里打着旋儿,最后贴在墙角那丛半枯的狗尾草上。"
|
||
"远处的施工队歇了工,起重机的吊臂在烈日里投下细长的影子,像根被晒蔫的芦苇。";
|
||
|
||
/* 在字符串中找子串 */
|
||
char *p = strstr(str, "柏油路"); // 从前往后查找子串,返回子串第一次出现位置
|
||
char *q = strstr(p+1, "你的女孩");// 若未找到则返回NULL
|
||
if(p != NULL)
|
||
puts(p);
|
||
|
||
if(q != NULL)
|
||
puts(q);
|
||
```
|
||
|
||
## **函数strcpy与strncpy**
|
||
|
||

|
||
|
||
```c
|
||
int main(int argc, char *argv[])
|
||
{
|
||
char *name = "张三丰";
|
||
char name1[20] = "123465dsdskfhjdsahs";
|
||
|
||
// 不能把一个进行字符串赋值
|
||
// name1 = name;
|
||
|
||
strcpy(name1, name); // 将name的内容全部内容包括'\0'都拷贝给name1的内存中
|
||
puts(name1);
|
||
puts(name1+10);
|
||
|
||
|
||
strncpy(name1, name, sizeof(name1));// 将name的内容sizeof(name1)字节部分内容包括'\0'都拷贝给name1的内存中,不足的不会拷贝
|
||
puts(name1);
|
||
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
- 注意:
|
||
|
||
1. 这两个函数的功能,都是将 src 中的字符串,复制到 dest 中。
|
||
|
||
1. strcpy() 没有边界控制,因此可能会由于 src 的过长而导致内存溢出。
|
||
|
||
1. strncpy() 有边界控制,最多复制 n+1 个字符(其中最后一个是 ‘\0’ )到 dest 中。
|
||
|
||
## **函数strcmp与strncmp**
|
||
|
||

|
||
|
||
```c
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
|
||
void fun(char *p)
|
||
{
|
||
char *q = "abc";
|
||
if(p==q)
|
||
{
|
||
printf("p与q相等\n");
|
||
}
|
||
else
|
||
{
|
||
printf("p与q不相等\n");
|
||
}
|
||
}
|
||
|
||
int main(int argc, char *argv[])
|
||
{
|
||
// char *str1 = "abc";
|
||
// char *str2 = "abc"; // 相同的常量在内存中只有一份
|
||
|
||
// fun(str1);
|
||
|
||
// if (str1 == str2) // 比较的是指针指向的目标是否相同
|
||
// {
|
||
// printf("str1与str2相等\n");
|
||
// }
|
||
// else
|
||
// {
|
||
// printf("str1与str2不相等\n");
|
||
// }
|
||
|
||
char s1[] = "abcacccaddc";
|
||
char s2[] = "abca";
|
||
|
||
// if (s1 == s2)// 比较的是s1和s2的内存地址是否相同
|
||
// {
|
||
// printf("s1与s2相等\n");
|
||
// }
|
||
|
||
int ret = strcmp(s1,s2); // 不是比较长短,而是比较两个字符串内容的大小(ASCII码值),一直比较到有结果为止
|
||
// 若s1中字符的ASCII码值>s2中字符的ASCII码值则返回值大于0
|
||
// 若s1中字符的ASCII码值与s2中字符的ASCII码值全部相等则返回值等于0
|
||
// 若s1中字符的ASCII码值<s2中字符的ASCII码值则返回值小于0
|
||
// printf("%d\n",ret);
|
||
if(ret == 0)
|
||
printf("s1与s2相等\n");
|
||
else if(ret > 0)
|
||
printf("s1大于s2\n");
|
||
else
|
||
printf("s1小于s2\n");
|
||
|
||
ret = strncmp(s1,s2, 4); // 选择性比较,可以设置比较的字符长度
|
||
// printf("%d\n",ret);
|
||
if(ret == 0)
|
||
printf("s1与s2相等\n");
|
||
else if(ret > 0)
|
||
printf("s1大于s2\n");
|
||
else
|
||
printf("s1小于s2\n");
|
||
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
- 注意:
|
||
|
||
- 比较字符串大小,实际上比较的是字符的 ASCII码值的大小。
|
||
|
||
- 从左到右逐个比较两个字符串的每一个字符,当能“决出胜负”时立刻停止比较(s1的字符ascii码值减去s2字符的ascii码值返回差值)。
|
||
|
||
## **函数strchr与strrchr**
|
||
|
||

|
||
|
||
```c
|
||
char *str = "正午十二点,柏油路面被晒得发软。便利店的冷柜吐出白雾,穿校服的女孩咬着冰棒跑过,"
|
||
"塑料包装纸在风里打着旋儿,最后贴在墙角那丛半枯的狗尾草上。"
|
||
"远处的施工队歇了工,起重机的吊臂在烈日里投下细长的影子,像根被晒蔫的芦苇。";
|
||
/* 在字符串中找字符 */
|
||
char *k = strchr(str, ','); // 从前往后查找字符,返回字符第一次出现位置(中文字符不行),没有找到返回NULL
|
||
if(k != NULL)
|
||
puts(k);
|
||
char *j = strrchr(str, '\0'); // 从后往前主要字符,返回字符第一次出现位置(中文字符不行),没有找到返回NULL
|
||
if(j != NULL)
|
||
puts(j);
|
||
printf("%#x\n", j[0]);
|
||
```
|
||
|
||
- 注意:
|
||
|
||
1. 这两个函数的功能,都是在指定的字符串 s 中,试图找到字符 c。
|
||
|
||
1. strchr() 从左往右找,strrchr() 从右往左找。
|
||
|
||
1. 字符串结束标记 ‘\0’ 被认为是字符串的一部分。
|
||
|
||
## 练习
|
||
|
||
自己封装函数实现strlen,strcat,strtok,strstr,strcpy,strcmp函数的功能。
|
||
|
||
# 晚上作业
|
||
|
||
1. 定义一个长度为20的整型数据生成随机数对这个数组进行初始化,编写排序函数对这个数据中的数据进行从小到大排序
|
||
|
||
- 要求编写五种排序函数:冒泡排序、选择排序、插入排序、快速排序、希尔排序
|
||
|
||
- 提示:
|
||
|
||
- **各种排序算法的****时间复杂度****与****空间复杂度**
|
||
|
||

|
||
|
||
- **冒泡排序**
|
||
|
||
- 顺序:两个数据位置符合排序要求
|
||
|
||
- 逆序:两个数据位置不符合排序要求
|
||
|
||
- 思路:从头到尾让两个相邻数据进行比较,顺序保持不变,逆序交换位置,经过一轮比较序列中具有一个“极值”将被挪至末端。
|
||
|
||

|
||
|
||
```c
|
||
|
||
```
|
||
|
||
- **插入排序**
|
||
|
||
- 思路:假设数列前面有i个节点的序列是有序的,那么就从第i+1个节点开始,插入到前面i个节点中的合适位置。由于序列的第一个节点始终视为有序,所以实在从第二个节点开始。
|
||
|
||

|
||
|
||
```c
|
||
|
||
```
|
||
|
||
- **选择排序**
|
||
|
||
- 在无序序列中依次从头到尾挑选合适的节点放入有序序列。
|
||
|
||

|
||
|
||
```c
|
||
|
||
```
|
||
|
||
- **快速排序**
|
||
|
||
- 快排是一直典型的递归思想,相比较其他排序它需要跟多的空间,理论上时间效率是最高的。
|
||
|
||
- 思想:在待排序序列中选取一个数据,作为“支点”,然后其他数据与支点比较,(升序)比支点小的放左边,比支点大的放右边,全部比较完后支点位于两个序列的中间,这叫一次划分(partition)
|
||
|
||

|
||
|
||
- 一次划分之后,序列的内部也许无序,但是左右序列与支点三者间,形成了一种基本有序状态,接下来使用相同的思路,递归的对左右序列进行排序,直到子序列的长度小于等于1为止;
|
||
|
||

|
||
|
||
```c
|
||
|
||
```
|
||
|
||
- **希尔排序**
|
||
|
||
- 插入排序的改进版本,普通插入排序是从第2个节点开始,依次插入到有序序列中,这种做法在虽然一次成型,但时间效率上不划算,优化思路:
|
||
|
||
- 不严格一个个插入使之有序,而是拉开插入节点的距离,让它们逐步有序,有待排序序列如下:
|
||
|
||
84、83、88、87、61、50、70、60、80、89
|
||
|
||
- 第一遍,先区间隔(Δ=5),即依次对以下5组数据进行排序
|
||
|
||
**84**
|
||
|
||
84、
|
||
|
||
84、83、
|
||
|
||
84、83、88、
|
||
|
||
84、83、88、87、
|
||
|
||
**注意:**
|
||
|
||
**50**
|
||
|
||
50、
|
||
|
||
50、70、
|
||
|
||
50、70、60、
|
||
|
||
50、70、60、80、
|
||
|
||
**结果:(**
|
||
|
||
**50**
|
||
|
||
50、
|
||
|
||
50、70、
|
||
|
||
50、70、60、
|
||
|
||
**得到:**
|
||
|
||
**50**
|
||
|
||
50、
|
||
|
||
50、61、
|
||
|
||
50、61、60、
|
||
|
||
**结果**
|
||
|
||

|
||
|
||
```c
|
||
|
||
```
|
||
|
||
1. 将自己写的字符串操作函数进行吸收
|
||
|
||
1. 制作一个图书管理系统,要求:
|
||
|
||
1. 输入1:增加书籍名称(可以连续添加多本)
|
||
|
||
1. 输入2:删除数书籍名称(删除一本或全部删除)
|
||
|
||
1. 输入3:修改书籍名称
|
||
|
||
1. 输入4:查找书籍名称(模糊查找或精确查找)
|
||
|
||
1. 输入5:显示所有书籍
|
||
|
||
1. 输入0:退出系统
|
||
|
||
只要系统未退出则可以继续重复进行,直至系统退出。
|
||
|
||
提示:char *book_name[1000]; // 表示表示最多可存放1000书,书名的长度自己设计。
|
||
|
||
[设置终端信息字体及颜色](https://share.note.youdao.com/s/DydeICJh) |