8

I am just wondering if there is a way to make an array of pointers that point to the first column of each row in a multidimensional array of integers. As an example, please look at the following code:

#include <stdio.h>

int day_of_year(int year, int month, int day);

main()
{
    printf("Day of year = %d\n", day_of_year(2016, 2, 1));
    return 0;
}

static int 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}
};

int day_of_year(int year, int month, int day)
{
    int leap;
    int *nlptr = &daytab[0][0];
    int *lpptr = &daytab[1][0];
    int *nlend = nlptr + month;
    int *lpend = lpptr + month;

    leap = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
    if (leap)
        for (; lpptr < lpend; lpptr++)
            day += *lpptr;
    else
        for (; nlptr < nlend; nlptr++)
            day += *nlptr;
    return day;
}

When I write like this below:

int *p[2];
*p[0] = daytab[0][0];
*p[1] = daytab[1][0];

I get an error like this:

Error: Array must have at least one element
Error: Variable 'p' is initialized more than once
Error: { expected
Error: Variable 'p' is initialized more than once
Error: { expected
***5 errors in Compile***

I changed it like this:

int *p[2];
p[0] = &daytab[0][0];
p[1] = &daytab[1][0];

I still get the same error.

I know we can make an array of pointers to character strings as in the following:

char *str[] = {
    "One", "Two", "Three",
    "Four", "Five", "Six",
    "Seven", "Eight", "Nine"
}

How do we do that for arrays of integers?

alk
  • 69,737
  • 10
  • 105
  • 255
W. Zhu
  • 755
  • 6
  • 16
  • "*It does not work*" is the more or less worth error report one can give. Please be more precise on the error, warning, malfunction you get, observe! – alk May 15 '16 at 08:43
  • 2
    First example: big chance to cause Segmentation Fault by dereferencing invalid pointer Second example: Would you explain what you mean by "doesn't work"? – MikeCAT May 15 '16 at 08:43
  • 1
    The code as shown (using the 2nd approach) looks good to me. – alk May 15 '16 at 08:51
  • Probably, using your 2nd approach, you are using the array wrongly in following (not posted) code. – LPs May 15 '16 at 08:56
  • 1
    "*I still get the same error.*" I doubt this. The code as shown compiles cleanly and runs correct. With `int * p[2];` `p[0]` and `p[1]` both evaluate to an `int *`, which is the same as `int * nlptr; int * lpptr`. – alk May 15 '16 at 09:04
  • What compiler do you use? Could you post compiler flags? – LookAheadAtYourTypes May 15 '16 at 09:07
  • I found a horrible way of checking leap years contrary to your simple method : `(year%4==0)?(year%100!=0)?1:(year%400==0)?1:0:0;` Ironically both are not very readable for a beginner. :P – sjsam May 15 '16 at 09:13
  • @tomekpe Turbo C++ Version 3.00 Copyright (c) 1992 Borland International. I use tcc -I..\include -L..\lib exp2.c. – W. Zhu May 15 '16 at 09:46
  • 4
    "*Turbo C/C++*" Stay away from this completely outdate compiler! Under Windows go for Cygwin and GCC for an IX'ish like environment or use MinGW for Windows-API programming. Also there is a free VC version around. – alk May 15 '16 at 09:54

3 Answers3

2

Your code should work as charm:

int *p[2];
p[0] = &daytab[0][0];
p[1] = &daytab[1][0];

printf("%d \n", p[0][2]); // shows: 28
printf("%d \n", p[1][2]); // shows: 29

This also works:

int *p[2] = { &daytab[0][0],&daytab[1][0] };
LookAheadAtYourTypes
  • 1,629
  • 2
  • 20
  • 35
  • The former code, when compiled, keeps giving me the errors that I mentioned above, though I think it should not. But the latter works for me, and it's made the program more compact, eliminating the need for if-else. Thank you. – W. Zhu May 15 '16 at 09:21
  • The latter code works when I compile it as cpp. But when I compile it as c, I get the error `Illegal initialization in function day_of_year` at the line `int *pe[2] = {p[0] + month, p[1] + month};`. – W. Zhu May 15 '16 at 09:50
  • 1
    As already mentioned by Alk, please upgrade your compiler as soon as possible!. It was obsolete in 90's and it will for sure give you much of a headache. – LookAheadAtYourTypes May 15 '16 at 15:30
1

If it's about changing the definition of daytab to go like the 3rd example you might like to use this:

int * daytab[] = {
  (int[]){0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  (int[]){0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

instead.

Or to stay save and mark the end of the array using a sentinel do:

int * daytab[] = {
  (int[]){0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  (int[]){0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  NULL
};

Or^2 to stay even saver marking also the inner array ends:

int * daytab[] = {
  (int[]){0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1},
  (int[]){0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1},
  NULL
};

Please note that the compounds ((Type){Initialiser}) used here are available only from C99 on.

alk
  • 69,737
  • 10
  • 105
  • 255
1

Use like below

int *p[2]; p[0] = daytab[0]; p[1] = daytab[1];

Ashish
  • 153
  • 1
  • 1
  • 11