c语言的qsort函数理解与使用

介绍:qsort 函数是 C 标准库中用于排序的快速排序算法函数。它的用法非常灵活,可以对任意类型的元素进行排序,只要提供了比较函数即可。

qsort 函数原型及参数解释:

void qsort (

     void* base,         //指向要排序的数组的首元素的指针

     size_t num,         //待排序数组中元素的个数

     size_t size,        //待排序数组中每个元素的大小(以字节为单位)

     int (*compare)(const void*,const void*)  //比较函数的指针,用于确定元素之间的排序

);

注意: 

使用qsort函数时,需要根据实际情况编写一个合适的比较函数来确定排序规则。

比较函数可以根据元素的类型和排序需求进行自定义。

比较函数的原型如下:

int compare(const void *a, const void *b);

比较函数需要返回一个整数值,表示两个元素之间的关系:

如果返回值小于0,则表示a应该排在b之前。

如果返回值等于0,则表示a和b相等,它们的相对顺序不变。

如果返回值大于0,则表示a应该排在b之后。

对于一个数组或是任意需要进行排序的内容进行排序时可以理解如下:

// qsort中自定义比较函数compare返回值 > 0表示对需要排序的内容进行升序排序(小->大)

// qsort中自定义比较函数compare返回值 < 0表示对需要排序的内容进行降序排序(大->小)

实例:

// qsort排序举例:升序排序(小->大)
// 自定义比较函数返回值 > 0表示对需要排序的内容进行升序排序// qsort 函数是 C 标准库中用于排序的快速排序算法函数。
// 它的用法非常灵活,可以对任意类型的元素进行排序,只要提供了比较函数即可。#include <stdio.h>
#include <stdlib.h>// 比较函数的形式为:
// int cmp(const void *a, const void *b);
// 其中,cmp 函数用于比较 a 和 b 两个指针所指向的元素的大小关系,
// 如果 a 指向的元素小于 b 指向的元素,则返回负数;
// 如果 a 指向的元素大于 b 指向的元素,则返回正数;
// 如果 a 指向的元素等于 b 指向的元素,则返回 0。
// 下面我们来看一个最简单的实例代码,用于对整数数组进行排序:
int compare(const void *a, const void *b)
{printf("%d - %d = %d,  ", *(int *)a, *(int *)b, (*(int *)a - *(int *)b));return (*(int*)a - *(int*)b);
}int main()
{int arr0[] = {2, 1};int len = sizeof(arr0) / sizeof(int);// 这段代码的核心部分就是使用 qsort 函数对整数数组进行排序,排序时需要传递一个比较函数 cmp。// cmp 函数的实现非常简单,就是计算 a 和 b 之间的差值。最后,我们依次输出排序后的整数数组。// 需要注意的是,在使用 qsort 函数时,我们需要传递以下参数:// 1. 待排序的数组的首地址。// 2. 数组中元素的个数。// 3. 每个元素的大小(以字节为单位)。// 4. 比较函数的地址(即函数指针)。// 这里我们传递的数组是 int 类型的数组,每个元素占据 4 个字节;// 比较函数 cmp 的地址可以直接传递函数名,也可以使用 & 运算符取地址。// 这就是 qsort 函数的基本用法。// 需要注意的是,cmp 函数要保证正确性和稳定性才能得到正确的排序结果,同时在实际使用时,也需要根据具体情况进行参数传递和处理。printf("arr0 升序排序过程:\n");// compare 返回值 > 0表示对数组arr1进行降序排序qsort(arr0, len, sizeof(int), compare);printf("\narr0 after sort:\n");for (int i = 0; i < len; i++) {printf("%d ", arr0[i]);}printf("\n");int arr1[] = {3, 2, 1, 5, -2, 9};int len1 = sizeof(arr1) / sizeof(int);printf("\narr1 升序排序过程:\n");// compare 返回值 > 0表示对数组arr1进行降序排序qsort(arr1, len1, sizeof(int), compare);printf("\narr1 after sort:\n");for (int i = 0; i < len1; i++) {printf("%d ", arr1[i]);}printf("\n");return 0;
}

