4
    #include <stdio.h>

    int main()
    {
        char str[3][15] = {"Pointer to","char","program"};
        char (*pt)[15] = str; // statement A
        char *p = (char *)str; // statement B
        printf("%s\n",p[3]); // statement C  - Seg Fault in this line
        printf("%s\n",p); // working properly displaying "Pointer to"
        printf("%s\n",p+1); // here it is pointing to second element of first array so displaying "ointer to"
        printf("%s\n",pt+1); // printing properly "char" as expected
        int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
        int (*nm)[3] = num[1];
        int *n = num;
        printf("n - %d\n",n[10]); // statement D
        printf("nm - %d\n",nm[0][0]);
        return 0;
    }

My questions:

  1. Please help me to get clear idea about the data storing mechanism in case of char array and int array

  2. In above program I am understanding that when pointer to char array is pointed to 2D array of char as shown in statement A it is displaying properly but when it is pointed by normal char pointer and trying to print the char in statement C it is getting SegFault, instead it should print 'n'(3rd number char in first array "Pointer to") so having confusion why in case int array i am getting proper element n = 11 in statement D and why in this case (statement C) it is not properly printing.

  3. How the data will be stored in case of char array will it be stored in this form shown below


char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o'},
                   {'c','h','a','r'},
                   {'p','r','o','g','r','a','m'}};

if it is stored like this then it should work like array of integer pointer shown in statement D Please help me to guide about this issue and clarify the issue I have in case of char and int array storage.

Sergio
  • 8,099
  • 2
  • 26
  • 52
ssg
  • 247
  • 2
  • 15
  • `char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o','\0'}, {'c','h','a','r', '\0'}, {'p','r','o','g','r','a','m', '\0'}};` – LPs Jul 28 '16 at 06:26
  • statement D works because `num` is getting allocated as a single array which the compiler accesses using the following formula: given the statement `num[row][col]` then it's the same as `*((int *)num + row * 4 + col)`. – miravalls Jul 28 '16 at 06:35
  • `printf("%s\n",p[3]);` --> `printf("%s\n",&p[3]);` – LPs Jul 28 '16 at 06:37
  • statement B is the same as `p = str[0]` because how the array is being declared on the stack. `p[3]` returns a character, not an address as @LPs is noting. If you want to print `p[3]`, the format specifier should be `%c`. – miravalls Jul 28 '16 at 06:42

2 Answers2

4

Lets look to your code step by step.

char str[3][15] = {"Pointer to","char","program"};

Here you have created an array of three arrays of fifteen char's. And you are initializing each of the char arrays with string literals. If literals are shorter than array - last elements are filled with zeros, so it is the same as:

char str[3][15] = {
    {'P', 'o', 'i', 'n', 't', 'e', 'r', ' ', 't', 'o', 0, 0, 0, 0, 0},
    {'c', 'h', 'a', 'r', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {'p', 'r', 'o', 'g', 'r', 'a', 'm', 0, 0, 0, 0, 0, 0, 0, 0}
};

Then

char (*pt)[15] = str; // statement A

Here you create pt as a pointer to array of fifteen char's, and you are initializing it with address of str[0], i.e. pt points to first char[15] array from str.

Next

char *p = (char *)str; // statement B

It is not OK. As far as I see - you are trying to make p to point to the first char at memory that str occupies. Expression str has type of char (*)[15], i.e. it is a pointer to array of characters, not pointer to char (and because of this you are forced to use cast), And regardless to the fact that str really points to cell where the 'P' is stored - you should to it in more type-safe way:

char *p = &str[0][0]; // the same as "p = str[0];"

str[0] is referencing to first element of str, i.e. type of str[0] is an array of fifteen char's, then you can just refer to the first char and take it address - &(str[0])[0], or simply use the fact that expression with type "array" decays to type "pointer to first array's element", that's why str[0] works too.

Lets go ahead

printf("%s\n",p[3]); // statement C  - Seg Fault in this line

This line causes undefined behavior, because format specifier requires the second argument to be a const char * but you are passing char. If you want to print one char - do that:

printf("%c\n", p[3]); // prints "n"

Then

    printf("%s\n",p); // working properly displaying "Pointer to"
    printf("%s\n",p+1); // here it is pointing to second element of first array so displaying "ointer to"

These work well, because the type of second argument is proper and we know that strings are nul-terminated.

printf("%s\n",pt+1); // printing properly "char" as expected

Saying frankly - it is incorrect, since pt + 1 is "pointer to array of char" but you should pass "pointer to char". It should be rewritten as:

printf("%s\n",*(pt+1)); // or pt[1]

But it seems to work because regardless to the type incompatibility both pointers point to the same location.

Next section about int's.

int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*nm)[3] = num[1];
int *n = num;

