2

I creating a program which imports date and time entries (eg. 29/11/2021-15:33:56) from a file and stores them in an array. We are asked to then create a function (timeStampToSeconds) to convert these to long ints. Once we have the long ints we have to compare the entries as seconds and use a selection sort to place these from earliest to latest.

I have created the below program to do this, but when I get to the strcpy function the program crashes.

I don't see how I am using this incorrectly but certainly seem to be missing something. If anyone has any advice on how to use this to swap my corresponding char array entries, it would be appreciated. It may be that I need to use an entirely different function for this purpose.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

long int timeStampToSeconds(char array[]);

int main(void) {
    char array[50][20];
    long int intarray[50];

    char input[12], filename[] = "Timestamps", outputfile[40], file_ext[] = ".dat", temp[20];
    int i = 0, n = 0, j, x = 0, y = 0, o = 0, f = 1, result = 1;
    double datetime = 0;

    while (result != 0) {
        printf("\nPlease enter the names of the required Input file: \n");
        scanf("%10s", input);

        /* compare input & filename */
        result = strcmp(input, filename);
        
        if (result == 0) {
            printf("Input accepted!\n");
        } else
            printf("File name not found.Please try again!\n");
    }

    printf("Please enter the name of the sorted Output file to be created: \n");
    scanf("%s", &outputfile);
    strncat(&outputfile, &file_ext, 4);  /* appends file extension characters to outputfile variable characters */

    FILE *Ptr = NULL;
    FILE *cfPtr = (char *)malloc(100 * sizeof(char));

    if ((cfPtr = fopen("Timestamps.dat", "r")) == NULL) {
        printf("File could not be opened\n");
    }

    while (!feof(cfPtr)) {
        for (i = 0; i < 50; ++i) {
            for (j = 0; j < 20; ++j) {
                array[x][j] = fgetc(cfPtr);
                y++;
            }
            x++;
        }
    }

    fclose(cfPtr);

    for (int p = 0; p < 50; p++) { // loop to control number of passes
        int l;
        for (l = 0; l < 50; ++l, ++f) {   /* loop to control number of comparisons per pass */
            n = timeStampToSeconds(array[l]); /*convert to long int to compare 2 strings*/
            o = timeStampToSeconds(array[f]);

            if(n > o) {
                strcpy(temp, array[f]); /* selection sort algorithm */
                strcpy(array[f], array[l]);
                strcpy(array[l], temp);
            }
        }
    }

    if ((Ptr = fopen(outputfile, "w+")) == NULL) {
        printf("File could not be opened\n");
    }

    for (int l = 0; l < 50; ++l) {
        fprintf(Ptr, "%ld\n", intarray[l]);
    }
    fclose(Ptr);

    return 0;
}