// qsort排序举例:降序排序(大->小)
#include <stdio.h>
#include <stdlib.h>int cmp0(const void *a, const void *b)
{printf("%d - %d = %d,  ", *(int *)a, *(int *)b, (*(int *)a - *(int *)b));return -(*(int*)a - *(int*)b);
}int cmp1(const void *a, const void *b)
{printf("%d - %d = %d,  ", *(int *)b, *(int *)a, (*(int *)b - *(int*)a));return (*(int *)b - *(int*)a);
}int main()
{int arr[] = {5, 4, 2, 5, 3, 1};int len = sizeof(arr) / sizeof(int);printf("升序排序过程:\n");// cmp1返回值 < 0表示对数组arr1进行降序排序qsort(arr, len, sizeof(int), cmp0);printf("\nafter sort:\n");for (int i = 0; i < len; i++) {printf("%d ", arr[i]);}printf("\n");// cmp1返回值 < 0表示对数组arr1进行降序排序int arr1[] = {3, 2, 1, 5, -2, 9};printf("降序排序过程:\n");qsort(arr1, len, sizeof(int), cmp1);printf("\nafter sort:\n");for (int i = 0; i < len; i++) {printf("%d ", arr1[i]);}printf("\n");return 0;
}

// 对浮点数进行排序
#include <stdio.h>
#include <stdlib.h>// 对浮点数进行升序排序
int cmpFloat2Ascending(const void *a, const void *b)
{return *(float *)a - *(float *)b;
}// 对浮点数进行降序排序
int cmpFloat2Descending(const void *a, const void *b)
{return -(*(float *)a - *(float *)b);
}int main()
{float arr0[] = { -0.52, 1.7, 20.5, 9.9, 10.22 };int num0 = sizeof(arr0) / sizeof(int);printf("升序排序过程:\n");// cmp1返回值 < 0表示对数组arr1进行降序排序qsort(arr0, num0, sizeof(float), cmpFloat2Ascending);printf("\nafter sort:\n");for (int i = 0; i < num0; i++) {printf("%.2f ", arr0[i]);}printf("\n");// cmp1返回值 < 0表示对数组arr1进行降序排序float arr1[] = {3.3, 5.2, 1.1, 0.5, -1.2, 9.9};int num1 = sizeof(arr0) / sizeof(float);printf("降序排序过程:\n");qsort(arr1, num1, sizeof(float), cmpFloat2Descending);printf("\nafter sort:\n");for (int i = 0; i < num1; i++) {printf("%.2f ", arr1[i]);}printf("\n");return 0;
}

