簡體   English   中英

對struct tm數組進行排序

[英]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表示, intqsort()使用的比較函數返回的值。 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結構的副本,並以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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM