Topic : C Lessons
Author : Christopher Sawtell
Page : << Previous 7  Next >>
Go to page :


             /* generated format
string     */
        printf( "\n" );
        }

/* ----------------------------------------- */


  If you cheated and looked at my example before even attempting
        to have a go, you must pay the penalty and explain fully why
        there are THREE "%" signs in the line which starts with a call
        to the sprintf function. It's a good idea to do this anyway!


  So much for printf(). Lets examine it's functional opposite - scanf(),

        Scanf is the family of functions used to input from the outside world
        and to perform internal format conversions from character strings to
        binary numbers. Refer to the entry scanf(3S) in the Programmer
        Reference Manual. ( Just a few pages further on from printf. )

  The "Important Point to Note" for the scanf family is that the
        arguments to the function are all POINTERS. The format string has to
        be passed in to the function using a pointer, simply because this
        is the way 'C' passes strings, and as the function itself has to store
        its results into your program it ( the scanf function ) has to "know"
        where you want it to put them.


Lesson 3


Arrays and Pointers.


   You can allocate space for an array of elements at compile time with fixed
   dimension sizes of any data type, even functions and structs.
   So these are legal array definitions:

  char name[30];                   /* An array of 30 signed

characters. */
  char *strings[50];               /* 50 pointers to strings. */
  unsigned long int *(*func)()[20];/* An array of pointers to functions which
*/
                                   /* return pointers to unsigned long ints.

*/


   You can declare a pointer to point at any type of data element, and as in
   the array situation above functions and structs are included.

struct ship
{
  char name[30];
  double displacement;                           /* in grammes */
  float length_of_water_line;                    /* in meters */
  unsigned short int number_of_passengers;
  unsigned short int number_of_crew;
  };


   So using the ship concept from Lesson 2 you can declare a pointer to point
   at one of the ship structs in an array.

struct ship *vessel_p;

   Note the use of the suffix "_p".
   This is my way of reminding myself that the variable is a pointer.

struct ship fleet[5];     /* This allocates enough storage for

5 ships' info.
*/


   Now lets set the pointer to point at the first vessel in the fleet.

  vessel_p = fleet;

   This pointer can be made to point at other ships in the fleet by
   incrementing it or doing additive arithmetic on it:

  vessel_p++;             /* point a the next ship in the fleet array. */
  vessel_p = fleet + 3;

   Also we can find out the index of the ship in the fleet at which we are
   pointing:

  i = vessel_p - fleet;

   It is also legal to find out the separation of two pointers pointing at
   elements in an array:

  d = vessel_p - another_vessel_p; /* This gives the separation

in elements. */


   So summarising, pointers may be, incremented, decremented, and subtracted
   one from another or have a constant subtracted from them. Any other
   mathematical operation is meaningless and not allowed.

   Assembler programmers should note that while the pointer variables contain a
   byte machine address, when the arithmetic is done using pointers the
compiler
   also issues either a multiply or a divide as well as the add or subtract
   instruction so that the result is ALWAYS expressed in elements rather than
   bytes. Have a go and write yourself a trivial little program, and have a
   look at the compiler ouput code. Lesson 1 told you how!

   When using a pointer to reference a structure we have to use a "pointer
   offset" operator in order to access the member of the struct we require:

  vessel_p = fleet;

  vessel_p->name = "Queen Mary";
  vessel_p->displacement = 97500000000.0;
  vessel_p->length_of_water_line = 750.0
  vessel_p->number_of_passengers = 3575;
  vessel_p->number_of_crew = 4592;


   Remember:

       It's a "." when accessing a struct which is in storage declared in
       the program.

       It's a "->" when accessing a struct at which a pointer is pointing.

  Initialisation of arrays.

   'C' has the facility to initialise variables in a program script.

   Some examples:

  char *qbf = "The quick brown fox jumped over the lazy dogs back";

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

  struct ship fleet[2] =
  {
    { "Queen Elizabeth",  97500000000.0, 750.0, 3575, 4592 },
    {      "Queen Mary", 115000000000.0, 875.0, 4500, 5500 }
    };


   Take a careful note of where the commas and semi-colons go ( and don't go )!

   Initialised Tables of Indeterminate Length.

   One nice feature 'C' offers is that it is able to calculate
   the amount of storage required for a table by 'looking' at the number
   of initialisers.

char *verse[] =
{
  "On top of the Crumpetty Tree",
  "The Quangle Wangle sat,",
  "But his face you could not see,",
  "On account of his Beaver Hat.",
  "For his Hat was a hundred and two feet wide.",
  "With ribbons and bibbons on every side,",
  "And bells, and buttons, and loops, and lace,",
  "So that nobody ever could see the face",
  "Of the Quangle Wangle Quee."
  NULL
  };


   Note the * character in the definition line. This means that we are going
   to make an array of pointers to variables of type char. As there is no
   number between the [ ] characters the compiler calculates it for us.
   With this kind of set-up it is nice and easy to add extra information
   to the table as program development proceeds. The compiler will calculate
   the new dimension for you. The point to remember is that the program has to
   know - from the contents of the table - that it has come to the end of the
   table! So you have to make a special entry which CANNOT under any
   circumstances be a real data element. We usually use NULL for this.
   The other way is to calculate the size of the table by using the sizeof
         operator - Note that although use of sizeof looks like a function call
         it is in fact an intrinsic operator of the language. The result is
         available at compile time. So one can say:-

        #define SIZE_OF_VERSE sizeof verse

   There is one final initialised data type, the enum. It is a fairly recent
   addition

Page : << Previous 7  Next >>