Metropoli BBS
VIEWER: lesson6 MODE: TEXT (ASCII)
.NT
 A NOTE ABOUT THE LESSONS in C 
.b4-24
.R5C4
These were written while the author was ~Ilearning~N  the language and since
.R6C4
they  are  ~Ifree~N ( to  copy  and/or  distribute ) there  is  a money-back
.R7C4
guarantee on the accuracy of each and every statement in the lessons (!)
.R9C4
The  ~Idisplay~N  program was written ( in C ) in order to provide a vehicle
.R10C4
for displaying the lessons.
.R12C5
.B
P.J.Ponzo
.B
Dept. of Applied Math
.B
Univ. of Waterloo
.B
Ontario N2L 3G1
.K16,30
PonzoTUTOR
.WNT
  POINTERS and ARRAYS  
.R4C1
    Recall that, when we refer to ~b~I&x~N, ~IC~N will interpret this as the
    ~Iaddress~N in memory of the variable ~b~Ix~N. Here ~b~I&x~N is a ~w~Rpointer~N.

    If we set ~b~Iy=&x~N, in our program, then ~b~Iy~N ~w~Rpoints~N to the 
    variable ~b~Ix~N  ( ~b~Iy~N is now an address, in memory ).

.b9-11
.R10C17
~V    HOW DO WE DECLARE A POINTER VARIABLE ?    ~N
.W
.R10C17
~V                    patience                  ~N

    In addition to the ~b~I&~N ~Ioperator~N (which returns the ~Iaddress~N of
    the variable which follows it), there is the C ~Ioperator~N ~b~I*~N.

    If ~b~Iy~N points to ~b~Iint x~N, then ~b~I*y~N is the ~Icontents of memory~N
    ~Ilocation y~N. When a program refers to ~b~I*y~N, the C compiler will go
    to the address given by the ~w~Rpointer~N ~b~Iy~N, extract the ~b~Iint~Neger
    it finds there, and use this ~b~Iint~Neger in place of ~b~I*y~N.

    This poses a problem.....
.K19,60
a problem?
.WN

    How is the compiler to know whether the contents of the address ~b~Iy~N,
    (which we refer to as ~b~I*y~N, in our program) is an ~b~Iint~Neger or a
    ~b~Ifloat~Ning point number or a ~b~Ichar~Nacter variable  ???

    Since an ~b~Iint~Neger occupies ~I2~N bytes ( usually ..depending upon the
    computer you are using) and a single ~b~Ichar~Nacter variable occupies
    just ~I1~N byte and a ~b~Ifloat~N occupies ~I4~N bytes ...etc. etc...then
    it's clearly important that the compiler KNOW that ~b~Iy~N is pointing to
    an ~b~Iint~N or a ~b~Ichar~N or a ~b~Ifloat~N ...etc.

   ~ISO ... we must declare the type of variable that ~b~Iy~N points to !~N

    To do this we declare ~Ithe contents of y~N, namely ~b~I*y~N !!
.K19,60
 example?
.WN
1 ~b~Imain() {                                                    ~N
2 ~b~I    int *y;                                                 ~N
3 ~b~I    int x=123;                          /* x=integer 123  */~N
4 ~b~I    y=&x;                               /* y=address of x */~N
5 ~b~I    printf("The value of x is %d",*y);                      ~N
6 ~b~I}                                                           ~N
    This program will (correctly) print: ~r~IThe value of x is 123~N
.K19,60
 int *y;

    Note that, in line 4, ~b~Iy~N is made a ~w~Rpointer~N, pointing to ~b~Ix~N
    and ~b~Ix~N is an ~b~Iint~N .... ~ISO~N  ... in line 2 we declare our
    ~w~Rpointer~N ~b~Iy~N as:  ~b~I  int *y  ~N  since it points to an ~b~Iint~N.
.K19,60
all clear?
.WN

       ~V                                                        ~N
       ~V   REMEMBER!! IF  sam  IS A POINTER TO SOME  VARIABLE,  ~N
       ~V              THEN BE SURE TO DECLARE *sam AS THE SAME  ~N
       ~V              TYPE AS THE VARIABLE TO WHICH sam POINTS! ~N
       ~V                                                        ~N
