对struct tm数组进行排序

时间:2017-07-14 09:54:04

标签: c file sorting date struct

我目前正在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             */
 };

2 个答案:

答案 0 :(得分:3)

您可以使用mktime()difftime()编写比较函数,然后使用qsort()tm结构数组进行排序。 cmp_dates_descend()可以使用下面的比较函数qsort()按降序对日期数组进行排序:

#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(表示以秒为单位的时间差),因此返回值可能无法在int中表示,qsort()是{{1}使用的比较函数返回的值}}。 INT_MAX == 2147483647,典型的4字节int,大于68年的日期差异会导致从doubleint的转换溢出,从而导致未定义的行为。如果要处理这样大的日期差异,可能应该编写自定义排序函数。

修改

@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结构并调用{ {1}}以较低的性能成本复制副本:

mktime()

答案 1 :(得分: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");   
}