// qsort 函数对结构体类型的数据进行升序和降序排序:
// 这个程序定义了一个 Student 结构体类型,包含了学生的姓名、年龄和考试成绩三个成员变量。
// 在比较函数中,我们先比较考试成绩的大小,如果不同则返回差值;
// 如果考试成绩相同,则比较年龄的大小,如果不同则返回差值;
// 如果年龄也相同,则比较姓名的大小,从而实现了升序和降序排序。
// 在 main 函数中,我们首先定义了一个 Student 类型的数组,用于测试排序结果。
// 然后先调用 qsort 函数实现升序排序,并输出排序后的结果;
// 接着再调用 qsort 函数实现降序排序,并输出排序后的结果。
// 需要注意的是,在实际使用 qsort 函数时,需要根据具体情况进行参数传递和处理,
// 特别是在程序中使用了自定义结构体类型时,需要编写相应的比较函数来实现排序。
// 同时,也需要特别注意比较函数的实现方式,确保能够正确地比较结构体类型的各个成员变量。#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct {char name[20];int age;int score;
} Student;// 升序
int cmpAsc(const void *a, const void *b)
{Student *sa = (Student *)a;Student *sb = (Student *)b;if (sa->score != sb->score) {return sa->score - sb->score;} else if (sa->age != sb->age) {return sa->age - sb->age;} else {return strcmp(sa->name, sb->name);}
}// 降序
int cmpDesc(const void *a, const void *b)
{Student *sa = (Student *)a;Student *sb = (Student *)b;if (sa->score != sb->score) {return -(sa->score - sb->score);} else if (sa->age != sb->age) {return -(sa->age - sb->age);} else {return -strcmp(sa->name, sb->name);}
}int main()
{Student students[] = {{"Alice", 18, 80},{"Bob", 20, 70},{"Charlie", 19, 90},{"David", 18, 80},{"Ella", 20, 85}};int n = sizeof(students) / sizeof(students[0]);// 升序qsort(students, n, sizeof(Student), cmpAsc);printf("Asc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\t Score: %d\n", students[i].name, students[i].age, students[i].score);}printf("\n");// 降序排序qsort(students, n, sizeof(Student), cmpDesc);printf("Desc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\t Score: %d\n", students[i].name, students[i].age, students[i].score);}return 0;
}
// 实现一个自定义的模拟qsort函数
// 在这个程序中,我们首先定义了一个 Person 结构体类型,包含名称和年龄两个成员变量。
// 在比较函数中,我们首先比较名称的大小,如果不同则返回名称的差值;
// 如果名称相同,则比较年龄的大小,从而实现了升序和降序排序。
// 在 bubble_sort 函数中,我们使用冒泡排序的逻辑来实现元素的排序,传入的对象是 void 指针,
// 因此我们需要将其强制转换为 char 指针,然后利用 memcpy 函数以元素的大小 width 为单位进行移动。
// 每次比较都使用传入的函数指针 cmp 来比较元素的大小,如果需要交换则使用 memcpy 函数来实现交换。
// 在 main 函数中,我们首先定义了一个 Person 类型的数组,包含了五个元素。
// 我们先对数组进行升序排序打印输出,然后再进行降序排序打印输出。
// 需要注意的是,在输出时使用了结构体的成员变量 name 和 age,分别代表了名称和年龄
#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct {char name[20];int age;
} Person;int cmp_asc(const void *a, const void *b)
{Person *pa = (Person *)a;Person *pb = (Person *)b;if (strcmp(pa->name, pb->name) != 0) {return strcmp(pa->name, pb->name);} else {return pa->age - pb->age;}
}int cmp_desc(const void *a, const void *b)
{Person *pa = (Person *)a;Person *pb = (Person *)b;if (strcmp(pa->name, pb->name) != 0) {return strcmp(pb->name, pa->name);} else {return pb->age - pa->age;}
}void bubble_sort0(void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *))
{char *array = (char *)base;for (int i = 0; i < nel - 1; i++) {for (int j = i + 1; j < nel; j++) {// > 0 表示升序if (cmp(array + i * width, array + j * width) > 0) {char tmp[width];memcpy(tmp, array + j * width, width);memcpy(array + j * width, array + i * width, width);memcpy(array + i * width, tmp, width);}}}
}void bubble_sort1(void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *))
{char *array = (char *)base;for (int i = 0; i < nel - 1; i++) {for (int j = 0; j < nel - i - 1; j++) {// > 0 表示升序if (cmp(array + j * width, array + (j + 1) * width) > 0) {char tmp[width];memcpy(tmp, array + j * width, width);memcpy(array + j * width, array + (j + 1) * width, width);memcpy(array + (j + 1) * width, tmp, width);}}}
}int main()
{Person people[] = {{"Alice", 18},{"Bob", 20},{"Charlie", 19},{"David", 18},{"Ella", 20}};int n = sizeof(people) / sizeof(Person);// 升序排序bubble_sort0(people, n, sizeof(Person), cmp_asc);printf("Asc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\n", people[i].name, people[i].age);}printf("\n");// 降序排序bubble_sort1(people, n, sizeof(Person), cmp_desc);printf("Desc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\n", people[i].name, people[i].age);}return 0;
}

// 实现一个自定义的模拟qsort函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct {char name[20];int age;
} Person;int cmp_asc(const void *a, const void *b)
{Person *pa = (Person *)a;Person *pb = (Person *)b;if (strcmp(pa->name, pb->name) != 0) {return strcmp(pa->name, pb->name);} else {return pa->age - pb->age;}
}int cmp_desc(const void *a, const void *b)
{Person *pa = (Person *)a;Person *pb = (Person *)b;if (strcmp(pa->name, pb->name) != 0) {return strcmp(pb->name, pa->name);} else {return pb->age - pa->age;}
}//交换 --一个字节一个字节的交换,共交换width次
void Swap(char* buf1, char* buf2, size_t width)
{size_t i = 0;for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}
void my_BubbleSort(void* base, size_t num,size_t width, int(*cmp)(const void* e1, const void* e2))
{//冒泡排序//若要排序n个元素,只需要进行n-1趟//每一趟可以少比较一个元素,每一趟可以使一个元素在确定的位置上//num:要排序元素的个数 类型是size_t //num是无符号数 防止产生警告 所以i和j也定义为size_t// size_t == unsigned int size_t i = 0;size_t j = 0;//共进行num-1趟for (i = 0; i < num; i++){//每一趟for (j = 0; j < num - 1 - i; j++){//比较//传地址   //相邻两个元素比较   width:宽度,每个元素所占字节//排成升序if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){//交换两数Swap( (char*)base + j * width, (char*)base + (j + 1) * width, width );}}}
}int main()
{Person people[] = {{"Alice", 18},{"Bob", 20},{"Charlie", 19},{"David", 18},{"Ella", 20}};int n = sizeof(people) / sizeof(Person);// 升序排序my_BubbleSort(people, n, sizeof(Person), cmp_asc);printf("Asc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\n", people[i].name, people[i].age);}printf("\n");// 降序排序my_BubbleSort(people, n, sizeof(Person), cmp_desc);printf("Desc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\n", people[i].name, people[i].age);}return 0;
}

使用qsort对字符串数组进行排序:

// 使用qsort函数来对字符串数组进行升序和降序排序#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX_STR_NUM 10
#define MAX_STR_LEN 20int cmpAsc(const void *a, const void *b)
{char **pa = (char **)a;char **pb = (char **)b;return strcmp(*pa, *pb);
}int cmpDesc(const void *a, const void *b)
{char **pa = (char **)a;char **pb = (char **)b;return -strcmp(*pa, *pb);return strcmp(*pb, *pa);
}int main()
{int n = 3;int i = 0;char **strs = (char **)malloc(n * sizeof(char *));char *str0 = (char *)malloc(100);for (i = 0; i < 3; ++i) {strs[i] = (char *)malloc(100);}snprintf(strs[0], 100, "ff str0\n");snprintf(strs[1], 100, "dd str1\n");snprintf(strs[2], 100, "aa str2\n");// 升序排序qsort(strs, n, sizeof(char *), cmpAsc);printf("\nAsc: \n");for(int i = 0; i < n; i++) {printf("%s", strs[i]);}printf("\n");// 降序排序qsort(strs, n, sizeof(char *), cmpDesc);printf("\nDesc: \n");for(int i = 0; i < n; i++) {printf("%s", strs[i]);}printf("\n");return 0;
}
// 使用qsort函数对字符串数组进行排序#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 在实际使用时,比较函数的参数应该根据实际情况转换为正确的指针类型。
// 在字符串数组中,每个元素都是指向一个字符串的指针,
// 因此需要将`const void *`类型的指针转换为`char **`类型的指针,即指向指针的指针,然后才能解引用该指针,
// 即使用`*(char **)a`,获取指向的字符串。
// 如果使用`(char *)a`进行强制类型转换,`char *`类型的指针是单层指针,而不是指针的指针。
// 这将导致在解引用该指针时不能得到正确的字符串指针,从而产生错误的答案。
// 因此,在使用指针数组中的字符串进行排序时,
// 必须使用`char **`类型的指针进行指针转换,再解引用该指针获取到正确的字符串指针进行比较,才能保证排序的正确性。
// a和b的值是strs的元素的地址,也就是指针的指针,所以void其实是char*,void*就是char**
// strs的每个元素都是一个指针,每个元素的地址就应该用指针的指针来存储
// 所以a和b就是指针的指针,所以void*就是char**,void想当于char*
int cmp(const void *a, const void *b)
{printf("a : %p, b : %p\n", a, b);char *tmpa = (char *)a;char *tmpb = (char *)b;char **tmpaa = (char **)a;char **tmpbb = (char **)b;printf("*tmpa:  %s, **tmpaa:%s\n", tmpa, *tmpaa);printf("tmpa: %p, tmpb: %p, tmpaa: %p, tmpbb: %p\n",tmpa, tmpb, tmpaa, tmpbb);// 调试后发现:// a存放的是strs[0]的地址(char**类型)b存放的是strs[1]的地址(char**类型)        // strcmp()会将p地址对应的内容转化成字符串,也就是将strs[0~2]的地址转化成字符串,将得到一个乱码// 因为将(char **类型的数据转换成了char *类型的数据,这样解引用出来的字符串当然是错误的// 因此得先把a,b转化成char**,这样解引用以后才是一个char*的地址// return strcmp(tmpa, tmpb);// return strcmp(*tmpaa, *tmpbb);// 用指针的方式进行排序return strcmp(*(char **)a, *(char **)b);// 不能将二级指针直接解引用,这样借用用后的值为1个一级指针,而不是一个字符串,// 因此需要转换成char **类型后在进行解引用操作// return strcmp((char *)a, (char *)b);
}int main()
{int n = 3;int i = 0;char **strs = (char **)malloc(n * sizeof(char *));char *str0 = (char *)malloc(100);for (i = 0; i < 3; ++i) {strs[i] = (char *)malloc(100);}printf("strs: %p, *strs: %p, strs[0]: %p, strs[1]: %p, strs[2]: %p\n",strs, *strs, strs[0], strs[1], strs[2]);printf("strs: %p, &strs[0]: %p, &strs[1]: %p, &strs[2]: %p\n",strs, &strs[0], &strs[1], &strs[2]);snprintf(strs[0], 100, "ff str0\n");snprintf(strs[1], 100, "dd str1\n");snprintf(strs[2], 100, "aa str2\n");printf("\nbefore sort:\n");for (i = 0; i < n; ++i) {printf("%s", strs[i]);}// 传入的参数为strs[0~2],即指针的指针qsort(strs, n, sizeof(char *), cmp);printf("\nafter sort:\n");for (i = 0; i < n; ++i) {printf("%s", strs[i]);}printf("\n");for (i = 0; i < n; ++i) {free(strs[i]);}free(strs);return 0;
}

通过以上代码可以活得一个经验,在进行字符串数组比时较需要注意如下问题:

不能在自定义的数据比较函数中return strcmp((char *)a, (char *)b);

而是应该return strcmp(*(char **)a, *(char **)b);

strs是一个指针数组,保存3个指针,也就是说&strs[0], &strs[1], &strs[2]都是二级指针,

地址分别为

0x555555757260

0x555555757268

0x555555757270

这3个二级指针分别各自保存1个一级指针,分别为strs[0], strs[1], strs[2]

指针的地址和保存的字串分别为:

0x5555557572f0 "ff str0\n"

0x555555757360 "dd str1\n"

0x5555557573d0 "aa str2\n"

而传入到cmp函数中的指针为二级指针&strs[0], &strs[1], &strs[2]

(用void *类型作为形参类型,并于不同类型数据的转换),

二级指针保存一级指针的地址对应关系为:

&strs[0]: 0x555555757260 ->  strs[0]:0x5555557572f0 "ff str0\n"

&strs[1]: 0x555555757268->  strs[0]:0x555555757360 "dd str1\n"

&strs[2]: 0x555555757270->  strs[0]:0x5555557573d0 "aa str2\n"

若将传入的二级指针转换成char *类型,则接应用时去除的字符串是一个乱码,

因为二级指针保存的值为1个一级指针,所以接应用后的值仍然是一个一级指针,

而这个一级指针指向的内容才是需要获取的字符串。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/887740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

#渗透测试#红蓝攻防#HW#漏洞挖掘#漏洞复现01-笑脸漏洞(vsftpd)

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

(73)脉冲幅度调制PAM调制解调通信系统的MATLAB仿真

文章目录 前言一、PAM调制的基本原理二、PAM调制的步骤三、PAM调制示例四、PAM调制的应用五、MATLAB仿真1. 仿真代码2. 仿真结果 总结 前言 PAM&#xff08;Pulse Amplitude Modulation&#xff0c;脉冲振幅调制&#xff09;是一种模拟信号到数字信号的转换方式&#xff0c;它…

算法的NPU终端移植:深入探讨与实践指南

目录 ​编辑 引言 算法选择 模型压缩 权重剪枝 量化 知识蒸馏 硬件适配 指令集适配 内存管理 并行计算 性能测试 速度测试 精度测试 功耗测试 案例分析 图像识别算法的NPU移植案例 结论 引言 在人工智能技术的浪潮中&#xff0c;神经网络处理器&#xff08;…

汽车免拆诊断案例 | 2017款捷豹F-PACE车发动机偶尔怠速不稳

故障现象  一辆2017款捷豹F-PACE车&#xff0c;搭载2.0 L GTDi发动机&#xff0c;累计行驶里程约为16万km。车主反映&#xff0c;车辆组合仪表上发动机故障灯点亮&#xff08;图1&#xff09;&#xff0c;且发动机偶尔怠速不稳。 图1 发动机故障灯点亮 故障诊断 接车后试车…

不建模,无代码,如何快速搭建VR虚拟展厅?

不建模、无代码搭建虚拟展厅&#xff0c;可以借助一些专业的虚拟展厅搭建平台或工具来实现。以下是一些具体的步骤和建议&#xff1a; 一、选择平台或工具 首先&#xff0c;需要选择一个适合的平台或工具来搭建虚拟展厅。这些平台通常提供预设的展厅模板、拖拽式编辑工具和丰富…

数星星 (C++ 树状数组)

1265. 数星星 - AcWing题库 分析&#xff1a; 星星是按纵坐标递增给我们的&#xff0c;如果纵坐标相同&#xff0c;就按横坐标来给 所以星星是从低到高&#xff0c;一行一行来给的 题目要求我们去求每个等级的星星各有多少个 星星的等级由它左下角&#xff08;包括左边和下…

AIGC培训讲师人工智能培训讲师叶梓Python深度学习与AIGC培训提纲

【课程时长】 8天&#xff08;6小时/天&#xff09; 【课程简介】 随着AIGC&#xff08;基于AI的内容生成&#xff09;技术的崛起&#xff0c;以ChatGPT为代表的人工智能技术正引领全球科技潮流。为了帮助学员更好地理解和应用这一技术&#xff0c;特推出了本课程。 本课程…

GB28181系列三:SIP消息格式

我的音视频/流媒体开源项目(github) GB28181系列目录 目录 一、SIP消息Header字段 二、SIP URI(URL) 三、SIP路由机制 1、路由机制介绍 2、严格路由&#xff08;Strict Routing&#xff09;与松散路由&#xff08;Louse Routing&#xff09; 3、总结 四、SIP消…

STM32-C语言基础知识

C语言基础知识 stdint.h简介 给寄存器某个位赋值 给位6赋值为1流程&#xff1a;先清0&#xff0c;再赋值 带参数的宏定义 建议使用do {…}while(0)来构造宏定义 条件编译 条件编译后面必须跟宏语句&#xff0c;如#if _LED_H 指针使用常见的2大问题 1、未初始化 2、越界使…

计算机网络 实验八 应用层相关协议分析

一、实验目的 熟悉CMailServer邮件服务软件和Outlook Express客户端软件的基本配置与使用&#xff1b;分析SMTP及POP3协议报文格式和SMTP及POP3协议的工作过程。 二、实验原理 为了观察到邮件发送的全部过程&#xff0c;需要在本地计算机上配置邮件服务器和客户代理。在这里我…

若依解析(一)登录认证流程

JWTSpringSecurity 6.X 实现登录 JWT token只包含uuid ,token 解析uuid&#xff0c;然后某个常量加UUID 从Redis缓存查询用户信息 流程图如下 感谢若依&#xff0c;感谢开源&#xff0c;能有这么好系统供我学习。 设计数据库&#xff0c;部门表&#xff0c;用户表&#xff0c…

阿里巴巴即将超越OpenAI的o1?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

第29天 MCU入门

目录 MCU介绍 MCU的组成与作用 电子产品项目开发流程 硬件开发流程 常用元器件初步了解 硬件原理图与PCB板 常见电源符号和名称 电阻 电阻的分类 贴片电阻的封装说明&#xff1a; 色环电阻的计算 贴片电阻阻值计算 上拉电阻与下拉电阻 电容 电容的读数 二极管 LED 灯电路 钳位作…

Pump Science平台深度剖析:兴起、优势、影响与未来

在过去的几个月里&#xff0c;人们越来越关注去中心化科学&#xff08;DeSci&#xff09;。DeSci 是一种利用区块链技术进行科学研究的新方法。传统的科学研究经常面临所谓的“死亡之谷”&#xff0c;这指的是基础科学研究与成功开发和造福患者的实施之间的重要时期。DeSci 旨在…

Tülu 3:重新定义开源大模型的后训练范式

一、引言 在大型语言模型&#xff08;LLM&#xff09;的发展历程中&#xff0c;预训练阶段往往受到最多关注&#xff0c;动辄需要数百万美元算力投入和数万亿token的训练数据。然而&#xff0c;一个鲜为人知但同样关键的事实是&#xff1a;预训练完成的模型实际上并不能直接投…

Excel中根据某列内容拆分为工作簿

简介&#xff1a;根据A列的内容进行筛选&#xff0c;将筛选出来的数据生成一个新的工作簿(可以放到指定文件夹下)&#xff0c;且工作簿名为筛选内容。 举例&#xff1a; 将上面的内容使用VBA会在当前test1下生成5个工作簿&#xff0c;工作簿名分别为TEST1.xls TEST2.xls TEST3…

【电子通识】“标准的标准”:国家标准GB/T 1.1-2020 标准的分类

标准是可以分类的。比如根据层次、专业、对象、目的、功能等维度进行分类。 以层次进行分类&#xff1a; 可以分为国际标准、区域标准、国家标准、团体标准、企业标准、行业标准 以专业进行分类&#xff1a; 可以分为农业、医药、卫生、劳动保护、矿业、化工、机械等等。 以对象…

【网络安全设备系列】12、态势感知

0x00 定义&#xff1a; 态势感知&#xff08;Situation Awareness&#xff0c;SA&#xff09;能够检测出超过20大类的云上安全风险&#xff0c;包括DDoS攻击、暴力破解、Web攻击、后门木马、僵尸主机、异常行为、漏洞攻击、命令与控制等。利用大数据分析技术&#xff0c;态势感…

数据库(MySQL黑马)

基础篇 MySQL概述 数据库概述 数据库相关概念 主流的关系型数据库管理系统 MySQL数据库的安装与启动 下载&#xff1a;MySQL :: MySQL Community Downloads 安装步骤 MySQL―8.0.40超详细保姆级安装教程_mysql8.0.40安装教程-CSDN博客文章浏览阅读1k次。_mysql8.0.40安装教…

Java算法OJ(11)双指针练习

目录 1.前言 2.正文 2.1存在重复数字 2.1.1题目 2.1.2解法一代码 解析&#xff1a; 2.1.3解法二代码 解析&#xff1a; 2.2存在重复数字plus 2.2.1题目 2.2.2代码 2.2.3解析 3.小结 1.前言 哈喽大家好吖&#xff0c;今天来给大家分享双指针算法的相关练习&…