.b1-7
.K19,32
mamma mia!
.R10C1
    If ~b~Ix~N is an ~Iint~N  and ~b~Iy=&x~N then declare : ~b~Iint *y~N
    If ~b~Ix~N is a  ~Ichar~N and ~b~Iy=&x~N then declare : ~b~Ichar *y~N
    If ~b~Ix~N is a ~Ifloat~N and ~b~Iy=&x~N then declare : ~b~Ifloat *y~N
.WNT
   VARIABLES and their HOMES in MEMORY   
    We've mentioned that the ~b~Ichar c~N occupies ~I1~N byte of memory, and 
    that ~b~Iint i~N occupies ~I2~N bytes and ~b~Ifloat f~N occupies ~I4~N bytes.

    Suppose ~b~Ipc=&c~N is a ~w~Rpointer~N to ~b~Ic~N, and ~b~Ipi=&i~N and ~b~Ipf=&f~N.

        ~V  WHERE DOES pc+1 POINT TO ?  ~N

   and  ~V  WHERE DOES pi+1 POINT TO ?  ~N

   and  ~V  WHERE DOES pf+1 POINT TO ?  ~N
.K16,32
I give up!
.WN
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.R4C2
pc-2 pc-1 pc   pc+1 pc+2 pc+3 pc+4 pc+5 pc+6 pc+7 pc+8


    If the boxes are each ~I1~N byte of memory, and ~b~Ipc~N points to one
    such byte, then the scheme shown above indicates where ~b~Ipc-2~N, etc.
    point to.

    The fact that ~b~Ipc~N is a ~w~Rpointer~N to a ~b~Ichar~N (because we would 
    (should?) have declared it with ~b~Ichar *pc~N) and because a ~b~Ichar~N
    only occupies ~I1~N byte, then ~IC~N is smart enough to know that ~b~Ipc-2~N
    is the address of the memory location 2 bytes below ~b~Ipc~N.
.K16,32
 try int!
.WN
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.R4C2
pi-1       pi         pi+1       pi+2       pi+3       pi+4

    Now ~b~Ipi~N points to a (~I2~N byte) ~b~Iint~N, so ~IC~N (whatta guy!)
    arranges that ~b~Ipi-1~N points ~I2~N bytes earlier than ~b~Ipi~N ...that
    way it will point to the IMMEDIATELY PRECEDING ~b~Iint~N.

    (...of course, who knows if there IS an ~b~Iint~N stored at ~b~Ipc-1~N ?!)
.W
.K16,32
TRY FLOAT!
.WN
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.B
    
