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

Time:01-22

I have 10 text files with some packets which are represented by rollnumber, source, destination and generation time, those are also in a struct :

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

I want to open each file in every time unit and be able to check if any packet was generated. This means, that the generation time must be less than the Time unit I am in. For example, in the time unit 0-1, I must find a packet with 0<generation time<1. So, if this happens, that packet enters a list with the insert function:

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;
}

My code is below:

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
                    }

                }    
            }
                
        }
}

My question is how will I be able if a packet does not insert in to the list to check the same packet in the next time unit? If a packet is inserting in the list, reading the next one is correct for what I want to do. But if a packet does not insert in to the list I do not want to go to the next one in the next time unit. Any help will be appreciated, thanks in advance!

Minimal Reproducible Example:

#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:-\t", current->rollnumber);
        printf("src:-\t", current->src);
        printf("dest:-\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;
}

The result I get for the first &second time unit is:

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

and so it goes for the next time units. For example for the fptg_4.txt, in the first time unit it checks the first line of it: 1 4 18 0.2 but in the next time unit it goes to the next line: 2 4 12 12.8, even though it should have checked the same line because that packet represented by the previous line did not enter the list. So, my question is how is this possible?

CodePudding user response:

From my top comments ...

  1. Your MRE wouldn't compile because of an extra } [fixed with my edit].

  2. static unsigned long pos[] = { 0 }; is wrong (it has UB--undefined behavior because it is too short). It should be: static unsigned long pos[11] = { 0 };

  3. You're indexing into arrays starting from 1. This means that the first array element is never used and all arrays have to be one larger (e.g. int array[11]; instead of int array[10]; You're probably better off with: for (i = 0; i < 10; i ) and then: snprintf(to_open, 32, "fptg_%d.txt", i 1);

  4. Using fseek/ftell is problematic because the input files are variable length text. What are you trying to do? The only think I can think of is that you're trying to make your list sorted by time?

  5. You are always setting pos[i] to the ftell value even if the record is not stored. Move the pos[i] = ftell(file); line under/after the if (Time < gentime && gentime < Time 1.0) { line. (i.e. just above the insert_end call)

  6. After doing that last change, the position issue is fixed. Instead of 192 output lines, I'm getting 3479 lines.

  7. But, honestly, while I'm not sure what effect you're trying to get with the intention/stations code, rereading the files many times isn't the best way.

  8. I'd read each file once, add it to the list if (e.g.) (gentime >= 1.0) && (gentime <= 50.0) and then after all files are read, sort the linked list based on the stored gentime.

  9. It seems the intentions code can be done outside/after the read loops because they don't depend of data from one another.


Additional bugs:

  1. You are never doing fclose so you have a ton of dangling file stream pointers.
  2. You never check the return value of fgets, so you don't handle EOF properly.
  3. You call sscanf twice. Once to decode the line and another just to print the return value of sscanf
  4. Don't cast the return value of malloc. See: Do I cast the result of malloc?

Here is the modified/corrected code:

#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:-\t", current->rollnumber);
        printf("src:-\t", current->src);
        printf("dest:-\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

No. rewind is [effectively] just a wrapper around fseek

As I mentioned above, I'd read in all lines from all files at once. Then, sort the lists.

#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:-\t", current->rollnumber);
        printf("src:-\t", current->src);
        printf("dest:-\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;
}

UPDATE:

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

I do that for tutorial/documentation purposes. I use cpp conditionals to denote old vs. new code (e.g.):

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

#if 1
// new code
#endif

This is less error prone than commenting out old code with /* and */

Here, IMO, it makes it easier for an OP to see what was changed on a line-by-line basis.

I also do this in production code, if I have "working" code, but want to try some new [presumably faster/better] code, but the new code is experimental and may not work.

It provides an easy way to revert to the working code if the new code does not work [but should work]. I can work on something else and come back to the better code when I figure out to make it work.

I usually commit the code [(e.g.) to git] with the conditionals left in. Then, I hand edit out the nop'ed code and commit again. This documents what/why/how I got to the final state.

Notice that in my second code example [with the node sorting], I removed the cpp conditionals to show the clean/final code.

  •  Tags:  
  • Related