tags:

views:

590

answers:

4

Exercise (5-9): Rewrite the routines day_of_year with pointers instead of indexing.

static char daytab[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

/* day_of_year: set day of year from month and day */
int day_of_year(int year, int month, int day)
{
    int i, leap;

    leap = (year%4 == 0) && (year%100 != 0) || (year%400 == 0);
    for (i = 1; i < month; i++)
    {
        day += daytab[leap][i];
    }

    return day;
}

I may just be tired and not thinking, but how does one actually create a multidimensional array with pointers?

I could probably figure out the rest of the function, but I can't get the syntax right.

Thanks!

+2  A: 

There are two ways of handling this:

The first is to emulate the way that C actually handles multidimensional arrays, which is to say not at all. char[4][4] is really just syntactical sugar around char[16]. You can create a pointer to an array of 16 bytes (in this case) and you've got the same thing.

The other is to create a pointer to a pointer. Following the previous example:

char **foo = malloc(sizeof(char *) * 4);
for(int i = 0; i < 4; ++i)
    foo[i] = malloc(sizeof(char) * 4);
foo[0][0] = bar;
Cody Brocious
A: 

I'm not sure since I don't have K&R, but if that's how it is worded then I would think the point of the exercise to access the daytab array using pointers, not indexes.

days += *(daytab + (leap * 13) + i);
dreamlax
+2  A: 

The following complete program will do what you desire. I've converted your array into a char pointer (string) and interspersed the leap year values. I've also removed the dummy entries and adjusted the loop.

The test program lacks serious error checking so don't expect it to work with dodgy arguments.

#include <stdio.h>

static char *daytab =
    "\x1f\x1f\x1c\x1d\x1f\x1f"
    "\x1e\x1e\x1f\x1f\x1e\x1e"
    "\x1f\x1f\x1f\x1f\x1e\x1e"
    "\x1f\x1f\x1e\x1e\x1f\x1f";

/* day_of_year: set day of year from month and day */
int day_of_year(int year, int month, int day) {
    int i, leap;

    leap = (year%4 == 0) && (year%100 != 0) || (year%400 == 0);
    for (i = 0; i < month-1; i++) {
        day += *(daytab+i*2+leap);
    }

    return day;
}

int main (int argc, char *argv[]) {
    if (argc != 4) {
        printf ("Usage: blah yy mm dd\n");
        return 1;
    }
    printf ("%4.4s/%2.2s/%2.2s -> %04d/%02d/%02d -> %d\n",
        argv[1], argv[2], argv[3],
        atoi (argv[1]), atoi (argv[2]), atoi (argv[3]),
        day_of_year (atoi(argv[1]),atoi(argv[2]),atoi(argv[3])));
    return 0;
}
paxdiablo
Thanks for taking the time to code that out!That is really helpful.
Tyler
+3  A: 

You're just asked to modify the day_of_year routine, not the daytab declaration. I would leave that array as-is, and modify day_of_year as follows:

/* day_of_year: set day of year from month and day */
int day_of_year(int year, int month, int day)
{
    char* p = (year%4 == 0) && (year%100 != 0) || (year%400 == 0) ? 
        daytab[0] : daytab[1];

    p++;
    for (i = 1; i < month; i++, p++)
    {
        day += *p;
    }

    return day;
}

If you want to the declaration of p to be shorter, you can do this:

    char* p = daytab[(year%4 == 0) && (year%100 != 0) || (year%400 == 0)];

If you still want to remove that access, too:

    char* p = *(daytab + ((year%4 == 0) && (year%100 != 0) || (year%400 == 0)));

One might argue that it looks ugly, but hey, that's what you get with pointers.

Remoun
Thanks for clarifying. I was getting really frustrated.
Tyler