2

If I want to print out array of string like:

char juices_A[][12] = { "dragonfruit", "waterberry", "sharonfruit", };

I can simply use juices_A[0],juices_A[1],juices_A[3], respectively as a pointer to string "dragonfruit", "waterberry", "sharonfruit", and print them out.

But what if I want to print out array of int array like:

int data[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

I can not simply use data[0],data[1],data[2] as pointer to { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, I need to adopt a more complicated way to print them out. I need to use loop inside loop. So I want to know why I can not use pointer in the int situation? I read on book "Array variables are like pointers.." so I assume int array variable data[0],data[1],data[2] are also like pointers...

#include <stdio.h>

int main() {

    int i_A = 0;
    char juices_A[][12] = { "dragonfruit", "waterberry", "sharonfruit", };
    for (; i_A < 3; i_A++)
        printf("%s;", juices_A[i_A]);
    puts("");

    int i_B = 0;
    int data[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
    for (; i_B < 3; i_B++) {
        int i_C = 0;
        for (; i_C < 3; i_C++)
            printf("%i,", data[i_B][i_C]);
        printf(";");
    }

    return 0;
}

the result is:

dragonfruit;waterberry;sharonfruit;
1,2,3,;4,5,6,;7,8,9,;
Lee William
  • 125
  • 1
  • 11
  • 3
    The language treats `char*` as a string -- an array of characters that has a terminating null character. There is nothing of the sort for `int` and `int*`. `char` and `char*` are special in that regard. – R Sahu Apr 07 '15 at 06:13
  • You seem to understand things pretty clearly, and with reference to the above comment too, the simple answer is 'no'. – teppic Apr 07 '15 at 06:24
  • BTW, your example refers to `juice_A[0]` when your array is called `juices_A`. – Wai Ha Lee Apr 07 '15 at 06:30

4 Answers4

2

You can use access arrays like pointers and vice versa.

Here's the output from the program below:

dragonfruit;waterberry;sharonfruit;
{ { 1, 2, 3, }, { 4, 5, 6, }, { 7, 8, 9, }, }

Here's a modification to your code:

#include <stdio.h>
#define ROW_WIDTH 3
#define TABLE_HEIGHT 3
int main(void) {

    char *juices[] = { "dragonfruit", "waterberry", "sharonfruit", };
    int data[TABLE_HEIGHT][ROW_WIDTH] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

    for (int n = 0; n < ROW_WIDTH; n++) 
        printf("%s;", juices[n]);

    int *ip = (int *)data;

    printf("\n{ ");
    for (int i = 0; i < TABLE_HEIGHT; i++) {
       printf("{ ");
       for(int j = 0; j < ROW_WIDTH; j++) {
           printf("%d, ", *ip + ((i * ROW_WIDTH) + j));
       }
       printf("}, ");
    }
    printf("}\n");
    return 0;
}
clearlight
  • 12,255
  • 11
  • 57
  • 75
  • The problem with using pointer notation is you lose the sense of boundaries that the [] notation maintains for you. So in this example we just treat data like a single dimension array of ints that we have a pointer to, and then use basic matrix math to represent it as an H x W table. And C knows, that, because it is a pointer to an int array that it needs to move use internal pointer offset by 4-bytes for each 'external' increment of 1. – clearlight Apr 07 '15 at 06:55
  • @Allaboutthatbase2, `in this example we just treat data like a single dimension array of ints that we have a pointer to ...` in practice it works, but it's undefined behavior, take a look to [this](http://stackoverflow.com/q/25303647/1606345) and [this](http://stackoverflow.com/a/7785116/1606345) – David Ranieri Apr 07 '15 at 07:03
  • Thanks. The 2nd answer is easier to understand, as it's my bed time. I was toying with casting data as a **, but as it's late I didn't pursue that further. I wasn't aware of the caveat about optimizing compilers. I'd really be surprised if there's a C compiler that would break for cases like this because so many people depend on predictable layout of data. And while there is a specification - we all know the pressure vendors and the community feel to succumb to the popular demand and tolerate things that are not technically what they initially intended :-) Keith's answer is excellent tho. – clearlight Apr 07 '15 at 07:17
  • @AlterMann - And thanks for keeping me honest. I will have to re-visit your quoted text again and try to make sense of it. – clearlight Apr 07 '15 at 07:17
  • @Allaboutthatbase2, you're welcome, `I'd really be surprised if there's a C compiler that would break for cases like this`, as pointed out by Ken Thompson in comments, it's safe enough because most C implementations don't do array bounds-checking, but the correct way of dealing with that array through a pointer is using `int (*ip)[ROW_WIDTH] = data;` – David Ranieri Apr 07 '15 at 07:29
1

Strings:

-------------------------
|h | e | l | l | o | \0 |
-------------------------
|w | o | r | l | d | \0 |
------------------------

As you see this array can be stored in a 2D char array

char a[2][6];

Now a[i] gives the starting address of each row and %s prints out a string until a \0 is enountered so you can just pass the address of each row and get the contents of the row. Just like

char *p = "hello";
printf("%s\n",p);

Note: Again if you want to read the character at a particular location you need to specify a[row][col]

Whereas

Integers:

----------------
|1 | 2 | 3 | 4 |
----------------
|5 | 6 | 7 | 8 |
----------------

Now you can have a array like

int b[2][4];

b[i] will give you the starting address of each row but in order to get the value stored in a particular location you need to specify value with b[row][col].

The difference is the sentinel condition for valid C strings is \0 and is it being used to access each row which is not the case for integers.

so I assume int array variable data[0],data[1],data[2] are also like pointers

Yes they are pointers to each row but you need to dereference the pointer to get the value right? So if data[0] is a pointer then do data[0][column]

Gopi
  • 19,784
  • 4
  • 24
  • 36
1

The char juices_A[][12] = { "dragonfruit", "waterberry", "sharonfruit" }; whenever the data is accessed it prints till \0 is reached, as strings are considered only till \0. So when we use juices_A[0] it points to start of first data till \0 is reached.But to get an individual char we need to mention both the dimensions of the array.

char juices_A[1][2] to access 't' in waterberry

But this is not the case with int as each is considered as separate entity. So we use both dimensions of the array to access it.

Even if we reduce the size of the array like char juices_A[][12] = { "dragon", "waterberry", "sharonfruit" }; when printed it outputs

dragon;waterberry;sharonfruit

But in the case of int data[3][3] = { { 1, 2}, { 4, 5, 6 }, { 7, 8, 9 } }; it outputs

1,2,0,....` this makes the difference

Nerdy
  • 1,016
  • 2
  • 11
  • 27
0
#include <stdio.h>

int main()
{
    int data[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
    int *ptr;
    int lines = 3;
    int columns = 3;
    int i;


    ptr = &data[0][0];

    while (lines-- > 0) {
        i = columns;

        while (i-- > 0) {
            printf("%d ", *ptr);
            ptr += 1;
        }

        putchar('\n');
    }
    return 0;
}

or:

#include <stdio.h>

int main()
{
    int data[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
    int *ptr;
    int lines = 3;
    int columns = 3;
    int max = lines * columns;


    ptr = &data[0][0];

    while (max-- > 0) {
        printf("%d ", *ptr);
        ptr++;

        if (max % columns == 0)
            putchar('\n');
    }

    return 0;
}
David Ranieri
  • 39,972
  • 7
  • 52
  • 94