由浅到深认识C语言(10):字符串处理函数
该文章Github地址:https://github.com/AntonyCheng/c-notes
在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.csdn.net/AntonyCheng/article/details/136555245),该模板集成了最常见的开发组件,同时基于修改配置文件实现组件的装载,除了这些,模板中还有非常丰富的整合示例,同时单体架构也非常适合SpringBoot框架入门,如果觉得有意义或者有帮助,欢迎Star & Issues & PR!
上一章:由浅到深认识C语言(9):动态内存分配
10.字符串处理函数
对字符串的处理一般在嵌入式编程,应用编程和网络编程中会大量用到;
字符串主要有拷贝,连接,比较,切割,变换等操作;
要求熟练使用常见字符串处理函数,并且会编写典型的字符串操作函数;
字符串操作函数有如下:
strlen
长度的测量;strcpy/strncpy
字符串拷贝;strcat/strncat
字符串连接;strcmp/strncmp
字符串比较;
字符串头文件: #include<string.h>
关于 Visual Studio 的安全模式需要补充的解释,在 Visual Studio 中默认的一些输入输出操作均为安全模式下的操作,即 函数名_s 的结构,该结构对于字符串来说影响极大,因为字符串的长度是不好把控的,很容易造成内存的溢出,所以为了解决此问题,在相关函数操作字符串时,会跟一个限制大小的 int 参数,即接下来操作的字符数组(字符串)的长度不能超过该长度;
10.1.测字符串长度函数
原型: int strlen(const char *str)
参数说明: str
是被测量的字符串首元素地址,const
是一个关键字,在 10.9 中会有介绍;
返回值: 返回字符串的长度,不包含 \0
和 null 字符;
这个函数虽然传的是 * 类型,但是不会修改其指向的内容;
示例如下:
#include<stdio.h>
#include<string.h>void test() {char buf1[128] = "hello world";char buf2[] = "hello world";char buf3[] = "hello\0world";char buf4[] = "hello\123\\world";printf("sizeof(buf1) = %d\n", sizeof(buf1));printf("strlen(buf1) = %d\n", strlen(buf1));printf("sizeof(buf2) = %d\n", sizeof(buf2));printf("strlen(buf2) = %d\n", strlen(buf2));printf("sizeof(buf3) = %d\n", sizeof(buf3));printf("strlen(buf3) = %d\n", strlen(buf3));printf("sizeof(buf4) = %d\n", sizeof(buf4));//hello--5个 \123--1个 \\--1个 world--5个 \0--1个printf("strlen(buf4) = %d\n", strlen(buf4));//hello--5个 \123--1个 \\--1个 world--5个 return;
}int main(int argc, char* argv[]) {test();return;
}
打印效果如下:
sizeof 和 strlen 的主要区别
sizeof
计算的是字符串中所有的元素,且加上最后一位隐藏掉的 \0
;
strlen
计算的是字符串中可见范围的元素,遇到 \0
就结束,不管其是否是最后的隐藏位;
实例:重写函数
自己定义一个 strlen 函数测量字符串长度;
#include<stdio.h>
#include<string.h>int my_strlen(char* p) {int count = 0;int turn = 1;while (turn) {if (*(p + count) != '\0') {count++;}else {turn = 0;}}return count;
}int main(int argc, char* argv[]) {char ch[] = "hello\123\\ world";int length1 = strlen(ch);int length2 = my_strlen(ch);printf("strlen = %d\n", length1);printf("my_strlen = %d", length2);return 0;
}
打印效果如下:
10.2.字符串拷贝函数
原型一: char* strcpy(char* dest,const char* src)
- 功能:把 src 所指向的字符串赋值到 dest 所指向的空间中;
- 返回值:返回 dest 字符串的首地址;
- 注意:遇到
\0
会结束,只是\0
也会被拷贝过去,需要保证 dest 足够大;
示例如下:
由于 VS 中该函数存在安全问题,所以需要按照编译器给定的安全模式输出,参数会不一样;
#include<stdio.h>
#include<string.h>void test() {char src[] = "hello world";char dest[128] = "";strcpy_s(dest,128 ,src); //安全模式下,还需要在中间插入需要传的字节大小,我们直接使用dest的字节大小printf("dest = %s", dest);
}int main(int argc, char* argv[]) {test();return;
}
打印效果如下:
有 \0
的情况:
#include<stdio.h>
#include<string.h>void test() {char src[] = "hello\0world";char dest[128] = "";strcpy_s(dest,128 ,src);printf("dest = %s", dest);
}int main(int argc, char* argv[]) {test();return;
}
打印效果如下:
原型二: char* strncpy(char* dest,const char* src,int num)
- 功能:把 src 所指向的字符串赋值到 dest 所指向的空间中;
- 参数说明:num 表示从第一位字符开始所拷贝字符的个数,若数字过大,则遇 \0 结束;
- 返回值:返回 dest 字符串的首地址;
- 注意:遇到
\0
会结束,但是\0
不会被拷贝过去,需要保证 dest 足够大;
实例:重写函数
自己定义一个 strcpy 函数来拷贝字符串;
#include<stdio.h>
#include<string.h>void my_strcpy(char* p1,char* p2) {int i = 0;int turn = 1;while (turn) {if (*(p2 + i) != '\0') {*(p1 + i) = *(p2 + i);i++;}else {*(p1 + i) = '\0';turn = 0;}}
}int main(int argc, char* argv[]) {char ch_1[] = "hello wo\0rld";char ch_2[128] = "";char ch_3[128] = "";my_strcpy(ch_2, ch_1);printf("sizeof(ch_2) = %d\n", sizeof(ch_2));printf("%s\n", ch_2);strcpy_s(ch_3,128,ch_1);printf("sizeof(ch_3) = %d\n", sizeof(ch_3));printf("%s\n", ch_3);return 0;
}
打印效果如下:
10.3.字符串拼接函数
原型一:char* strcat(char* dest,const char* src);
-
**功能:**将 src 的字符串拼接到 dest 的末尾(这里指的是 dest 中第一个 \0),且需要 dest 有足够的空间;
-
示例如下:
由于 VS 中该函数存在安全问题,所以需要按照编译器给定的安全模式输出,参数会不一样;
#include<stdio.h> #include<string.h>void test() {char ch1[] = "world";char ch2[128] = "hello ";strcat_s(ch2 ,128 ,ch1);printf("%s", ch2); }int main(int argc, char* argv[]) {test();return 0; }
打印效果如下:
原型二:char* strncat(char* dest,const char* src,int num);
-
**功能:**将 src 的字符串中的前 n 个字符拼接到 dest 的末尾(这里指的是 dest 中第一个 \0),且需要 dest 有足够的空间;
-
示例如下:
#include<stdio.h> #include<string.h>void test() {char ch1[] = "world";char ch2[128] = "hello ";strncat_s(ch2, 123, ch1, 3);printf("%s", ch2); }int main(int argc, char* argv[]) {test();return 0; }
打印效果如下:
实例:重写函数
自己定义一个 strcat 函数来连接字符串;
#include<stdio.h>
#include<string.h>void my_strcat(char* p2, char* p1) {int count = 0;while (*(p2 + count) != '\0') {count++;}int i = 0;int b = 1;while (b) {if (*(p1 + i) != '\0') {*((p2 + count) + i) = *(p1 + i);i++;}else {b = 0;}}
}int main(int argc, char* argv[]) {char ch1[] = "hello\0 world";char ch2[128] = "hello C ";char ch3[128] = "hello C ";my_strcat(ch2, ch1);strcat_s(ch3, 128, ch1);printf("ch2 = %s\n", ch2);printf("ch3 = %s", ch3);return 0;
}
打印效果如下:
10.4.字符串比较函数
原型一:int strcmp(const char* s1,const char* s2);
-
**功能:**将 s1 和 s2 指向的字符串逐个字符进行比较,用于整个字符串的比较;
-
返回值:
-
>0(一般是 1 ) 表示 s1 > s2 即两字符串不相同
-
<0(一般是 -1 ) 表示 s1 < s2 即两字符串不相同
-
=0 表示 s1 = s2 即两字符串相同
-
-
示例如下:
#include<stdio.h> #include<string.h>void test() {char s1[] = "hello world";char s2[] = "hello zorld";char s3[] = "hello aorld";char s4[] = "hello world";printf("'w' or 'z' = %d\n",strcmp(s1, s2));printf("'w' or 'a' = %d\n",strcmp(s1, s3));printf("'w' or 'w' = %d\n",strcmp(s1, s4));return; }int main(int argc, char* argv[]) {test();return 0; }
打印效果如下:
原型二:int strncmp(const char* s1,const char* s2,int num);
-
**功能:**将 s1 和 s2 指向的字符串前 n 个字符逐个进行比较,用于部分字符串的比较;
-
返回值:
-
>0(一般是 1 ) 表示 s1 > s2 即两部分字符串不相同
-
<0(一般是 -1 ) 表示 s1 < s2 即两部分字符串不相同
-
=0 表示 s1 = s2 即两部分字符串相同
-
实例:重写函数
自己定义一个 strcmp 函数来比较字符串;
#include<stdio.h>
#include<string.h>int my_strcmp(char* str1, char* str2) {int count1 = 0;int count2 = 0;int length1 = 0;int length2 = 0;int i1 = 0;int i2 = 0;while (*(str1 + i1) != '\0') {i1++;length1++;}while (*(str2 + i2) != '\0') {i2++;length2++;}i1 = 0;i2 = 0;if (length1==length2) {while (*(str1 + i1) != '\0') {if (*(str1 + i1) > *(str2 + i2)) {return 1;}if (*(str1 + i1) < *(str2 + i2)) {return -1;}i1++;i2++;}return 0;}else if (length1 > length2) {while (*(str2 + i2) != '\0') {if (*(str1 + i1) > *(str2 + i2)) {return 1;}if (*(str1 + i1) < *(str2 + i2)) {return -1;}i1++;i2++;}return 1;}else {while (*(str1 + i1) != '\0') {if (*(str1 + i1) > *(str2 + i2)) {return 1;}if (*(str1 + i1) < *(str2 + i2)) {return -1;}i1++;i2++;}return -1;}
}void test() {char str1[] = "abc";char str2[] = "abc";char str3[] = "aac";char str4[] = "acc";char str5[] = "abca";char str6[] = "aaca";printf("abc abc = %d\n", strcmp(str1, str2));printf("abc abc = %d\n", my_strcmp(str1, str2));printf("abc aac = %d\n", strcmp(str1, str3));printf("abc aac = %d\n", my_strcmp(str1, str3));printf("abc acc = %d\n", strcmp(str1, str4));printf("abc acc = %d\n", my_strcmp(str1, str4));printf("abc abca = %d\n", strcmp(str1, str5));printf("abc abca = %d\n", my_strcmp(str1, str5));printf("abc aaca = %d\n", strcmp(str1, str6));printf("abc aaca = %d\n", my_strcmp(str1, str6));
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
10.5.字符串变换函数
strchr字符查找
原型:char* strchr(const char* str1,char ch);
**功能:**在字符串 str1 中查找字符 ch 出现的的地址;
**返回值:**返回 ch 第一次出现的位置地址,找不到则返回空值;
示例如下:
我们运用 strchr
函数将 “hello world” 里的 ‘l’ 全部替换为 ‘a’;
#include<stdio.h>
#include<string.h>void test() {char str[] = "hello world";char* ret = NULL;while (1) {ret = strchr(str, 'l');if (ret == NULL) {break;}*ret = 'a';}printf("%s", str);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
strstr字符串查找
原型:char* strstr(const char* src,const char* dest);
**功能:**在字符串 src 中查找 dest 字符串出现的地址;
**返回值:**返回 dest 第一次出现的位置地址,找不到则返回空值;
示例如下:
利用 strstr 函数将 “www.dog.cat.dog.com” 中的 “dog” 用 * 屏蔽掉;
#include<stdio.h>
#include<string.h>void test() {char str1[] = "www.dog.cat.dog.com";char* ret = NULL;while (1) {ret = strstr(str1, "dog");if (ret == NULL) {break;}memset(ret, '#', strlen("dog"));}printf("%s", str1);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
10.6.字符串处理函数
memset字符填充
原型:void* memset(void* str,char c,int n);
**功能:**将 str 所指向的内存区的前 n 个全部用 c 填充,用于清楚指定空间,常用于 malloc 申请空间后的初始化操作;
**返回值:**返回 str 的地址;
atoi/atol/atof字符转换
头文件:#include<stdlib.h>
原型:
int atoi(const char* str);
long atol(const char* str);
double atof(const char* str);
功能:
将 str 所指向的 数字字符串转化为 int/long/double;
示例如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>void test() {char str1[] = "123.456";char str2[] = "123";printf("%f\n", (double)atoi(str2)+atof(str1));
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
实例:重写函数
自己定义一个 strcmp 函数来比较字符串;
#include<stdio.h>int my_atoi(char* str) {int sum = 0;while (*str != '\0'&& *str >= '0' && *str <= '9') {sum = sum * 10 + *str - '0';//这里要理解 ascii 中字符数与字符0的差值就是真实的数值str++;}return sum;
}int main(int argc, char* argv[]) {char str[] = "123";printf("%d\n", my_atoi(str) + 1);return 0;
}
打印效果如下:
strtok字符串切割
原型:char* strtok(char* str,const char* string);
**功能:**strtok 函数可以将一个字符串 s 以 string字符串==(字符串就代表要用双引号包裹)==为分界线进行切割;
注意:当函数在参数 s 字符串中发现参数 string 中包含的分割字符时,则会将该字符改为 \0 字符,当连续出现多个时只会替换第一个为 \0,即调用一次只能切割一次,在第二次调用时,string 字符串不变,s 字符串一定要设置成 NULL,因为第一次返回的地址就是下一次要切割的地址,传空值就能够接着该地址往下切割,每次调用成功则返回指向被分割出片段的指针,一般将切割后的独立字符串首地址存放在指针数组中;
这也是唯一一个要对原字符串进行改变的函数;
示例如下:
在 Visual Studio 中,该函数是一个安全性问题函数
char *strtok_s( char *strToken, const char *strDelimit, char **buf);
最后一个参数表示将剩余的字符串存储在 buf 指针数组中,而不是静态变量中,从而保证了安全性。
#include<stdio.h>
#include<string.h>int test() {char str[] = { "xixixi,hehehe,lalala" };char* protect[] = { NULL };char* arr[32] = { NULL };//第一次切割int i = 0;arr[i] = strtok_s(str, ",", protect);//第二次……切割while (arr[i] != NULL) {i++;arr[i] = strtok_s(NULL, ",", protect);}//输出结果i = 0;while (arr[i] != NULL) {printf("第%d次输出为:\n", i + 1);printf("%s\n", arr[i]);i++;}printf("原函数为:%s", str);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
10.7.sprintf组包
图解 printf:
**意义:**将零散的数据组成一个完整的整体;
格式:
int sprintf(str,"格式",数据);
//str:用于存放组好的报文
//"格式":按照格式组包
//数据:各个零散的数据
//返回值:返回的是组好的报文的实际长度(不包含 \0)
示例一如下:
在 Visual Studio 中,该函数是一个安全性问题的函数,需要在第二个参数中加入适当的长度限制,保证内存不溢出,通常可以直接使用存放该报文的数组长度;
#include<stdio.h>void test() {int year = 2022;int mon = 3;int day = 24;//要求:将以上变量组成一个"2022年3月24日"字符串char str[128] = "";sprintf_s(str, 128, "%d年%d月%d日", year, mon, day);printf("%s\n", str);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
示例二如下:
#include<stdio.h>void test() {char name[] = "陈一";int age = 20;char sex[] = "男";char addr[] = "四川省";char str[128] = "";sprintf_s(str, 128, "姓名:%s;年龄:%d;性别:%s;地址:%s", name, age, sex, addr);printf("%s\n", str);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
示例三如下:
将 int 型整数转换成字符串;
#include<stdio.h>void test() {int a = 100;int b = 200;char str[128] = "";sprintf_s(str, 128, "%d + %d = %d", a, b, a + b);printf("%s\n", str);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
10.8.sscanf解包
图解 scanf:
**意义:**将一个完整的整体拆解成零散的数据;
格式:
int sscanf(str,"格式",地址数据);
//str:存放报文的字符串地址
//"格式":按照格式组包
//数据:各个零散的需要获取数据的地址
注意:sscanf若遇到不满足条件的字符(条件的反面)时,会直接结束获取进程,即使该字符后有满足的字符;
示例如下:
#include<stdio.h>void test() {char str[] = "2022年3月24日";int year = 0;int mon = 0;int day = 0;sscanf_s(str, "%d年%d月%d日", &year, &mon, &day);printf("%d , %d , %d\n", year, mon, day);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
要注意提取的格式,%c、%d、%f、%lf 的提取类似,但是 %s 提取字符串就会有问题,因为提取的原理是对于字符数组进行逐个遍历,寻找适合要求的部分并进行取值,例如 %d 的范围是 1-9,%c 的范围是单个字符,%f 的范围是 float型,%lf 的范围是 double型,而如果我们要遍历一个字符串的话,它的范围就是所有字符(但会遇到空格结束),但是遍历内容全是字符,所以总是会拿到所有的内容,而不是我们想要的内容;
高级用法
用法一:使用 %*s 、%*d 跳过提取内容,即不要提取到的内容;
%*s 和 %s 的相同点在于都能提到数据,不同点在于前者不能被取到,而后者可以被取到,即能够拿出来赋值;
示例如下:提取 "1234 5678"
中的 "5678"
;
#include<stdio.h>void test() {int data1 = 0;sscanf_s("1234 5678", "%*d %d", &data1);//也可以这样//sscanf_s("1234 5678", "1234 %d", &data1);printf("data1 = %d\n", data1);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
所以我们可以用以上的方法和 %s 的特性来做一些复杂的操作:
提取 "abcdef 1234 sndhcbakdh 8763 ds 6.999"
中的数学数据;
#include<stdio.h>void test() {int data1 = 0;int data2 = 0;float data3 = 0;sscanf_s("abcdef 1234 sndhcbakdh 8763 ds 6.999", "%*s %d %*s %d %*s %f", &data1, &data2, &data3);printf("data1 = %d\n", data1);printf("data2 = %d\n", data2);printf("data3 = %f\n", data3);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
用法二:使用 %ns 、%nd 来提取指定宽度 n 的字符串或数据;
示例如下:
#include<stdio.h>void test() {int data = 0;sscanf_s("12abc5678", "%*5s%d", &data);printf("data = %d\n", data);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
**用法三:**支持集合的操作(正则表达式);
-
%[a-z]:提取 a-z 的字符串;
示例如下:
#include<stdio.h>void test() {char str[16] = "";sscanf_s("abcDeFgH","%[a-z]",str,16);printf("str = %s\n", str); }int main(int argc, char* argv[]) {test();return 0; }
打印效果如下:
-
%[aBc]:提取 aBc 中的任意一个;
示例如下:
#include<stdio.h>void test() {char str[16] = "";sscanf_s("aBcBcacBefacc","%[aBc]",str,16);printf("str = %s\n", str); }int main(int argc, char* argv[]) {test();return 0; }
打印效果如下:
-
%[^abc]:提取非 abc 中任何一个的字符;
示例如下:
#include<stdio.h>void test() {char str[16] = "";sscanf_s("ABCabcDeFgH", "%[^abc]", str, 16);printf("str = %s\n", str); }int main(int argc, char* argv[]) {test();return 0; }
打印效果如下:
高级用法案例
案例一:
需求: 现在有 data=0 和 str[16]="" ,需要从 “12345678” 中提取到 34 赋值给整型 data,再提取到 78 赋值给字符串 str ,一并输出;
#include<stdio.h>void test() {int data = 0;char str[16] = "";sscanf_s("12345678", "%*2d%2d%*2d%s", &data, str, 3);printf("data = %d\n", data);printf("str = %s\n", str);}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
案例二:
需求:给定一个形如 xxx@xxx.com
的网址,其中 xxx 不定长,提取两部分 xxx 分别放入两个字符数组中;
#include<stdio.h>void test() {char str1[16] = "";char str2[16] = "";sscanf_s("1999998888@qq.com", "%[^@]%*[@]%[^.]", str1, 16, str2, 16);printf("str1 = %s\n", str1);printf("str2 = %s\n", str2);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
案例三:
需求:在歌词格式中里提取歌词时间(不要毫秒)和内容(格式:[分:秒:毫秒][分:秒:毫秒]歌词内容
);
#include<stdio.h>void test() {int minute1 = 0;int second1 = 0;int minute2 = 0;int second2 = 0;char song[128] = "";char file[] = "[1:13:46][2:11:53]这是歌词的内容!";sscanf_s(file, "[%d:%d:%*d][%d:%d:%*d]%s", &minute1, &second1, &minute2, &second2, song, 128);printf("[%d:%d—%d:%d]:%s", minute1, second1, minute2, second2, song);}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
10.9.const关键字
const修饰普通变量
const修饰普通变量,表示该普通变量只读,即该变量只能取值,不能被赋值,类似于 Java 中的 final,但是有区别,Java中是绝对不能改变的一个值,但是在C语言中,在编译器固定只读变量地址的前提下,如果知道其地址,这个值也是可以改的,被 const 赋值后的变量指针类型为 const int* 类型,我们只需要将其强制转换成 int* 即可;
const修饰的变量一定要初始化,虽然可以通过地址类型的强制转换去更改内容,但是尽量不要去做;
只读示例如下:
改变权限示例如下:
#include<stdio.h>void test() {const num = 10;//将指针类型从const int*强制转换为int*,然后再取内容进行赋值*(int*)&num = 11;printf("num = %d\n", num);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
所以从底层来讲,该变量不能被修改的原因是此变量指针的指针类型不可重新指向另外的地址,只需要强制转换成可重定向的指针类型,就能临时性地永久改变该地址的内容(临时性指的是下一次需要改变时仍要重新强制转换,永久指的是从地址层改变该地址的内容);
const修饰指针星花
格式:const int* p
const修饰指针星花重在修饰 * 而不是 p ,所以修饰之后的效果是用户不能借助 *p 更改空间的内容,但是 p 可以指向其他空间,即 *p 只读,p 可读可写;
*p 只读示例如下:
p 可读可写示例如下:
#include<stdio.h>void test() {int num = 10;const int* p = #int num2 = 20;p = &num2;printf("num = %d\n", *p);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
const修饰指针变量
格式:int* const p
const修饰指针变量重在修饰 p ,而不是 * ,所以修饰后的效果是用户可以通过 *p 修改 p 的所指向空间的内容,但是不能再更改 p 的指向,即 *p 可读可写,p 只读;
p 只读示例如下:
*p 可读可写示例如下:
#include<stdio.h>void test() {int num1 = 10;int* const p = &num1;*p = 20;printf("num = %d\n", *p);
}int main(int argc, char* argv[]) {test();return 0;
}
打印效果如下:
const同时修饰指针星花和变量
格式:const int* const p
从上两点可以看出,此时 *p 和 p 都是只读的;
*p 只读示例如下:
p 只读示例如下:
相关文章:

由浅到深认识C语言(10):字符串处理函数
该文章Github地址:https://github.com/AntonyCheng/c-notes 在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.csdn…...

防范服务器被攻击:查询IP地址的重要性与方法
在当今数字化时代,服务器扮演着重要的角色,为企业、组织和个人提供各种网络服务。然而,服务器也成为了网络攻击者的目标之一,可能面临各种安全威胁,例如DDoS攻击、恶意软件攻击、数据泄露等。为了有效地防范服务器被攻…...

3. ElasticSearch搜索技术深入与聚合查询实战
1. ES分词器详解 1.1 基本概念 分词器官方称之为文本分析器,顾名思义,是对文本进行分析处理的一种手段,基本处理逻辑为按照预先制定的分词规则,把原始文档分割成若干更小粒度的词项,粒度大小取决于分词器规则。 1.2 …...

【Linux】Shell编程【一】
shell是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。 Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。 Shell属于内置的…...

Windows10+tensorrt+python部署yolov5
一、安装cuda 打开NVIDIA控制面板 —>帮助—>系统信息—>组件,找到驱动版本新,我这边是11.2, 然后去CUDA Toolkit Archive | NVIDIA Developer下载对应版本的CUDA,根据查看的CUDA型号确定对应的cuda Toolhit版本&#…...

