如何根据每种情况保留我在文本文件中的位置?

How is it possible to keep the position from where I am in the text files based on each case?

我有 10 个文本文件,其中包含一些数据包,这些数据包由 rollnumber、源、目标和生成时间表示,它们也在一个结构中:

typedef struct Node 
{
    int rollnumber, src, dst;
    double gentime;
    struct Node *next;
} Node;

我想在每个时间单位打开每个文件,并能够检查是否生成了任何数据包。这意味着,生成时间必须小于我所在的时间单元。例如,在时间单元 0-1 中,我必须找到一个 0<生成时间<1 的数据包。因此,如果发生这种情况,该数据包将进入一个具有插入功能的列表:

void insert_end ( Node **head, int rollnumber, int src, int dst, double gentime){
    struct Node * new_node = NULL;
    struct Node * last = NULL;
    new_node = (struct Node *)malloc(sizeof(struct Node));

    if (new_node == NULL)
    {
        printf("Failed to insert element. Out of memory");
        return;
    }

    new_node->rollnumber=rollnumber;
    new_node->src = src;
    new_node->dst=dst;
    new_node->gentime=gentime;
    new_node->next = NULL;

    if( *head == NULL)
    {
        *head = new_node;
        return;
    }
    last = *head;
    while(last->next) last = last->next;
    last->next = new_node;
}

我的代码如下:

for (Time=1.0; Time<10.0; Time=Time+1.0){ //the time units checking them per one like: 0-1,1-2 etc..
        
        for(i=1;i<=10;i++){ //because I have 10 text files
            
            char to_open[32];
            snprintf(to_open,32, "fptg_%d.txt", i);
            printf("\n\nFPTG_%d.txt\n", i);
            
            if ((file = fopen(to_open, "r")) == NULL)
            {
                break;
            }else{
                    
                    fseek(file , pos[i], SEEK_CUR);
                    fgets(line, sizeof(line), file);
                    sscanf(line,"%d %d %d %lf",&rollnumber, &src, &dst, &gentime);
                    printf("%s", line);
                    printf("Return value=%d\n",sscanf(line, " %d %d %d %lf", &rollnumber, &src, &dst, &gentime));
                    printf("gentime=%.1f\n", gentime);
                    pos[i] = ftell(file);
                    
                if(Time<gentime && gentime<Time+1.0){
                    insert_end ( &link[i], rollnumber, src, dst, gentime );
                    printf("Time=%0.1f\n", Time);  
                }else{
                    //do something else here and in the next time unit check the same packet again
                    }

                }    
            }
                
        }
}

我的问题是,如果一个数据包没有插入到列表中,我将如何在下一个时间单元检查同一个数据包?如果一个数据包插入到列表中,读取下一个数据包对我想做的是正确的。但是如果一个数据包没有插入到列表中,我不想在下一个时间单位转到下一个。 任何帮助将不胜感激,提前致谢!

最小可重现示例:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#define MAX_LINE_LENGTH 105

typedef struct Node {
    int rollnumber, src, dst;
    double gentime;
    struct Node *next;
} Node;

void
insert_end(Node **head, int rollnumber, int src, int dst, double gentime)
{
    struct Node *new_node = NULL;
    struct Node *last = NULL;

    new_node = (struct Node *) malloc(sizeof(struct Node));

    if (new_node == NULL) {
        printf("Failed to insert element. Out of memory");
        return;
    }

    new_node->rollnumber = rollnumber;
    new_node->src = src;
    new_node->dst = dst;
    new_node->gentime = gentime;
    new_node->next = NULL;

    if (*head == NULL) {
        *head = new_node;
        return;
    }
    last = *head;
    while (last->next)
        last = last->next;
    last->next = new_node;
}

void
output(Node *head)
{
    for (Node *current = head; current != NULL; current = current->next) {
        // printf("%d ", current->data);
        printf("Roll Number:%2d\t", current->rollnumber);
        printf("src:%2d\t", current->src);
        printf("dest:%2d\t", current->dst);
        printf("gentime:%0.1f\n", current->gentime);
    }
}

