3

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.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Tyler
  • 4,679
  • 12
  • 41
  • 60

4 Answers4

2

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;
Serafina Brocious
  • 30,433
  • 12
  • 89
  • 114
2

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
  • 854,327
  • 234
  • 1,573
  • 1,953
2

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
  • 74
  • 3
  • 11
  • Thanks for clarifying. I was getting really frustrated. – Tyler Jan 28 '09 at 03:45
  • For anyone just now coming across this, daytab[0] and daytab[1] should be switched in the ternary statement since daytab[0] is the char array for when it isn't a leap year. – velocirabbit Jul 06 '16 at 23:27
0

Old thread, but I actually have a solution that doesn't use indexing, not even [0]. So instead of writing

day += daytab[leap][i];

write

day += *(*(daytab+leap)+i);
hga
  • 1
  • 1