2

As in the question at "Excess elements of scalar initializer for pointer to array of ints", I too am working on Ex. 5–9 in K&R, trying to convert

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

into

static char *daytab[] = {
    {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}
};

and am getting the errors described there. However, the accepted answer of

static char arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
static char (*ptr)[3] = NULL;

ptr = arr;

just gives me another error at ptr = arr of

error: data definition has no type or storage class

Can anyone help?

Also, why is it legal to use an array of pointers to char arrays, such as

static char *name[] = {
    "Illegal month",
    "January", "February", "March",
    "April", "May", "June",
    "July", "August", "September",
    "October", "Novemer", "December"
};

but not int arrays?

Community
  • 1
  • 1
Pjj56
  • 83
  • 1
  • 8

1 Answers1

0

I am assuming that your code looks like (as error message by gcc is exactly the same):

#include <stdio.h>

static char arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
static char (*ptr)[3] = NULL;
ptr = arr;

int main(void)
{       
    printf("%d\n", ptr[0][0]);

    return 0;
}

This is indeed invalid, as ptr = arr; assignment is placed outside of any function. The syntax rules of C language allow only to place it inside, like here:

#include <stdio.h>

int main(void)
{
    static char arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
    static char (*ptr)[3] = NULL;
    ptr = arr;

    printf("%d\n", ptr[0][0]);

    return 0;
}

There is also fundamental difference in meaning of static keyword for both those examples. The former affects linkage, and the latter storage duration of particular object, that is represented by identifier.

For your second question, you may simplify it into more basic form:

Why the following is legal:

char *name = "January";

while this is not:

int *name = "January";

?

Here (as well as in previous form in your question), "January" is interpreted not as array initializer, but as string literal.

These literals are read-only (any attempt to modify them results into undefined behavior) objects of type char[n], where is n equal to number of characters between " delimiters (with special handling of escape sequences), plus one for null character (represented in common as '\0'). The value of n is always known in compile-time for string literals. They have static storage duration, so you can think of them like existing objects, that are already present, when the is program is being executed.

The pointer to int is incompatible with char[n] array, so you cannot assign string literal to int *.

To be honest, yes you can "force" it, by explicit cast, like here:

int *name = (int *) "January";

but any attempt to read from such pointer would violate strict aliasing rule, that results into UB.

Community
  • 1
  • 1
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • Thank you very much for the answer. However, for the second part, I was more wondering why `char *name = "January";` is legal, but `char *num = {1, 2, 3};` is not? Is the string literal treated as an existing array? – Pjj56 Feb 08 '15 at 11:52
  • Ah, that is what I was wondering, that the string literal is treated as a pre-existing array. Thanks again! – Pjj56 Feb 08 '15 at 11:56
  • char * name = "January"; is being converted by the compiler to char * name[8] = {'J','a','n','u','a','r','y','/0'}; Where [ char ] the compile add a /0 to the end of the array. – Andre Apr 25 '17 at 10:13