Member Avatar for Mouche

Hello, I'm working on a project in C to practice before I take a class this fall that requires C. I decided on making a task list. First, I'm starting with a cli interface, and then I hope to move it to GTK+ since that would look better and I have PyGTK experience.

Anyways, I just finished a function that formats the due date for a task. I want it in MM/DD/YYYY format so the date strings are all the same width (for aesthetics).

So I have a date struct like this:

typedef struct date
{
  int month;
  int day;
  int year;
} date;

I have written a date_to_string() function that takes a pointer to a date struct and returns a char pointer to a string of the date in MM/DD/YYYY format. I'm a bit rusty with char arrays/pointers, so I'm not sure if this is a good way to do it.

/* Convert a date to a string in the format MM/DD/YYYY */
char *date_to_string_std(date *d)
{
    char *date_string = (char *) malloc(11*sizeof(char)); /* 11 characters for MM/DD/YYYY + \0 */
    char month_string[3];
    char day_string[3];

    /* Put month int and day int into char arrays of length 3*/
    sprintf(month_string, "%d", d->month);
    sprintf(day_string, "%d", d->day);
    
    /* If the month < 10, add a 0 in front of the month number
     * to fit MM format */
    if (strlen(month_string) == 1)
    {
        month_string[2] = '\0';
        month_string[1] = month_string[0];
        month_string[0] = '0';
    }
    
    /* If the day < 10, add a 0 in front of the day number
     * to fit DD format */
    if (strlen(day_string) == 1)
    {
        day_string[2] = '\0';
        day_string[1] = day_string[0];
        day_string[0] = '0';
    }

    /* Create a string of the date in MM/DD/YYYY format */
    sprintf(date_string, "%s/%s/%d", month_string, day_string, d->year);

    return date_string;    
}

I would really appreciate any feedback about how I implemented this function. One problem is that I don't free the malloc'd memory given to date_string. But I can't add a

free(date_string);

before the end of the function because the function returns that value. It seems like I should have a local variable for date_string but I'm not sure how that works with returning a local variable.

Also, is there a better way to add the '0' character in front of a month or day number that is only one digit?

Thanks for any suggestions. I'm enjoying figuring things out in C. Python makes it way too easy. :P

C has functions to print up, or help you print up dates, in a variety of formats.

So free the memory, afterward. As long as you have the right address, what function you free the memory in, won't matter to the OS.

There's no need for the cast you have on the pointer from malloc(). C does that for you correctly, in this case.

for numbers in a field two columns wide, with 0's padding in front as needed:

printf("%02d", number);
commented: Quick and helpful reply with a simple solution +4
Member Avatar for Mouche

Thanks for the quick response. And wow, that's a simple solution.

Here's my solution with your method applied:

char *date_to_string_std(date *d, char *date_string)
{
    date_string = malloc(11*sizeof(char)); /* 11 characters for MM/DD/YYYY + \0 */
    
    sprintf(date_string, "%02d/%02d/%d", d->month, d->day, d->year);

    return date_string;
}

And it runs in this function:

/* Print out the task list in a To-Do list format */
void print_task_list(tasklist *t)
{
    char *temp_date_string;
    task *current = t->first;
    printf("To-Do:\n");
    while (current != NULL)
    {
        temp_date_string = date_to_string_std(&current->due_date, temp_date_string);
        if(temp_date_string != NULL)
        {
            printf(" [ ] %s\t%s\n", current->name,temp_date_string);
            free(temp_date_string);
        }
        else
        {
            printf("Error formatting date");
        }
        current = current->next;
    }
    printf("\n");
}

Seeing task struct may be helpful to understand the above code:

typedef struct task task;
struct task
{
  char name[50];
  boolean completed; /* enum created in boolean.h */
  date due_date;

  task *next;
};

Is this an adequate way to handle this date_to_string function? I'm feeding it a temporary char pointer from the calling function and freeing the allocated memory if the malloc doesn't fail (aka when the returned string isn't NULL).

Any suggestions as to how to clean this up or is this a good way to do it?

As a practical matter, I'd use C date functions, but as an exercise, it looks OK. I'd use a static int variable first_flag to malloc the array just one time, and then not free it until the loop was all through.

I'd say you've got your C basics pretty well working, here. ;)

Member Avatar for Mouche

Ok, thanks Adak. Reviewing C basics was the point. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.