Skip to main content
Engineering LibreTexts

5.1: Introduction

  • Page ID
    25704
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    All variables and functions have an address (memory location) associated with them. This is where they "live". For multiple byte entities, this is the starting address of the memory block the item occupies. The address of any variable (with the exception of register class) can be found with the & operator. Depending on the operating system, the address will generally be contained within either 2 bytes or 4 bytes in length (8 bytes for a 64 bit OS). That is, all possible addresses in the system can be so described. If an address is placed into another variable, this other variable is said to be a pointer (i.e., it stores the address of, or "points to", the first variable). In order to take advantage of type checking and pointer math, pointers are declared by the type of item they point to, even though all pointers are themselves the same size. Thus, a pointer is properly declared as a pointer to a type char or a pointer to a type float, for example. The * operator is used to indicate that the declaration is of a pointer. For example:

    int *pc;
    

    declares a pointer to an int.

    int c, *pc;
    
    c = 12;
    pc = &c;
    

    This chunk of code declares an int and a pointer to an int, assigns 12 to the int (c), and then places the address of the int (c) in the pointer (pc). The value of the item pointed to can be retrieved through the indirection operator *. Consider the following addition to the above:

    printf("The value of c = %d, the address of c = %d\n", c, &c );
    printf("The value of pc = %d, the value pc points to = %d\n", pc, *pc );
    

    Note that c and *pc are the same value (12). Also, note that if the value of c is changed, *pc reflects this change. Thus, adding

    c = 36;
    printf("New value of c = %d, the address of c = %d\n", c, &c );
    printf("The value of pc = %d, the value pc points to = %d\n", pc, *pc );
    

    will show 36 for *pc as well as c, and the addresses will not have changed.

    Exercise \(\PageIndex{1}\)

    Create a small program based on the above code and run it. Compare your results to those of your fellow lab workers. What do you notice?

    What if the address of the pointer is stored in another pointer? This is called a handle. Consider the following code fragment:

    int c, *pc, **ppc;
    
    c = 12;
    pc = &c;
    ppc = &pc;
    
    printf("pc = %d, the value pc points to = %d\n", pc, *pc );
    printf("ppc = %d, the value ppc points to = %d\n", ppc, *ppc );
    

    Exercise \(\PageIndex{2}\)

    Alter your program to reflect the above. Run it and compare your results. What do you think the value **ppc is? (Try it).

    Addresses can be sent as arguments to functions. This is how a function can return more than one value and is an important concept to remember. Consider the following:

    int main( void )
    {
          int a, b, c, *pc;
    
          pc = &c;
    
          assign_it( &a, &b, pc );
    
          printf(“The values in main are: %d %d %d\n”, a, b, c );
    }
    
    void  assign_it( int *x, int *y, int *z )
    {
          *x = 1;
          *y = 20;
          *z = 300;
    }
    

    Note that assign_it() can be called using either the address of operator (&) on an existing variable, or by passing a pointer to a variable (as in the case of &c or pc). Also, assign_it()s declaration states that it is accepting pointers to int, not plain old int.

    Exercise \(\PageIndex{3}\)

    Using the above as a guide, create a program to test returning multiple values from a function.

    Exercise \(\PageIndex{4}\)

    Modify the above to print out the addresses of the variables as received by assign_it(), as well as &a, &b, and pc back in main(). What does this show?

    Note: If you are unsure of the size of the pointers in a given operating system, simply use the sizeof() operator. This will return the size of the given item in bytes. For example, the code fragment,

    int x, *pc;
    
    x = sizeof( pc );
    printf(“Pointers are %d bytes\n”, x );
    

    may print 2 (Windows 3.1, Eeek!), 4 (Windows 95/XP, some UNIX systems) or 8 (true 64 bit operating systems). Note that pc could be a pointer to a float, double, char or anything, and it will still be the same size. This is a very important point to understand. Try using sizeof() to verify this.


    This page titled 5.1: Introduction is shared under a CC BY-NC-SA 4.0 license and was authored, remixed, and/or curated by James M. Fiore via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.