Lecture #24: Arrays 2

December 1, 1999

Bob Pitha

bpitha@cs.ucsd.edu

http://www-cse.ucsd.edu/classes/fa99/cse5a

our story so far…

•      On Monday we began talking about arrays

•      An array is a group of one or more adjacent things in memory

–   they are all the same type

•   any of the 7 basic data types

•   pointers

•   arrays (we won’t tackle this yet)

•   other things we haven’t learned about

array recap: array declarations

•      We have to declare an array variable just like any other variable

       type name[size];

       type name[size] = { initializer list };

       type name[] = { initializer list };

–   common elements:

•   type: the data type of each element of the array

•   name: the name of the variable we are declaring

•   size: either explicit or implicit, it’s the number of elements

array recap: array definitions

•      As with other declarations, a defining declaration will reserve storage

–   this will allocate an adjacent block of memory large enough to store all elements of the array

–   all of the declarations we’ve seen (and probably will see) have been definitions

array declaration examples

•      Some examples of array declarations

double coordinate[3];

•   this defines an array named coordinate

–   each element is a double
–   it reserves space for 3 elements

int frequency [26];

•   this defines an array named frequency

–   each element is an int
–   it reserves space for 26 elements

int *pointer [6];

•   this defines an array named pointer

–   each element is a pointer to an int
–   it reserves space for 6 elements

array recap: using arrays

•      We can only do two things with arrays:

–   refer to an element of the array

•   we can then do lots of different things with that element

–   get a pointer to the first element of the array

array recap: subscript expression

•      We refer to an array element using a subscript expression

–   array_name[index]

–   details

•   the index is any expression with integral value

•   the index value selects a specific element of the array

–   the first element is index 0

•   a subscript expression is usually an lvalue

–   which means we can assign a value to an array element

array recap: subscript expression

•      Given the following declaration:

       int a[8];

–   it’s not illegal to use an index off the end of the array

•   but it may have undefined results, since it will mean you’re referring to memory that isn’t part of the array

•   we’ll see why this is legal a little later…

subscript expression examples

•      So remember our example declarations:

double coor[3];

int frequency [26];

int *pointer [6];

–   the following code is legal:

printf (“(%f, %f, %f)\n”, coor[0], coor[1], coor[2]);

for (i=0; i<26; ++i)

    frequency[i] = 0;

pointer[3] = &frequency[12];

array recap: array name as pointer

•      In many contexts, using the array name by itself gets you a pointer to the first element

int frequency [26];

int *pointer [6];

pointer[3] = &frequency[12];

pointer[2] = frequency;

so now back to our example

Text Box: #include <stdio.h>

int InputScores (double *);
void PrintStats (double *, int);

int main (void)
{
    double scores[250];
    int numScores;

    printf (“Scores: a program to compute grade statistics.\n”);
    printf (“Enter all scores, finish with –1:\n\n”);

    numScores = InputScores (scores);
    PrintStats (scores, numScores);
}
 


•      Note that we call the two functions with the argument scores

passing arrays

•      It is perfectly legal to put an array name into a list of arguments to a function

–   this is a value context

–   therefore, the array name expression becomes a pointer to the first element of the array

–   note that the prototype for InputScores looks like this:

Text Box: int InputScores (double *);
 


•      So when we pass an array into a function, we’re really just passing a pointer to the beginning of the array

passing arrays

•      Note the “difference” between passing a scalar variable and an array

–   up to now, when we put a variable name in an argument list, its value was passed to the function

–   with an array, what gets passed is a pointer

•      There’s no discrepancy here, really…

–   remember The Array Rule:

•   In a value context, the name of an array of type “array N of T” becomes a “pointer to T”

–   so in a manner of speaking, the “value” of the variable is the pointer to the first array element.

functions with array arguments

•      We’ve talked about passing arrays into functions, but what does it look like from the function side?

–   The function gets a pointer as an argument.

•   but we only know how to dereference a pointer to a single value

•   how does the function access the whole array?

arrays and pointers

•      Here’s where we start getting into the real overlap between arrays and pointers

–   remember I told you The Rule:

•   In a value context, the name of an array of type “array N of T” becomes a “pointer to T”

–   and remember the syntax of the subscript expression

array_name [index]

–   in fact, there’s nothing special about this use of the array name – it’s simply a value context too

say what?

•      A subscript expression is really a pointer expression, not an array expression

–   and to understand this, we have to delve into pointer arithmetic

pointers again

•      So far, we have discussed three operators that deal with pointers:

–   the “address-of” operator: &

–   the dereference operator: *

–   the assignment operator

•      There are other pointer operators you can use, including:

–   addition: +

–   subtraction: -

pointer arithmetic

•      The familiar arithmetic operators + and – can also be used with pointers

–   but there are rules…

–   I said that computer addresses are just numbers, but pointer arithmetic isn’t quite as simple as that…

pointer addition

•      One of the operands of + can be a pointer

–   but then the other operand must be an integer

–   and it doesn’t just add the integer to the address

•   instead, it adds the integer times the size of the thing the pointer points to

–   so given the declarations:

int i;

int *p = &i;

the logic of pointer addition

•      Why do things work this way?

–   remember, things are different sizes on different computers

•   so we can’t build into our programs an assumption that, say, ints are always 4 bytes long

–   plus, there’s array indexing…

•   you can step through an array by simply incrementing a pointer

•   adding 1 to a pointer gets you to the next “thing” in the array

–   whether it’s actually pointing to an array or not

pointer addition and array indexing

•      So given an array declared like this:

–   int a[8];

–   remember that using the array name by itself just gets a pointer to the first element

–   that means:

•  a is equivalent to &a[0]

•  *a is equivalent to a[0]

–   now if we mix in pointer addition:

•  a+1 is equivalent to &a[1]

•  *(a+1) is equivalent to a[1]

pointer addition and array indexing

•      In fact, the C language defines the subscript expression in terms of pointer addition

–   that is, the expression a[b] is identical to *(a+b)

•      So back to the original reason we brought up pointer addition:

–   you can use an array name or a pointer in a subscript expression, because to C it’s the same thing

•   it all becomes pointer arithmetic

some more details of pointer addition

•      If one operand of + is a pointer, the other operand must be an integer type

–   you cannot add two pointers

–   the data type of the expression is the same type as the pointer

•      It doesn’t matter what order you add the operands

–   p+i is the same as i+p

back to that locker analogy

•      Remember I’ve said that pointers are like locker numbers

–   pointer addition, then, is like finding a locker relative to another one

•   “5 lockers to the right of #371”

–   and as with pointer addition, it doesn’t make sense to add two locker numbers together