.R4C2
            pf                     pf+1                    pf+2

    You guessed it! ~b~Ipf+1~N will point to the VERY NEXT ~b~Ifloat~N, 
    ~I4~N bytes past where ~b~Ipf~N points.

    (...ain't ~Iaddress arithmetic~N wonderful ? )

    NOTE:If we have ~b~Imain() {           ~N
                    ~b~I    float f, *pf;  ~N
                    ~b~I    f=12.3;        ~N
                    ~b~I    pf=&f;         ~N

         then what IS ~I4~N bytes past the address of ~b~If~N ???

    There is one circumstance where we WILL know "what comes after".
.K19,60
  GUESS!
.WNT
    hip hip ARRAYS    
.R4C1
    You may recall, from an earlier lesson, that we defined a string by
    declaring it to be an ARRAY of (single) ~b~Ichar~Nacters.

    We'll reproduce it here:

~b~Ichar x[10];~N                 defines an ~IARRAY~N of ~b~I10~N elements.
~b~Ix[0]='A';~N                   the first element is the character ~b~IA~N.
~b~Ix[1]='b';~N                   the second element is the character ~b~Ib~N.
~b~Ix[2]='{';~N                   the third element is the character ~b~I{~N.
~b~Ix[3]='\0';~N                  the last element is the 'number' ~I0~N!!!!
~b~Iprintf("the string is %s",x);~N    print the string, up to the ~I0~N.

    ...and the printout would be: ~r~Ithe string is Ab{~N
.K19,60
remember?
.WN
~b~Imain() {                          ~N
~b~I    char x[10], *px;              ~N
~b~I    x[0]='A';                     ~N
~b~I    x[1]='b';                     ~N
~b~I    x[2]='{';                     ~N
~b~I    x[3]='\0';                    ~N
~b~I    printf("the string is %s",x); ~N


    NOW, if we define ~b~Ipx=&x[0]~N, a ~w~Rpointer~N to the first element in
    the ARRAY ~b~Ix[]~N, then:
.W
.Q
What character does px+2 point to ?
{
~b~Iprintf("%c%c%c",*px,*(px+1),*(px+2));~N
.Q
What will the above print?
Ab{

    ~b~Iprintf("%c",*px);~N would print the contents of memory location
    ~b~Ipx~N, namely ~r~IA~N, and ~b~Iprintf("%c",*(px+1));~N prints ~r~Ib~N,
    and ~b~Iprintf("%c",*(px+2));~N prints ~r~I{~N, and ALL THREE GIVE: ~r~IAb{~N.

                   ( ...a-a-a-h, C is ~Iso~N clever ...)
.K2,60
whatta gal
.WN
1 ~b~I    char x[4];                    ~N
2 ~b~I    x[0]='A';                     ~N
3 ~b~I    x[1]='b';                     ~N
4 ~b~I    x[2]='{';                     ~N
5 ~b~I    x[3]='\0';                    ~N
    In this program excerpt, we defined some elements of the ARRAY ~b~Ix[10]~N
    by saying ( laboriously ):~b~Ix[0]='A'; x[1]='b'; x[2]='{'; x[3]='\0';~N  

    For a ~b~Ichar~N ARRAY we can also say:

~b~Ichar x[4]={ 'A','b','{','\0' };~N

    making Lines 2-5 unnecessary.

    For an ~b~Iint~N ARRAY we can say:

~b~Iint x[3]={11,12,13};~N

    Under certain conditions, all ARRAYS may be ~Iinitialized~N (defined as they
    are declared).  We'll talk about this later ...
.K10,60
 curly {
.WNT
   More POINTERS and ARRAYS   
.R4C1
    When we define an ARRAY, say:  ~b~I int s[10];~N  then each of ~b~Is[0]~N,
    ~b~Is[1]~N, etc are (~I2~N byte) ~b~Iint~Negers.

                   ~I...and here's something special:~N 
.b6-8
.R10C1
               ~b~Is~N, all by itself, is a ~w~Rpointer~N to ~b~Is[0]~N
.b9-11
.K19,60
  WHAT!
.W
.R12C1                                                           
1 ~b~Imain() {                                                     ~N
2 ~b~I    int s[3];                    /* define integer array  */ ~N
3 ~b~I    s[0]=11; s[1]=12; s[2]=13;   /* define members of s[] */ ~N
4 ~b~I    printf("%d",s[0]);           /* print first integer   */ ~N
5 ~b~I    printf("\n%d",*s);           /* print what s points to*/ ~N
6 ~b~I}                                                            ~N
    Line 4 will print ~r~I11~N and line 5 will print ~r~I11~N    !!!
    ..proving that s[0] and *s are the same, right?
    ..so ~Is is a pointer to s[0]~N, right?
.K19,60
RIGHT!
.W
    Of course it would have been easier to say:
2 ~b~Iint s[3]={11,12,13};~N and omit Line 3!
.WN
    NOW, since an ARRAY (~Iany~N ARRAY, whether ~b~Iint~Ns or ~b~Ichar~Ns or ~b~Ifloats~N)
    ~Vhas its name as a pointer~N (..think about that! ), then not only will ~b~Is[2]~N
    give the 3rd element in the ARRAY, ~Ibut so will *(s+2) give the 3rd element!~N

    Here's a program you've seen in an earlier lesson (on STRINGS):

1 ~b~Imain() {                                                     ~N
2 ~b~I    char s;                      /* declare a char        */ ~N
3 ~b~I    s="I am a string";           /* make it a string      */ ~N
4 ~b~I    printf("%s",s);              /* print the string      */ ~N
5 ~b~I    printf("\n%s",s+2);          /*       what ?????      */ ~N
6 ~b~I}                                                            ~N

    Line 2 declares ~b~Is~N to be of type ~b~Ichar~N.
    Line 3 defines  ~b~Is~N to be a string ( double quotes, remember?).
    Line 4 prints the ~b~I%s~Ntring, giving ~r~II am a string~N        
    Line 5 prints ....  ~r~Iam a string~N
.W

    Here, just as for an ARRAY, ~b~Is~N is a ~w~Rpointer~N to the string
    ~b~I"I am a string"~N. In fact, ~b~Is~N points to the first element: ~b~II~N.
    HENCE, ~b~Is+2~N points to the ~I3rd element~N (~b~Ia~N) and ~b~Iprintf()~N will
    (upon receipt of a ~b~I%s~Ntring address) print everything from that
    address up to the special terminating ~I'\0'~N   ( ...remember him?).
.WK7,32
magnifico!
.WN






 ~ITHE NAME OF A STRING VARIABLE IS A POINTER TO THE FIRST ELEMENT IN THE STRING!

 ~ITHE NAME OF AN ARRAY VARIABLE IS A POINTER TO THE FIRST ELEMENT IN THE ARRAY !
.b5-11
~I
.K16,32
REMEMBER!
.WR3C1
                   ...and ~r~Ipointer~N arithmetic is wonderful...
.b2-4
.WNT
  Be kind to your compiler  
.R4C1
    Now, if we declare ~b~Ichar a[30];~N the C-compiler knows that ~b~Ia~N refers
    to a collection of ~I30~N ~b~Ichar~Ns ...and it knows this even before we define
    the elements ~b~Ia[0]~N, ~b~Ia[1]~N, etc.

    BUT, if we declare ~b~Ichar s;~N, how is the compiler to know whether ~b~Is~N
    if a single ~b~Ichar~N or a string of ~b~Ichar~Ns. If, subsequently, we say
    ~b~Is="I am a string"~N then ~b~Is~N IS a string ..but if we say ~b~Is='A'~N
    then ~b~Is~N is just one ~b~Ichar~N ...but should we REALLY make the compiler
    figure this out? After all, the compiler would reserve a single byte in
    memory for just one ~b~Ichar~N but may have to reserve dozens of bytes for
    a string of ~b~Ichars~N!

    ~VMORAL~N:     DECLARE A SINGLE CHARACTER AS ~b~Ichar s;~N
               DECLARE A STRING OF CHARS  AS ~b~Ichar *s;~N
.b15-18

    Since we (and the compiler) know that the name of a string is a ~w~Rpointer~N
    then the declaration ~b~Ichar *s;~N (followed perhaps by ~b~Is="I'm a string"~N)
    just anticipates the subsequent use of ~b~Is~N as the name of a string (as
    opposed to a single character).
.WNR3
~b~I                         ~N
~b~I    char s;              ~N
~b~I    s="I am a string";   ~N
~b~I    printf("%s",s);      ~N
~b~I                         ~N

    Although we have used the above format in earlier lessons .....

.B
IT MAY NOT COMPILE!
.R14C1
 ...and if it does 

.B
IT MAY NOT WORK!  
.WR4C40
~b~I    char *s;             ~N
.R21B
     If we use ~b~Ichar *s~N then ALL compilers will accept it.    
.WN
    We have:

    If ~b~Is~N is the name of a string (defined with ~Idouble quotes~N) then
    ~b~Is~N ~b~Is+1~N ~b~Is+2~N etc ~w~Rpoint~N to the ~I1st~N ~I2nd~N ~I3rd~N etc.
    members of the string.
.b2-6 
.R8C1
    If ~b~Is~N is the name of an ARRAY (defined with ~b~Is[0]=...~N etc.) then
    ~b~Is~N ~b~Is+1~N ~b~Is+2~N etc ~w~Rpoint~N to the ~I1st~N ~I2nd~N ~I3rd~N etc.
    members of the ARRAY. 
.b7-11 
.K17,60
hmmmmmm...
.WN
    Now, don't think that strings and ARRAYs are the same ...after all a string
    is only an ~IARRAY of (single) ~bchar~N~I variables~N whereas we can also have
    ARRAYs of ~b~Iint~Ns or ~b~Ifloats~N or other interesting ~Idata types~N.
.W

    Further, the name of a string pointer is a VARIABLE:

1 ~b~Imain()  {                                            ~N
2 ~b~I   char *x, *y, *z;   /* 3 pointers to strings    */ ~N
3 ~b~I   x="ABC";           /* x points to string ABC   */ ~N
4 ~b~I   y="DEF";           /* y points to string DEF   */ ~N
5 ~b~I   z=x;               /* z points to string ABC   */ ~N
6 ~b~I   printf(" The x-string is %s",z);                  ~N
7 ~b~I   z=y;               /* z points to string DEF   */ ~N
8 ~b~I   printf(" The y-string is %s",z);                  ~N
9 ~b~I                                                     ~N
    In line 5 we make ~b~Iz~N point to the same thing that ~b~Ix~N points to
    ...and line 6 prints: ~r~I The x-string is ABC~N

    In line 7 we make ~b~Iz~N point to the same thing that ~b~Iy~N points to 
    ...and line 8 prints: ~r~I The y-string is DEF~N
.W
    BUT, we could also say: ~b~Ix=y;~N and make ~b~Ix~N point to the y-string!
.WNT
    STRINGS and 1-dimensional CHAR ARRAYS   
.R4C1
    Suppose we may declare strings ~b~Ic~N and ~b~Ix~N by using:

    1   ~b~Ichar c[9]={'c','-','s','t','r','i','n','g','\0'}; ~N 
    2   ~b~Ichar *x="x-string";                               ~N

    In the first instance, ~b~Ic~N is a ~r~Ipointer~N to an ARRAY of ~b~Ichar~Nacter
    variables (8 ~b~Ichar~Ns: ~Ic-string~N , plus the terminating '\0').

    In the second instance, ~b~Ix~N is ~Ialso~N a ~r~Ipointer~N, but now it's a
    ~r~Ipointer~N to a ~Istring~N: ~b~Ix-string~N with (again) the terminating
    '\0' (which ~IC~N looks after appending).

    SO WHAT'S THE DIFFERENCE BETWEEN    char c[]   and   char *x ???
.K19,60
I give up
.WN
    1   ~b~Ichar c[9]={'c','-','s','t','r','i','n','g','\0'}; ~N 
    2   ~b~Ichar *x="x-string";                               ~N

    In the first case, ~b~Ic~N is a ~ICONSTANT POINTER~N to the first element of
    the ARRAY ...and ~Icannot be changed~N.
    In the second case, ~b~Ix~N is a ~IVARIABLE POINTER~N to the first element of
    the string ...and ~ICAN~N be changed!
.K19,32
  WHAT!
.WN
1 ~b~Ichar c[9]={'c','-','s','t','r','i','n','g','\0'};               ~N 
2 ~b~Ichar *x="x-string";                                             ~N
3 ~b~Iprintf("  %s   %s ",c,x);     /* print %strings  c and x    */  ~N
4 ~b~Ix=c;                          /* make x point to c          */  ~N
5 ~b~Iprintf("  %s   %s ",c,x);     /* print %strings  c and x    */  ~N

    Just to show that it is ~b~Ix~N (and ~INOT~N ~b~Ic~N) which is a VARIABLE,
    we declare/define them both in Lines 1 and 2.
    Then print them both in Line 3. We would get:

~r~I  c-string   x-string~N

    Then we ~Ichange x~N, in Line 4, so it points to the same thing as ~b~Ic~N does,
    then print them both again, in Line 5. We'd get:

~r~I  c-string   c-string~N

    You must not try:  ~b~Ic=x;~N    because it won't compile!

    ARRAY names point (ALWAYS and FOREVER) to the first element of the ARRAY!
.b19-21
.WNT
   more and more ARRAYS   
.R4C1
    In addition to an ARRAY such as ~b~Ix[10]~N (with 10 elements,
    which may be char,int,float,etc.),here's a ~Idouble ARRAY~N:

~b~Ifloat x[5][7];~N   This declares an ARRAY of 5*7=~I35~N
                 floating point numbers. We may define any or all
                 of them (for example we may write ~b~Ix[2][1]=1.5~N).
                 We think of this ARRAY as being arranged like so:
.R12C1
           x[0][0] x[0][1] x[0][2] x[0][3] x[0][4] x[0][5] x[0][6]
           x[1][0] x[1][1] x[1][2] x[1][3] x[1][4] x[1][5] x[1][6]
           x[2][0] x[2][1] x[2][2] x[2][3] x[2][4] x[2][5] x[2][6]
           x[3][0] x[3][1] x[3][2] x[3][3] x[3][4] x[3][5] x[3][6]
           x[4][0] x[4][1] x[4][2] x[4][3] x[4][4] x[4][5] x[4][6]
.b11-17
.K4,66
x[i][j][k]
.WR4C1
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
.R4C1
    Now, if we define ~b~Ix[2][1]=1.5~N, the number 1.5 goes here!
.sR14C20
~Fx[2][1]~N
.r

    ...and, as you might expect, we can have ~I3-dimensional~N ARRAYS, etc.
.rK4,66
x[i][j][k]
.WN
~V  x[0][0] x[0][1] x[0][2] x[0][3] x[0][4] x[0][5] x[0][6]  ~N
~V  x[1][0] x[1][1] x[1][2] x[1][3] x[1][4] x[1][5] x[1][6]  ~N
~V  x[2][0] x[2][1] x[2][2] x[2][3] x[2][4] x[2][5] x[2][6]  ~N
~V  x[3][0] x[3][1] x[3][2] x[3][3] x[3][4] x[3][5] x[3][6]  ~N
~V  x[4][0] x[4][1] x[4][2] x[4][3] x[4][4] x[4][5] x[4][6]  ~N
    When we declare a multi-dimensional ARRAY, as in ~b~Ifloat x[5][~F7~N~b~I]~N, the
    C-compiler knows that each element occupies ~I4 bytes~N in memory (because
    it's an ARRAY of ~b~Ifloat~Ns) ..hence it knows not only how much memory
    is needed but where each element is. Starting at the ~Iaddress~N of the first
    element, ~b~I&x[0][0]~N, we find the ~Iaddress~N of ~b~Ix[~F2~N~b~I][~F1~N~b~I]~N by moving
    ~F~I7~N*~F~I2~N+~F~I1~N=15 elements along the ARRAY ...and at 4-bytes-per-element
    that means moving 4*15=60 bytes through memory.

    Notice how important the number of ~Icolumns~N is to the C-compiler (in the
    declaration ~b~Ifloat x[5][7]~N
    Without this dimension the compiler wouldn't know how to get to ~b~Ix[2][1]~N!

    In fact, ~IYOU MAY LEAVE OUT THE NUMBER OF ROWS IN DECLARING THIS ARRAY!~N

    (and use ~b~Ifloat x[][7]~N instead!)
.WR6C1s
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
                                                                              
.r
    A 2-dimensional ARRAY is treated (by ~IC~N) as a 1-dimensional ARRAY each
    of whose elements is a 1-dimensional ARRAY.

    The ARRAY ~b~Ifloat x[5][7]~N consists of ~I5~N 1-dimensional ARRAYS, called
    (in C-speak), ~b~Ix[0]~N, ~b~Ix[1]~N, ~b~Ix[2]~N, etc. and each of these
    1-dimensional ARRAYS has ~I7~N elements.

    Since (for example) the element 3  of an ARRAY ~b~Isam~N is called ~b~Isam[3]~N
    then element 3 of the (1-dimensional) ARRAY ~b~Ix[2]~N is called ~b~Ix[2][3]~N
    ... which explains the C-notation for 2-dimensional ARRAYS,
    x[i][j], rather than (the more usual) x[i,j].

    In fact, you may refer to ~b~Ix[2][3]~N as ~b~I(x[2])[3]~N ... meaning 
    element 3 of the (1-dimensional) ARRAY x[2] (actually the 4th element
    since the first is element 0 !!!@#$*).
.WR3C1
~V  x[2][0] x[2][1] x[2][2] ~Fx[2][3]~N~V x[2][4] x[2][5] x[2][6]  ~N
.WN


    If ~IC~N regards ~b~Ix[5][7]~N as consisting of ~I5~N 1-dimensional ARRAYS
    ~b~Ix[0]~N, ~b~Ix[1]~N, ~b~Ix[2]~N, ~b~Ix[3]~N, and ~b~Ix[4]~N then what
    does (for example) ~b~Ix[2]~N refer to ?  What happens if we printf() ~b~Ix[2]~N?
    Is ~b~Ix[2]~N just a notation or does it refer to one of the ~I5*7=35~N members
    of ~b~Ix[5][7]~N ?
.b2-8
.K10,32
I give up!
.WN

    Actually, ~IC~N is very clever. ~b~Ix[2]~N (all by itself) is a ~r~Ipointer~N to the
    first element in the 1-dimensional ARRAY ~b~Ix[2]~N, namely  ~b~Ix[2][0]~N !

    ~IREMEMBER~N: Although ~b~Ix[2][0]~N gives the ~Ivalue~N of element ~b~Ix[2][0]~N,
              ~b~Ix[2]~N gives the ~Iaddress~N of ~b~Ix[2][0]~N!!

    Since ~b~Ix[2]~N is a ~r~Ipointer~N to ~b~Ix[2][0]~N, then ~Iaddress arithmetic~N
    can be used to obtain the ~Iaddress~N of any element in the 1-dimensional
    ARRAY ~b~Ix[2]~N.

    That means that we could identify the element ~b~Ix[i][j]~N
    by pointing just ~Ij~N elements past the address of ~b~Ix[i][0]~N.

    That means that ~b~Ix[i]+j~N is a ~r~Ipointer~N to ~b~Ix[i][j]~N

    That means that the 'value' of this element is ~b~I*(x[i]+j)~N.

    ~IREMEMBER~N: If x[i]+j is a pointer, then *(x[i]+j) is what it points to!
.b4-7
.b18-20
.WK8,32
MAMMA MIA!
.R23C1
          ~Iand that means that *(x[2]+3) and x[2][3] are EQUIVALENT~N
.b22-24
.WNT
    What's in a name ? (of an ARRAY)  
.R6C1
  ~V                                                                    ~N
  ~V             The  name  of a  1-dimensional  ARRAY is a             ~N
  ~V             POINTER to the first element of the ARRAY!             ~N
  ~V                                                                    ~N
.b5-10

    SO, if ~b~Ix~N is an ARRAY, declared as ~b~Iint x[10]~N, then ~b~Ix~N
    is a ~r~Ipointer~N to ~b~Ix[0]~N (since ~b~Ix~N is 1-dimensional).

    AND, if ~b~Ix~N is an ARRAY, declared as ~b~Iint x[10][15]~N, then ~b~Ix[7]~N
    is a ~r~Ipointer~N to ~b~Ix[7][0]~N (since ~b~Ix[7]~N is 1-dimensional).
.K19,32
sounds OK!
.WN
.R10C1
    ...and finally, we may ~b~Iprintf("%d",x[7][2]);  ~N to print the value of

    the element, OR we may ~b~Iprintf("%d",*(x[7]+2));~N.
.b8-14
.K19,32
beautiful!
.WN


.T
   That's all folks!   
.K16,32
au revoir!


.q

[ RETURN TO DIRECTORY ]