Here are two mistakes: nm shouldn't be initialized with num[1] since they have incompatible types: "pointer to array of three int" vs. "array of four int / pointer to int" (thanks to decaying). And n can not be initialized with num because they have incompatible types too. According to my guess about what you want it should look in next way:

int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*nm)[4] = num + 1;
int *n = &num[0][0];

And the last ones:

printf("n - %d\n",n[10]); // statement D
printf("nm - %d\n",nm[0][0]);

Dereference is correct and passed arguments too, but keep in mind that pointers were initialized incorrectly.

Hope, I've covered all your questions.

Sergio
  • 8,099
  • 2
  • 26
  • 52
2

Your segfault is due to the fact that you are passing the wrong type to printf.

Writing p[3] you are deferencing the pointer to the 4th char of first row of matrix str. Same as *(p+3)

If you want to print the 3rd char you should

printf("%c\n",p[3]);

If you want to print the first C-String (row 0 of matrix) you must:

printf("%s\n",&p[3]);

because %s wants a char *.

If you add, at least for gcc, -Wall option to your command, compiler will show you a good and useful warning:

test.c:8:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
         printf("%s\n",p[3]); // statement C  - Seg Fault in this line

About question 3 you must take note that the correct storing is:

char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o','\0'},
                   {'c','h','a','r','\0'},
                   {'p','r','o','g','r','a','m','\0'}};

due to the fact that C-String are null terminated, so, for example, the string "Pointer to" will occupy 11 chars


Last thing is about the int pointer. It works well because of %d format specifier wants an int value, not an address. So writing:

printf("n - %d\n",n[10]);

is fully correct because n[10] is dereferencing the 11th element of num matrix, that means 3rd element of 3rd row. Same as *(n+10)

LPs
  • 16,045
  • 8
  • 30
  • 61
  • *Writing p[3] you are deferencing the pointer to the 3rd char* That is not correct. – 2501 Jul 28 '16 at 10:59
  • Using `p` to point out of the bounds of the inner array, such as `p[10]` is undefined behavior. – 2501 Jul 28 '16 at 11:10
  • @2501 Ok for the first comment, I edited. But I'm not getting you about the second one. – LPs Jul 28 '16 at 12:04
  • Sorry I meant the pointer `n`. It's initialization is wrong, but if we ignore that, `n` is pointing to `num[0]` which is of type `int[4]`. Access `n[10]` is out of bounds. – 2501 Jul 28 '16 at 12:12
  • @2501 I guessed it. Probably sunbathing on the seaside last days cooked my brain, but I really not getting you. `num` is a matrix `3x4`. Memory is contiguous, so starting from `&num[0][0]` there are 12 `int`s. So `n[10]` is inbound. Do I need coffee? ;) – LPs Jul 28 '16 at 12:23
  • Read 6.5 8 in the latest standard. Accessing an object out of bounds is undefined behavior. If there happens to be another object contiguous to this one is irrelevant. – 2501 Jul 28 '16 at 12:25
  • @2501 Well, got it. But have you got an example where matrix rows are not contiguous and the behavior is really undefined? – LPs Jul 28 '16 at 12:58
  • The behavior is undefined because of 6.5 8. Whether the array is contiguous or not is irrelevant. – 2501 Jul 28 '16 at 13:02