【前端框架的发展史详细介绍】
前端框架的发展史 前端框架的发展史可以追溯到1995年,当时微软推出了IE浏览器并开始支持CSS,随后,在1997年,W3C(万维网联盟)发布了CSS的第一个正式标准。 在2003年,苹果推出了Safari浏览器&am…...

[JAVAEE]—进程和多线程的认识
文章目录 什么是线程什么是进程进程的组成什么是pcb 进程概括线程线程与进程的关系线程的特点 创建线程创建线程方法创建线程的第二种方法对比 其他的方式匿名内部类创建线程匿名内部类创建Runable的子类lambda表达式创建一个线程 多线程的优势 什么是线程 什么是进程 首先想…...

sqllab第十九关通关笔记
知识点: 错误注入 最大长度为32位;如果目标长度>32时,需要利用截取函数进行分段读取referer注入 insert语句update语句 通过admin admin进行登录发现页面打印除了referer字段的信息 这应该是一个referer注入 首先进行测试一下 构造payl…...

张量维度改变总结
文章目录 一、view() 或 reshape()二、unsqueeze()三、squeeze()四、transpose()五、torch.expand_dims 一、view() 或 reshape() view() 或 reshape(): 这两个函数可以用于改变张量的形状,但保持元素总数不变。它们可以接受一个新的形状作为参数,并返回…...