long int timeStampToSeconds(char array[]) {
    
    long int day, mon, yr, hr, min, sec;
    long int totaldays, totalmonths, total;
    
    day = atol(array);
    mon = atol(array + 3);
    yr = atol(array + 6);
    hr = atol(array + 11);
    min = atol(array + 14);
    sec = atol(array + 17);

    hr = hr * (60 * 60); /*converts hours to seconds*/
    min = min * 60;

    day = day * 86400;
    mon = mon * 2628000;
    yr = (yr - 2000) * 31557600; /* total seconds elapsed in yrs from 2020 */

    totaldays = hr + min + sec; /* total seconds from hr/min/sec */
    totalmonths = day + mon + yr; /* total seconds from dd/mm/yy */

    total = totaldays + totalmonths;

    return total;
}
Cik02
  • 59
  • 6
  • `while (n > o) ` how do you expect that loop to end considering neither `n` nor `o` are changed in the loop? – kaylum Jan 06 '22 at 20:31
  • 1
    [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – Eugene Sh. Jan 06 '22 at 20:36
  • You are changing your code in the question on the fly, which makes it look like it is not your actual code. – Eugene Sh. Jan 06 '22 at 20:37
  • My mistake. I have corrected the incorrect while loop to an if statement. It was that originally but i cut it out and pasted in the incorrect word while creating my question. Re-tried my code again with the if statement and getting the same error unfortunately. – Cik02 Jan 06 '22 at 20:37
  • Well that's just one error. There are more. For example, your `strcpy` loop is flawed. `for (int p = 0; p < 50; p++) { // loop to control number of passes` always processes all the array entries but not all of the entries will have been filled with valid strings. So the `strcpy` calls can easily overrun the array buffers due to unitialised/garbage values in them. – kaylum Jan 06 '22 at 20:41
  • 3
    Not to pour a bucket of salt on the wound, but `cfPtr = fopen("Timestamps.dat", "r")` also immediately leaks the totally worthless `malloc` just one line earlier in the program. C isn't Java. You don't have to malloc/new *everything*. – WhozCraig Jan 06 '22 at 20:43

1 Answers1

2

You read 20 bytes into the arrays array[x] but do not set a null terminator at the end, hence they are not proper C strings and strcpy likely copies much more than 20 bytes into tmp, invoking undefined behavior.

There are other problems:

  • the reading loop uses feof() incorrectly.
  • the timeStampToSeconds function does not handle actual month lengths and leap years.

Here is a modified version:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

long int timeStampToSeconds(const char array[]);

int main(void) {
    char array[50][21];
    long int intarray[50];
    char input[12];
    char filename[] = "Timestamps";
    char outputfile[40];
    char file_ext[] = ".dat";
    char temp[20];
    int i = 0, n = 0, j, x = 0, y = 0, o = 0, f = 1, result = 1;
    double datetime = 0;

    while (result != 0) {
        printf("\nPlease enter the name of the required Input file: \n");
        if (scanf("%11s", input) != 1)
            return 1;

        /* compare input & filename */
        result = strcmp(input, filename);
        
        if (result == 0) {
            printf("Input accepted!\n");
        } else {
            printf("File name not found.Please try again!\n");
        }
    }

    printf("Please enter the name of the sorted Output file to be created: \n");
    scanf("%15s", &outputfile);
    strcat(outputfile, file_ext);  /* append file extension */

    FILE *Ptr;
    FILE *cfPtr;

    if ((cfPtr = fopen("Timestamps.dat", "r")) == NULL) {
        printf("File could not be opened\n");
        return 1;
    }

    for (x = 0; x < 50; x++) {
        if (fread(array[x], 1, 20, cfPtr) != 20)
            break;
        array[x][20] = '\0'
    }
    fclose(cfPtr);

    for (int p = 0; p < x; p++) { // loop to control number of passes
        int l;
        for (l = 0; l < x; ++l, ++f) {   /* loop to control number of comparisons per pass */
            n = timeStampToSeconds(array[l]); /*convert to long int to compare 2 strings*/
            o = timeStampToSeconds(array[f]);

            if (n > o) {
                strcpy(temp, array[f]); /* selection sort algorithm */
                strcpy(array[f], array[l]);
                strcpy(array[l], temp);
            }
        }
    }

    if ((Ptr = fopen(outputfile, "w+")) == NULL) {
        printf("File could not be opened\n");
        return 1;
    }

    for (int l = 0; l < x; ++l) {
        fprintf(Ptr, "%ld: %s", timeStampToSeconds(array[l]), array[l]);
    }
    fclose(Ptr);

    return 0;
}

long int timeStampToSeconds(const char array[]) {
    static const int mdays[12] = {
        31,
        31+28,
        31+28+31,
        31+28+31+30,
        31+28+31+30+31,
        31+28+31+30+31+30,
        31+28+31+30+31+30+31,
        31+28+31+30+31+30+31+31,
        31+28+31+30+31+30+31+31+31,
        31+28+31+30+31+30+31+31+31+30,
        31+28+31+30+31+30+31+31+31+30+31,
        31+28+31+30+31+30+31+31+31+30+31+30,
    };
    int day, mon, yr, hr, min, sec;
    
    /* parse 29/11/2021-15:33:56 format */
    if (sscanf("%d/%d/%d-%d:%d:%d", &day, &mon, &yr, &hr, &min, &sec) != 6) {
        /* invalid format */
        return -1;
    }

    /* compute the number of seconds since midnight */    
    sec += min * 60 + hr * 3600;

    /* compute the number of days since Jan 1st, 2000 */
    day += (yr - 2000) / 4 * (366 + 365 + 365 + 365);
    yr %= 4;
    day += yr * 365;
    if (yr > 0 || mon > 2)
        day += 1;
    day += mdays[mon - 1];
​   return sec + day * 86400L;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Thanks everyone for the comments and @chqrlie for the above modifications. I realised that in my code the error is coming from the last string in my array. When it saves, it saves it as: 20/03/2004-19:19:59ÌÌ. Every other string save as just the date and time with the \n at the end. I'm assuming the strcpy then can read or copy this. This is the case with my code and the modified code. Any suggestions on what i might be doing for that to happen? – Cik02 Jan 06 '22 at 23:03
  • @CiaranKiernan: difficult to tell without the code that produces the text file. – chqrlie Jan 07 '22 at 15:45
  • Thanks everyone for the help. I realised after that the errors were appearing that reading in the file contents with fgets and then appending an end of line (\n) on the last string of data fixed the issue for me. – Cik02 Jan 10 '22 at 23:03