void
display(Node **set, int i)
{
    output(set[i]);
    putchar('\n');
}

int
remove_node_in_list(Node **set, size_t pos)
{
    int success = set[pos] != NULL;

    if (success) {
        Node *tmp = set[pos];

        set[pos] = set[pos]->next;
        free(tmp);
    }

    return success;
}

#define N   10

int
main(void)
{
    char line[MAX_LINE_LENGTH] = { 0 };
    int src, dst;
    int rollnumber;
    double gentime;
    int stations = 0;
    Node *link[N] = { 0 };
    int i = 1;
    static unsigned long pos[] = { 0 };
    FILE *file;
    char filename_format[] = "fptg_%d.txt";
    char filename[sizeof(filename_format) + 4];
    bool intention[10];
    double Time = 12.0;
    int lower = 0, upper = 9, count = 1;

    srand(time(0));
    int num;
    int k = 1;
    struct node *head = NULL;

    // the time units checking them per one like: 0-1,1-2 etc..
    for (Time = 1.0; Time < 50.0; Time = Time + 1.0) {

        // because I have 10 text files
        for (i = 1; i <= 10; i++) {
            char to_open[32];

            snprintf(to_open, 32, "fptg_%d.txt", i);
            printf("\n\nFPTG_%d.txt\n", i);

            if ((file = fopen(to_open, "r")) == NULL) {
                break;
            }
            else {

                fseek(file, pos[i], SEEK_CUR);
                fgets(line, sizeof(line), file);
                sscanf(line, "%d %d %d %lf", &rollnumber, &src, &dst, &gentime);
                printf("%s", line);
                printf("Return value=%d\n", sscanf(line, " %d %d %d %lf", &rollnumber, &src, &dst, &gentime));
                printf("gentime=%.1f\n", gentime);
                pos[i] = ftell(file);

                if (Time < gentime && gentime < Time + 1.0) {
                    insert_end(&link[i], rollnumber, src, dst, gentime);
                    printf("Time=%0.1f\n", Time);
                    for (int j = 0; j < count; j++) {
                        int num = (rand() % (upper - lower + 1)) + lower;

                        printf("Random number:%d\n", num);

                        if (num == 1 || num == 6 || num == 8) {
                            intention[i] = true;
                            printf("ok\n");
                            stations++;
                            printf("stations=%d\n", stations);
                            printf("intention[%d]=%d\n", i, intention[i]);
                            double offtime = gentime + 12.0;

                            printf("channel off until: %.1f starting from: %.1f\n\n", offtime, gentime);

                        }
                        else {

                            intention[i] = false;

                            printf("intention[%d]=%d\n", i, intention[i]);
                        }

                    }
                }
                else {
                    printf("Not in the list\n");

                }

            }

        }
    }

    if (stations == 1) {
        for (int i = 1; i <= 10; i++) {
            printf("intention[%d]=%d\n", i, intention[i]);
            if (intention[i] == true) {
                printf("link[%d]:\n", i);
                display(link, i);
                printf("i=%d\n", i);
                remove_node_in_list(link, i);
                printf("NEW:\n");
                display(link, i);
            }
        }

    }
    stations = 0;

    return 0;
}

我第一次&第二次得到的结果是:

FPTG_1.txt
1       1       3       1.6
Return value=4
gentime=1.6
ok
Time=1.0
Random number:2
intention[1]=0


FPTG_2.txt
1       2       4       1.9
Return value=4
gentime=1.9
ok
Time=1.0
Random number:8
ok
stations=1
intention[2]=1
channel off until: 13.9 starting from: 1.9



FPTG_3.txt
1       3       7       1.2
Return value=4
gentime=1.2
ok
Time=1.0
Random number:7
intention[3]=0


FPTG_4.txt
1       4       18      0.2
Return value=4
gentime=0.2
Random number:9
intention[4]=0


