[英]Sort an array of struct tm
我目前正在用C创建个人日记,我希望可以打印按日期排序的帖子。 我可以使用struct tm提取日期,但是我不知道如何对日期进行排序,因此最新日期排在最前面。 这是我的整个功能:
void dateOrder() {
FILE *postfile = fopen("post.txt", "r");
int numofpost = getNumOfPost(postfile);
int dates[numofpost];
struct tm ptime;
char *elt = malloc(5 * sizeof(char));
char *dref = "Date";
char *href = "Heure";
char c = 'c';
char *pseudo = malloc(20 * sizeof(char));
int pseudolen = 0;
rewind(postfile);
while (!feof(postfile)) {
fscanf(postfile, "%s", elt);
if (strcmp(elt, dref) == 0) {
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d/%d/%d", (int)&(ptime.tm_mday), (int)&(ptime.tm_mon), (int)&(ptime.tm_year));
}
if (strcmp(elt, href) == 0) {
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d:%d", (int)&(ptime.tm_hour), (int)&(ptime.tm_min));
}
ptime.tm_year -= 1900;
ptime.tm_mon -= 1;
ptime.tm_sec = 0;
ptime.tm_isdst = -1;
int rep = mktime(&ptime);
if (rep != -1) {
dates[i++] = rep;
}
}
insertsort(dates, sizeof(dates)/sizeof(dates[0]));
for (int i = 0; i < numofpost; i++) {
c = 'c';
rewind(postfile);
while (!feof(postfile) && c != 24) {
fscanf(postfile, "%s", elt);
if (strcmp(elt, "Pseudo") == 0) {
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%s", pseudo);
pseudolen = strlen(pseudo);
}
if (strcmp(elt, dref) == 0) {
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d/%d/%d", (int)&(ptime.tm_mday), (int)&(ptime.tm_mon), (int)&(ptime.tm_year));
}
if (strcmp(elt, href) == 0) {
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d:%d", (int)&(ptime.tm_hour), (int)&(ptime.tm_min));
}
ptime.tm_year -= 1900;
ptime.tm_mon -= 1;
ptime.tm_sec = 0;
ptime.tm_isdst = -1;
int mkt = mktime(&ptime);
if (mkt == dates[i]) {
fseek(postfile, -39, SEEK_CUR);
fseek(postfile, -pseudolen, SEEK_CUR);
while (c != 24) {
c = fgetc(postfile);
if (c == 24)
continue;
printf("%c", c);
}
}
}
}
fclose(postfile);
}
这是struct tm:
struct tm {
int tm_sec; /* seconds, range 0 to 59 */
int tm_min; /* minutes, range 0 to 59 */
int tm_hour; /* hours, range 0 to 23 */
int tm_mday; /* day of the month, range 1 to 31 */
int tm_mon; /* month, range 0 to 11 */
int tm_year; /* The number of years since 1900 */
int tm_wday; /* day of the week, range 0 to 6 */
int tm_yday; /* day in the year, range 0 to 365 */
int tm_isdst; /* daylight saving time */
};
您可以使用mktime()
和difftime()
编写比较函数,然后使用qsort()
对tm
结构数组进行排序。 qsort()
可以使用下面的比较函数cmp_dates_descend()
对日期数组进行降序排序:
#include <stdlib.h>
#include <time.h>
#define NUM_DATES 10 /* for example */
int cmp_dates_descend(const void *d1, const void *d2);
int main(void)
{
/* ... */
struct tm arr_dates[NUM_DATES];
/* ... */
size_t num_dates = sizeof arr_dates / sizeof *arr_dates;
qsort(arr_dates, num_dates, sizeof *arr_dates, cmp_dates_descend);
/* ... */
return 0;
}
int cmp_dates_descend(const void *d1, const void *d2)
{
struct tm *date_1 = (struct tm *) d1;
struct tm *date_2 = (struct tm *) d2;
return double d = -difftime(mktime(date_1), mktime(date_2));
}
请注意,对于大的日期差异,此方法可能会遇到问题。 由于difftime()
返回double
difftime()
值(表示以秒为单位的时间差),因此返回值可能无法以int
表示, int
是qsort()
使用的比较函数返回的值。 在INT_MAX == 2147483647
(典型值为4字节int
的情况下,日期差超过68年将导致从double
到int
的转换溢出,从而导致不确定的行为。 如果要处理如此大的日期差异,则可能应编写自定义排序函数。
编辑
@chqrlie在评论中指出,此方法也可能导致极接近日期(几分之一秒)的错误比较,因为如果difftime(mktime(date_1), mktime(date_2))
大小小于1
,则值将在返回时转换为0
,从而进行比较。 为了避免这种复杂性,可以将difftime()
的结果存储在double
并与0
比较以确定返回值。 这是比较功能的常见技巧。 这也消除了以前的日期差异较大的问题。 这是改进的比较功能:
int cmp_dates_descend(const void *d1, const void *d2)
{
struct tm *date_1 = (struct tm *) d1;
struct tm *date_2 = (struct tm *) d2;
double d = difftime(mktime(date_1), mktime(date_2));
return (d < 0) - (d > 0);
}
编辑2
为了使数组保持不变(比较函数在获取指向数组元素的const
指针时应该执行此操作),我们可以在比较函数中复制tm
结构的副本,并以mktime()
性能代价在副本上调用mktime()
:
int cmp_dates_descend(const void *d1, const void *d2)
{
struct tm date_1 = *(const struct tm *)d1;
struct tm date_2 = *(const struct tm *)d2;
double d = difftime(mktime(&date_1), mktime(&date_2));
return (d < 0) - (d > 0);
}
多亏了这里的答案和评论,这是我如何打印按日期排序的帖子
int check(int i, struct tm *dates, struct tm ptime){
if(dates[i].tm_year == ptime.tm_year && dates[i].tm_mon == ptime.tm_mon &&
dates[i].tm_mday == ptime.tm_mday && dates[i].tm_hour == ptime.tm_hour &&
dates[i].tm_min == ptime.tm_min)
return 1;
return 0;
}
int compareDates(const void *d1, const void *d2){
struct tm date_1 = *(const struct tm *)d1;
struct tm date_2 = *(const struct tm *)d2;
double d = difftime(mktime(&date_1), mktime(&date_2));
return (d < 0) - (d > 0);
}
void dateOrder(){ //print the post sorted by date
FILE *postfile = fopen("post.txt", "r");
int numofpost = getNumOfPost(postfile);
struct tm dates[numofpost];
int pseudolen = 0, i = 0;
struct tm ptime;
char *elt = malloc(5*sizeof(char));
char *pseudo = malloc(20*sizeof(char));
char *dref = "Date"; //Word to find to get the date
char *href = "Heure"; //Word to find to get hour
char c = 'c';
rewind(postfile);
while(!feof(postfile)){
fscanf(postfile, "%s", elt);
if(strcmp(elt, dref) == 0){
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d/%d/%d", (int)&(ptime.tm_mday), (int)&(ptime.tm_mon), (int)&(ptime.tm_year));
dates[i].tm_year = ptime.tm_year;
dates[i].tm_mon = ptime.tm_mon;
dates[i].tm_mday = ptime.tm_mday;
}
if(strcmp(elt, href) == 0){
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d:%d", (int)&(ptime.tm_hour), (int)&(ptime.tm_min));
dates[i].tm_hour = ptime.tm_hour;
dates[i++].tm_min = ptime.tm_min;
}
}
size_t num_dates = sizeof(dates)/sizeof(*dates);
qsort(dates, num_dates, sizeof(*dates), compareDates);
for(int i = 0; i < numofpost; i++){
c = 'c';
rewind(postfile);
while(!feof(postfile) && c != 24){ //We read the file until the end c is equal to 24 only if a already founded the wanted post
fscanf(postfile, "%s", elt);
if(strcmp(elt, "Pseudo") == 0){
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%s", pseudo);
pseudolen = strlen(pseudo);
}
if(strcmp(elt, dref) == 0){
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d/%d/%d", (time_t)&(ptime.tm_mday), (time_t)&(ptime.tm_mon), (time_t)&(ptime.tm_year));
}
if(strcmp(elt, href) == 0){
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d:%d", (time_t)&(ptime.tm_hour), (time_t)&(ptime.tm_min));
}
if(check(i, dates, ptime)){ //check look if the member of struct are the same in dates ans ptime
fseek(postfile, -40, SEEK_CUR);
fseek(postfile, -pseudolen, SEEK_CUR);
while(c != 24){ //while c != 24 is because user has stop typing a post when typing Ctrl + X == 24 in ascii code
c = fgetc(postfile);
if(c == 24)
continue;
printf("%c", c);
}
}
if(ftell(postfile)+15 < feof(postfile)) //If it is not the last post
fseek(postfile, 15, SEEK_CUR); //I go to next post*
}
printf("\n\n\n\n");
}
fclose(postfile);
printf("\n\n");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.