每日总结
一旦停下来太久,就很难继续了 ——《一个人的朝圣》
20240222
1. 自定义逻辑
请设计一个函数single_track_logic,传入三个参数,第一个参数是int数组,第二个参数是一个int变量,第三个参数是一个以int为返回值,无输入参数的函数指针,该函数实现以下功能:
1.首先对第一个参数的数组进行排序
2.当第二个参数在第一个参数数组的两个数之间时,返回数组下标
3.循环执行该函数时 当上一次的下标大于此次获取的下标时需要满足第三个参数的函数返回1时才能更新此次获取的数组下标,否则返回上一次的数组下标
#include <stdio.h>
#include <stdlib.h>int compare_up(const void *a, const void *b) {return (*(int*)a - *(int*)b);
}
int compare_down(const void *a, const void *b) {return (*(int*)b - *(int*)a);
}typedef int (*pfunc_condition)(void);
typedef enum sort_dir{enum_dir_up = 0,enum_dir_down,enum_dir_none,
}enum_sort_dir;
/*!* @brief: 单向逻辑* @funcname: single_track_logic * @param: arr 阶梯数组* dir 对数组进行排序的方向 从小到大 或者 从大到小 或者 不排序(默认从小到大)* size 阶梯数组的个数* value 要判断的值* pfunc 满足条件时可以重新更新下标* @return: 值所在下标区域* @note: 该函数实现以下功能:* 1.首先对第一个参数的数组进行排序 * 2.当第二个参数在第一个参数数组的两个数之间时,返回数组下标* 3.循环执行该函数时 当上一次的下标大于此次获取的下标时需要满足第三个参数的函数返回1时才能更新此次获取的数组下标,否则返回上一次的数组下标* @date: 20230830*/
int single_track_logic(int arr[], enum_sort_dir dir, int size, int value, pfunc_condition pfunc)
{static int prevIndex = -1; // 上一次获取的数组下标int index;// 对数组进行排序if (dir == enum_dir_up){qsort(arr, size, sizeof(int), compare_up);}else if (dir == enum_dir_down){qsort(arr, size, sizeof(int), compare_down);}else{printf("无需排序\n");}printf("排序结果:");for (size_t i = 0; i < size; i++){printf("%d ",arr[i]);}for (index = 0; index < size; index++) {if ((dir == enum_dir_none) || (dir == enum_dir_up)){if (arr[index] <= value)continue;else break;}else{if (arr[index] >= value)continue;else break;}}if (index >= prevIndex){prevIndex = index;}else{if (pfunc() == 1) //恢复条件成立{index = index;prevIndex = index;}else{index = prevIndex;}}return index-1;
}int custom_function(void) {// 在这里定义你的自定义函数// 返回1或者0int flag = rand() % 2 ? 1 : 0;printf("flag=%d\t", flag);return flag; // 这里只是个示例,根据实际情况修改
}int main() {int arr[] = {5, 3, 8, 1, 7, 4, 10, 0, -1};int num = 0;int size = sizeof(arr) / sizeof(arr[0]);int result = 0;printf("从小到大:\r\n");for (size_t i = 0; i < 10; i++){num = rand() % 10;result = single_track_logic(arr, enum_dir_up, size, num, custom_function);printf("num=%d result=%d\n",num, result);}printf("从大到小:\r\n");for (size_t i = 0; i < 10; i++){num = rand() % 10;result = single_track_logic(arr, enum_dir_down, size, num, custom_function);printf("num=%d result=%d\n",num, result);}return 0;
}
测试情况:
从小到大:
排序结果:-1 0 1 3 4 5 7 8 10 num=3 result=3
排序结果:-1 0 1 3 4 5 7 8 10 num=6 result=5
排序结果:-1 0 1 3 4 5 7 8 10 num=7 result=6
排序结果:-1 0 1 3 4 5 7 8 10 flag=1 num=5 result=5
排序结果:-1 0 1 3 4 5 7 8 10 num=5 result=5
排序结果:-1 0 1 3 4 5 7 8 10 num=6 result=5
排序结果:-1 0 1 3 4 5 7 8 10 flag=1 num=2 result=2
排序结果:-1 0 1 3 4 5 7 8 10 num=1 result=2
排序结果:-1 0 1 3 4 5 7 8 10 num=2 result=2
排序结果:-1 0 1 3 4 5 7 8 10 num=7 result=6
从大到小:
排序结果:10 8 7 5 4 3 1 0 -1 num=0 result=7
排序结果:10 8 7 5 4 3 1 0 -1 flag=1 num=9 result=0
排序结果:10 8 7 5 4 3 1 0 -1 num=6 result=2
排序结果:10 8 7 5 4 3 1 0 -1 num=0 result=7
排序结果:10 8 7 5 4 3 1 0 -1 flag=0 num=6 result=7
排序结果:10 8 7 5 4 3 1 0 -1 flag=1 num=6 result=2
排序结果:10 8 7 5 4 3 1 0 -1 flag=1 num=8 result=1
排序结果:10 8 7 5 4 3 1 0 -1 flag=0 num=9 result=1
排序结果:10 8 7 5 4 3 1 0 -1 num=0 result=7
排序结果:10 8 7 5 4 3 1 0 -1 flag=1 num=2 result=5
2. qsort
qsort
是 C 语言标准库中的一个函数,用于对数组进行快速排序。它的原型定义在 <stdlib.h>
头文件中,函数签名如下:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
base
:指向要排序的数组的起始地址的指针。nmemb
:数组中元素的个数。size
:每个元素的大小,以字节为单位。compar
:比较函数的指针,用来确定元素之间的顺序关系。这个函数接受两个参数,即指向要比较的两个元素的指针,返回值小于、等于或大于 0 分别表示第一个参数小于、等于或大于第二个参数。
qsort
函数使用快速排序算法对数组进行排序,其时间复杂度为 O(n log n),是一种高效的排序算法。在调用 qsort
函数时,需要提供数组的起始地址、元素个数、元素大小以及比较函数,比较函数决定了排序的规则。
以下是一个简单的示例,演示如何使用 qsort
对整数数组进行升序排序:
#include <stdio.h>
#include <stdlib.h>int compare(const void *a, const void *b) {return (*(int*)a - *(int*)b);
}int main() {int arr[] = {5, 3, 8, 1, 10};int size = sizeof(arr) / sizeof(arr[0]);qsort(arr, size, sizeof(int), compare);for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}return 0;
}
在这个示例中,我们定义了一个比较函数 compare
,用于告诉 qsort
函数如何比较两个元素。然后调用 qsort
函数对整数数组 arr
进行排序,最后输出排序后的数组结果。
3. printf输出
3.1 使用C语言模拟输出进度条
#include <stdio.h>
#include <unistd.h> // 用于sleep函数void printProgressBar(int progress, int total) {int barWidth = 50;float progressRatio = (float)progress / total;int progressBar = progressRatio * barWidth;printf("[");for (int i = 0; i < barWidth; i++) {if (i < progressBar) {printf(">"); // 黑方格} else {printf("-"); // 空白}}printf("] %d%%\r", (int)(progressRatio * 100));fflush(stdout); // 刷新输出缓冲区// 可以加上一些延迟效果usleep(100000); // 100毫秒
}int main() {int total = 100;for (int i = 0; i <= total; i++) {printProgressBar(i, total);}printf("\n");return 0;
}
实现原理
当在控制台中使用printf函数输出信息时,输出的内容通常会先被存储在缓冲区中,并不会立即显示在屏幕上。这样做是为了提高效率,在一次性输出大量内容时减少频繁的屏幕刷新操作。但是对于进度条等需要实时更新的情况,我们希望能够立即将信息显示出来,而不是等到缓冲区满或遇到换行符才刷新。
fflush(stdout);
函数用于强制将缓冲区中的内容立即输出到屏幕上。在进度条的实现中,每次调用printProgressBar
函数后,使用fflush(stdout);
可以确保立即将更新后的进度条显示出来。printf("\r");
中的\r
是回车符(Carriage Return),它的作用是将光标移动到当前行的起始位置,这样在输出文本时就可以覆盖之前的内容。这就是为什么在进度条更新时,我们使用\r
来让光标回到行首,然后再输出新的进度条,达到动态更新的效果。综合使用
fflush(stdout);
和\r
,我们可以在控制台中实现动态更新的进度条效果。
printf默认在什么情况下刷新?
在C语言中,printf
函数通常会将输出内容缓存到内存中,并不会立即刷新到输出设备(如终端或文件)上。刷新缓冲区意味着将缓存中的数据写入到输出设备中,使得数据立即可见。
printf
函数默认情况下会在以下几种情况下刷新缓冲区:
- 当缓冲区已满时:当缓冲区达到一定大小或者输出内容包含换行符
\n
时,缓冲区会被自动刷新。 - 当遇到换行符
\n
:如果printf
输出的内容中包含换行符\n
,缓冲区会被刷新,输出内容被立即显示。 - 在程序正常结束时:当程序执行完毕时,缓冲区会被自动刷新,确保所有输出内容被显示出来。
除了以上默认情况外,我们也可以使用 fflush
函数手动刷新输出缓冲区。例如,调用 fflush(stdout)
可以强制刷新标准输出流缓冲区。
需要注意的是,如果程序异常终止(比如使用 exit
函数或者发生错误导致程序崩溃),则缓冲区通常不会被刷新,部分输出内容可能会丢失。因此,在重要的输出操作后,最好及时刷新缓冲区以确保输出内容被正确显示。