FPTG_5.txt
1       5       19      0.2
Return value=4
gentime=0.2
Random number:0
intention[5]=0


FPTG_6.txt
1       6       3       0.1
Return value=4
gentime=0.1
Random number:0
intention[6]=0


FPTG_7.txt
1       7       6       0.0
Return value=4
gentime=0.0
Random number:0
intention[7]=0


FPTG_8.txt
1       8       17      0.5
Return value=4
gentime=0.5
Random number:4
intention[8]=0


FPTG_9.txt
1       9       6       0.1
Return value=4
gentime=0.1
Random number:1
ok
stations=2
intention[9]=1
channel off until: 12.1 starting from: 0.1



FPTG_10.txt
1       10      7       0.1
Return value=4
gentime=0.1
Random number:4
intention[10]=0

FPTG_1.txt
2       1       15      13.9
Return value=4
gentime=13.9
Random number:1
ok
stations=1
intention[1]=1
channel off until: 25.9 starting from: 13.9



FPTG_2.txt
2       2       19      14.0
Return value=4
gentime=14.0
Random number:6
ok
stations=2
intention[2]=1
channel off until: 26.0 starting from: 14.0



FPTG_3.txt
2       3       18      13.4
Return value=4
gentime=13.4
Random number:8
ok
stations=3
intention[3]=1
channel off until: 25.4 starting from: 13.4



FPTG_4.txt
2       4       12      12.8
Return value=4
gentime=12.8
Random number:8
ok
stations=4
intention[4]=1
channel off until: 24.8 starting from: 12.8



FPTG_5.txt
2       5       4       12.3
Return value=4
gentime=12.3
Random number:0
intention[5]=0


FPTG_6.txt
2       6       11      13.1
Return value=4
gentime=13.1
Random number:1
ok
stations=5
intention[6]=1
channel off until: 25.1 starting from: 13.1



FPTG_7.txt
2       7       13      12.8
Return value=4
gentime=12.8
Random number:2
intention[7]=0


FPTG_8.txt
2       8       14      13.5
Return value=4
gentime=13.5
Random number:4
intention[8]=0


FPTG_9.txt
2       9       11      14.0
Return value=4
gentime=14.0
Random number:0
intention[9]=0


FPTG_10.txt
2       10      9       12.1
Return value=4
gentime=12.1
Random number:7
intention[10]=0

下一个时间单位也是如此。例如对于 fptg_4.txt,在第一个时间单位它检查它的第一行:1 4 18 0.2 但在下一个时间单位它转到下一行:2 4 12 12.8,即使它应该有检查同一行,因为前一行表示的数据包没有进入列表。所以,我的问题是这怎么可能?

