strcpy crashing program

Viewed 98

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

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