C++ ezOptionParse的用法
在网上找了一下,发现并没有很多关于这个小型头文件的资料 只好自己上了 int main(int argc, const char * argv[]) {ezOptionParser opt;opt.overview "Demo of parsers features."; //概要说明,一般需要填写,简要介绍程序的作用opt.synta…...

MATLAB:一些杂例
a 2; b 5; x 0:pi/40:pi/2; %增量为pi/40 y b*exp(-a*x).*sin(b*x).*(0.012*x.^4-0.15*x.^30.075*x.^22.5*x); %点乘的意义 z y.^2; %点乘的意义 w(:,1) x; %组成w,第一列为x w(:,2) y; %组成w,第二列为y w(:,3) z; %组成w,第三列为z…...

使用OpenCV实现两张图像融合在一起
简单介绍 图像融合技术是一种结合多个不同来源或不同传感器捕获的同一场景的图像数据,以生成一幅更全面、更高质量的单一图像的过程。这种技术广泛应用于遥感、医学影像分析、计算机视觉等多个领域。常见的图像融合技术包括基于像素级、特征级和决策级的融合方法&a…...

PyTorch学习笔记之基础函数篇(十)
文章目录 6 张量操作6.1 torch.reshape()函数6.1 torch.transpose()函数6.1 torch.permute()函数6.1 torch.unsqueez()函数6.1 torch.squeeze()函数6.1 torch.cat()函数6.1 torch.stack()函数 6 张量操作 6.1 torch.reshape()函数 torch.reshape() 是 PyTorch 中的一个函数&a…...

kubernetes部署集群
kubernetes部署集群 集群部署获取镜像安装docker[集群]阿里仓库下载[集群]集群部署[集群]集群环境配置[集群]关闭系统Swap[集群]安装Kubeadm包[集群]配置启动kubelet[集群]配置master节点[master]配置使用网络插件[master]node加入集群[node]后续检查[master]测试集群 集群部署…...

软件工程师,该偿还一下技术债了
概述 在软件开发领域,有一个特殊的概念——“技术债”,它源于Ward Cunningham的一个比喻,主要用来描述那些为了短期利益而选择的快捷方式、临时解决方案或者未完成的工作,它们会在未来产生额外的技术成本。就像金融债务一样&#…...

HTML5、CSS3面试题(三)
HTML5、CSS3面试题(二) rem 适配方法如何计算 HTML 跟字号及适配方案?(必会) 通用方案 1、设置根 font-size:625%(或其它自定的值,但换算规则 1rem 不能小于 12px) 2…...

pytorch之诗词生成6--eval
先上代码: import tensorflow as tf from dataset import tokenizer import settings import utils# 加载训练好的模型 model tf.keras.models.load_model(r"E:\best_model.h5") # 随机生成一首诗 print(utils.generate_random_poetry(tokenizer, model)…...

Django自定义中间件
自定义中间件 传统方法的的五大钩子函数:(需要调用MiddlewareMixin类) process_request,请求刚到来,执行视图之前;正序 process_view,路由转发到视图,执行视图之前;正序…...

【JavaScript】JavaScript 运算符 ① ( 运算符分类 | 算术运算符 | 浮点数 的 算术运算 精度问题 )
文章目录 一、JavaScript 运算符1、运算符分类2、算术运算符3、浮点数 的 算术运算 精度问题 一、JavaScript 运算符 1、运算符分类 在 JavaScript 中 , 运算符 又称为 " 操作符 " , 可以实现 赋值 , 比较 > < , 算术运算 -*/ 等功能 , 运算符功能主要分为以下…...

掘根宝典之C++迭代器简介
简介 迭代器是一种用于遍历容器元素的对象。它提供了一种统一的访问方式,使程序员可以对容器中的元素进行逐个访问和操作,而不需要了解容器的内部实现细节。 C标准库里每个容器都定义了迭代器 迭代器的作用类似于指针,可以指向容器中的某个…...

DP-力扣 120.三角形最小路径和
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。相邻的结点: 下标与上一层结点下标相同或者等于上一层结点下标 1 的两个结点。样例: 例如,给定三角形: [ [2], [3,4], [6,5,7], [4…...

【WEEK3】学习目标及总结【SpringMVC】【中文版】
学习目标: 三周完成SpringMVC入门——第三周 感觉这周很难完成任务了,大概率还会有第四周 学习内容: 参考视频教程【狂神说Java】SpringMVC最新教程IDEA版通俗易懂数据处理JSON交互处理 学习时间及产出: 第三周 MON~FRI 2024.…...

peft模型微调--Prompt Tuning
模型微调(Model Fine-Tuning)是指在预训练模型的基础上,针对特定任务进行进一步的训练以优化模型性能的过程。预训练模型通常是在大规模数据集上通过无监督或自监督学习方法预先训练好的,具有捕捉语言或数据特征的强大能力。 PEF…...

【算法训练营】周测1
清华大学驭风计划课程链接 学堂在线 - 精品在线课程学习平台 (xuetangx.com) 如果需要答案代码可以私聊博主 有任何疑问或者问题,也欢迎私信博主,大家可以相互讨论交流哟~~ 考题11-1 题目描述 有一个初始时为空的序列,你的任务是维护这个…...

PyTorch Dataset、DataLoader长度
pytorch 可以直接对 Dataset 对象用 len() 求数据集大小,而 DataLoader 对象也可以用 len(),不过求得的是用这个 loader 在一个 epoch 能有几多 iteration,容易混淆。本文记录几种情况的对比。 from torch.utils.data import Dataset, DataL…...

动态IP和静态IP
与静态 IP 地址不同,动态 IP 地址会定期更改。让我们来分析一下: 1. IP 地址基础知识: * IP 地址是一个数字标签,用于唯一标识网络上的每个设备。 * 当设备通过网络通信时,数据会在它们之间来回传输。每个数据包都标有…...

中电金信:技术实践|Flink维度表关联方案解析
导语:Flink是一个对有界和无界数据流进行状态计算的分布式处理引擎和框架,主要用来处理流式数据。它既可以处理有界的批量数据集,也可以处理无界的实时流数据,为批处理和流处理提供了统一编程模型。 维度表可以看作是用户来分析数…...

HQL 55 题【持续更新】
前言 今天开始为期一个多月的 HQL 练习,共 55 道 HQL 题,大概每天两道,从初级函数到中级函数。这次的练习不再是基础的 join 那种通用 SQL 语法了,而是引入了更多 Hive 的函数(单行函数、窗口函数等)。 我…...

lqb省赛日志[8/37]-[搜索·DFS·BFS]
一只小蒟蒻备考蓝桥杯的日志 文章目录 笔记DFS记忆化搜索 刷题心得小结 笔记 DFS 参考 深度优先搜索(DFS) 总结(算法剪枝优化总结) DFS的模板框架: function dfs(当前状态){if(当前状态 目的状态){}for(寻找新状态){if(状态合法){vis[访问该点];dfs(新状态);?…...

uni app 钓鱼小游戏
最近姑娘喜欢玩那个餐厅游戏里的钓鱼 ,经常让看广告,然后就点点点... 自己写个吧。小鱼的图片自己搞。 有问题自己改,不要私信我 <template><view class"page_main"><view class"top_linear"><v…...