来自我的热门评论...

  1. 你的 MRE 无法编译,因为有一个额外的 } [已通过我的编辑修复]。

  2. static unsigned long pos[] = { 0 }; 是错误的(它具有 UB--undefined 行为,因为它太短了)。应该是:static unsigned long pos[11] = { 0 };

  3. 您从 1 开始对数组进行索引。这意味着第一个数组元素永远不会被使用,并且所有数组都必须更大(例如 int array[11]; 而不是 int array[10]; 你可能会更好:for (i = 0; i < 10; i++)然后:snprintf(to_open, 32, "fptg_%d.txt", i + 1);

  4. 使用fseek/ftell是有问题的,因为输入文件是可变长度的文本。你想做什么?我唯一能想到的是你想让你的列表按时间排序?

  5. 您总是将 pos[i] 设置为 ftell 值,即使未存储记录也是如此。将 pos[i] = ftell(file); 行移动到 under/after 行 if (Time < gentime && gentime < Time + 1.0) { 行。 (即在 insert_end 调用之上)

  6. 完成最后一次更改后,位置问题已解决。我得到 3479 行,而不是 192 行输出。

  7. 但是,老实说,虽然我不确定您试图通过 intention/stations 代码获得什么效果,但多次重读文件并不是最好的方法。

  8. 我会读取每个文件一次,如果(例如)(gentime >= 1.0) && (gentime <= 50.0),则将其添加到列表中,然后在读取所有文件后,根据存储的 gentime 对链表进行排序。

  9. 似乎意图代码可以完成 outside/after 读取循环,因为它们不依赖于彼此的数据。


其他错误:

  1. 从不fclose所以你有大量悬空的文件流指针。
  2. 您从未检查 fgets 的 return 值,因此您没有正确处理 EOF。
  3. 您调用 sscanf 两次 。一次解码行,另一次只是打印 sscanf
  4. 的 return 值
  5. 不要转换 malloc 的 return 值。参见:Do I cast the result of malloc?

这里是 modified/corrected 代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>

#define MAX_LINE_LENGTH 105

typedef struct Node {
    int rollnumber, src, dst;
    double gentime;
    struct Node *next;
} Node;

void
insert_end(Node **head, int rollnumber, int src, int dst, double gentime)
{
    struct Node *new_node = NULL;
    struct Node *last = NULL;

    new_node = (struct Node *) malloc(sizeof(struct Node));

    if (new_node == NULL) {
        printf("Failed to insert element. Out of memory");
        return;
    }

    new_node->rollnumber = rollnumber;
    new_node->src = src;
    new_node->dst = dst;
    new_node->gentime = gentime;
    new_node->next = NULL;

    if (*head == NULL) {
        *head = new_node;
        return;
    }
    last = *head;
    while (last->next)
        last = last->next;
    last->next = new_node;
}

void
output(Node *head)
{
    for (Node *current = head; current != NULL; current = current->next) {
        // printf("%d ", current->data);
        printf("Roll Number:%2d\t", current->rollnumber);
        printf("src:%2d\t", current->src);
        printf("dest:%2d\t", current->dst);
        printf("gentime:%0.1f\n", current->gentime);
    }
}

void
display(Node **set, int i)
{
    output(set[i]);
    putchar('\n');
}

int
remove_node_in_list(Node **set, size_t pos)
{
    int success = set[pos] != NULL;

    if (success) {
        Node *tmp = set[pos];

        set[pos] = set[pos]->next;
        free(tmp);
    }

    return success;
}

#define N   10

int
main(void)
{
    char line[MAX_LINE_LENGTH] = { 0 };
    int src, dst;
    int rollnumber;
    double gentime;
    int stations = 0;
    Node *link[N] = { 0 };
    int i = 1;
    static unsigned long pos[N] = { 0 };
    FILE *file;
    bool intention[N];
    double Time = 12.0;
    int lower = 0,
        upper = 9,
        count = 1;

    srand(time(0));

    // the time units checking them per one like: 0-1,1-2 etc..
    for (Time = 1.0; Time < 50.0; Time = Time + 1.0) {
        // because I have N text files
        for (i = 0; i < N; i++) {
            char to_open[32];

            snprintf(to_open, 32, "fptg_%d.txt", i + 1);
            printf("\n\nFILE/%d: %s Position:%ld (Time: %g)\n",
                i,to_open,pos[i],Time);

            if ((file = fopen(to_open, "r")) == NULL) {
                perror(to_open);
                break;
            }

            fseek(file, pos[i], SEEK_CUR);
#if 0
            fgets(line, sizeof(line), file);
#else
            char *cp = fgets(line, sizeof(line), file);
            fclose(file);
            if (cp == NULL)
                continue;
#endif

            int retval = sscanf(line, "%d %d %d %lf",
                &rollnumber, &src, &dst, &gentime);
            printf("%s", line);
            printf("Return value=%d\n", retval);
            printf("gentime=%.1f\n", gentime);

#if 0
            pos[i] = ftell(file);
#endif

            if (Time < gentime && gentime < Time + 1.0) {
#if 1
                pos[i] = ftell(file);
#endif
                insert_end(&link[i], rollnumber, src, dst, gentime);
                printf("Time=%0.1f\n", Time);

                for (int j = 0; j < count; j++) {
                    int num = (rand() % (upper - lower + 1)) + lower;

                    printf("Random number:%d\n", num);

                    if (num == 1 || num == 6 || num == 8) {
                        intention[i] = true;
                        printf("ok\n");
                        stations++;
                        printf("stations=%d\n", stations);
                        printf("intention[%d]=%d\n", i, intention[i]);
                        double offtime = gentime + 12.0;

                        printf("channel off until: %.1f starting from: %.1f\n\n", offtime, gentime);
                    }
                    else {
                        intention[i] = false;
                        printf("intention[%d]=%d\n", i, intention[i]);
                    }
                }
            }
            else {
                printf("Not in the list\n");
            }
        }
    }

    if (stations == 1) {
        for (int i = 0; i < N; i++) {
            printf("intention[%d]=%d\n", i, intention[i]);
            if (intention[i] == true) {
                printf("link[%d]:\n", i);
                display(link, i);
                printf("i=%d\n", i);
                remove_node_in_list(link, i);
                printf("NEW:\n");
                display(link, i);
            }
        }
    }

    stations = 0;

    return 0;
}

I saw and did all the changes and thank you a lot! Do you think I should use rewind at any position in my code? Would that be helpful? – wajaap

没有。 rewind [有效]只是 fseek

的包装

正如我上面提到的,我一次读入了所有文件的所有行。然后,对列表进行排序。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>

#define MAX_LINE_LENGTH 105

typedef struct Node {
    int rollnumber, src, dst;
    double gentime;
    struct Node *next;
} Node;

void
insert_end(Node **head, int rollnumber, int src, int dst, double gentime)
{
    struct Node *new_node;
    struct Node *last = NULL;

    new_node = malloc(sizeof(*new_node));

    if (new_node == NULL) {
        printf("Failed to insert element. Out of memory");
        return;
    }

    new_node->rollnumber = rollnumber;
    new_node->src = src;
    new_node->dst = dst;
    new_node->gentime = gentime;
    new_node->next = NULL;

    if (*head == NULL) {
        *head = new_node;
        return;
    }

    last = *head;
    while (last->next)
        last = last->next;

    last->next = new_node;
}

void
output(Node *head)
{
    for (Node *current = head; current != NULL; current = current->next) {
        // printf("%d ", current->data);
        printf("Roll Number:%2d\t", current->rollnumber);
        printf("src:%2d\t", current->src);
        printf("dest:%2d\t", current->dst);
        printf("gentime:%0.1f\n", current->gentime);
    }
}

void
display(Node **set, int i)
{
    output(set[i]);
    putchar('\n');
}

int
remove_node_in_list(Node **set, size_t pos)
{
    int success = set[pos] != NULL;

    if (success) {
        Node *tmp = set[pos];

        set[pos] = set[pos]->next;
        free(tmp);
    }

    return success;
}

typedef struct {
    Node *ptr;
} sort_t;

int
sort_cmp(const void *vlhs,const void *vrhs)
{
    const sort_t *plhs = vlhs;
    const Node *lhs = plhs->ptr;
    const sort_t *prhs = vrhs;
    const Node *rhs = prhs->ptr;
    int cmp;

    do {
        cmp = -1;
        if (lhs->gentime < rhs->gentime)
            break;

        cmp = 1;
        if (lhs->gentime > rhs->gentime)
            break;

        cmp = 0;
    } while (0);

    return cmp;
}

void
sort_list(Node **head)
{
    size_t count;
    size_t idx;
    Node *cur;
    Node *prev;

    // get count of list
    count = 0;
    for (cur = *head;  cur != NULL;  cur = cur->next)
        ++count;

    // get flat array of node pointers
    sort_t *base = malloc(sizeof(*base) * count);
    sort_t *arr;

    // fill the array
    arr = base;
    for (cur = *head;  cur != NULL;  cur = cur->next, ++arr)
        arr->ptr = cur;

    qsort(base,count,sizeof(*base),sort_cmp);

    // repopulate linked list from array
    prev = NULL;
    arr = base;
    for (idx = 0;  idx < count;  ++idx, ++arr) {
        cur = arr->ptr;
        cur->next = NULL;

        if (prev != NULL)
            prev->next = cur;
        else
            *head = cur;

        prev = cur;
    }

    free(base);
}

#define N   10

#define TMIN    1.0
#define TMAX    50.0

int
main(void)
{
    char line[MAX_LINE_LENGTH] = { 0 };
    int src, dst;
    int rollnumber;
    double gentime;
    int stations = 0;
    Node *link[N] = { 0 };
    int i = 1;
    FILE *file;
    char *cp;
    bool intention[N] = { 0 };
    double Time = 12.0;
    int lower = 0,
        upper = 9,
        count = 1;

    srand(time(0));

    // because I have N text files
    for (i = 0; i < N; i++) {
        char to_open[32];

        snprintf(to_open, 32, "fptg_%d.txt", i + 1);
        printf("\nFILE/%d: %s\n",i,to_open);

        if ((file = fopen(to_open, "r")) == NULL) {
            perror(to_open);
            break;
        }

        while (1) {
            cp = fgets(line, sizeof(line), file);
            if (cp == NULL)
                break;

            int retval = sscanf(line, "%d %d %d %lf",
                &rollnumber, &src, &dst, &gentime);
            printf("%s", line);
            printf("Return value=%d\n", retval);
            printf("gentime=%.1f\n", gentime);

            if ((gentime >= TMIN) && (gentime < TMAX))
                insert_end(&link[i], rollnumber, src, dst, gentime);
            else
                printf("Not in the list\n");
        }

        fclose(file);
    }

    // sort all lists
    for (i = 0; i < N; i++)
        sort_list(&link[i]);

    // the time units checking them per one like: 0-1,1-2 etc..
    for (Time = TMIN; Time < TMAX; Time = Time + 1.0) {
        for (int j = 0; j < count; j++) {
            int num = (rand() % (upper - lower + 1)) + lower;

            printf("Random number:%d\n", num);

            if (num == 1 || num == 6 || num == 8) {
                intention[i] = true;
                printf("ok\n");
                stations++;
                printf("stations=%d\n", stations);
                printf("intention[%d]=%d\n", i, intention[i]);
                double offtime = gentime + 12.0;

                printf("channel off until: %.1f starting from: %.1f\n\n",
                    offtime, gentime);
            }
            else {
                intention[i] = false;
                printf("intention[%d]=%d\n", i, intention[i]);
            }
        }
    }

    if (stations == 1) {
        for (int i = 0; i < N; i++) {
            printf("intention[%d]=%d\n", i, intention[i]);
            if (intention[i] == true) {
                printf("link[%d]:\n", i);
                display(link, i);
                printf("i=%d\n", i);
                remove_node_in_list(link, i);
                printf("NEW:\n");
                display(link, i);
            }
        }
    }

    stations = 0;

    return 0;
}

更新:

Very insightfull and helpful, thank you! Why did you put #if 0, #if 1 etc? – wajaap

我这样做是为了 tutorial/documentation 目的。我使用 cpp 条件来表示旧代码与新代码(例如):

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

这比使用 /**/

注释掉旧代码更不容易出错

在这里,IMO,它让 OP 更容易看到在 line-by-line 基础上发生了什么变化。

我也在生产代码中这样做,如果我有“工作”代码,但想尝试一些新的[大概faster/better]代码,但是新的代码是实验性的,可能无法正常工作。

如果新代码工作[但应该工作],它提供了一种恢复工作代码的简单方法。我可以处理其他事情,当我想办法让它工作时,再回到更好的代码。

我通常将代码 [(e.g.) 提交到 git] 并保留条件。然后,我手动编辑 out 已删除的代码并提交再次。这个文件 what/why/how 我到达了最终状态。

请注意,在我的第二个代码示例中 [使用节点排序],我删除了 cpp 条件以显示 clean/final 代码。