# Pointer, Array, String Review

Here, we review how to use basic pointers and arrays. We do not describe everything one might want to do with pointers or arrays.

1. Pointers to single objects:

The complete code we use in this section is available as ex1.c.

Suppose a `main()` function (or any other function) defines the following variables:

```int a = 8, b = -2;
int *ip;
```

These would look something like the following in memory:

```a @1000    b @2000
------     ------
|  8 |     | -2 |
------     ------

ip @3000
------
|    |
------
```

I.e., each variable is located at a certain point in memory (e.g., suppose `a` is at location `1000`, `b` at location `2000`, and `ip` at location `3000`).

The variables `a` and `b` have initial values of 8 and -2 respectively. The pointer `ip` has an arbitrary initial value.

Now, what would each of the following statements do:

• ```ip = &a;
```

This would make `ip` point to `a`. Graphically, this means we'd have:

```   a @1000    b @2000
------     ------
+->|  8 |     | -2 |
|  ------     ------
|
|  ip @3000
|  ------
+--+--  |
------
```

Another way to say this is that `ip` now holds the address of `a` (the ampersand (`&`) operator is what we used to get the address of `a`). So, we can also think of this statement as doing:

```a @1000    b @2000
------     ------
|  8 |     | -2 |
------     ------

ip @3000
------
|1000|
------
```

• ```*ip = 7;
```

Using the dereference operator (`*`) on a pointer gives you the thing it points to. Since `ip` currently points to `a`, the above statement effectively assigns the value 7 to `a`:

```a @1000    b @2000
------     ------
|  7 |     | -2 |
------     ------

ip @3000
------
|1000|
------
```

• ```ip = 5;
```

Unlike the previous statement, we have not used dereferencing. Thus, this is an attempt to give an integer value to a pointer. The compiler should at least warn us that the types are not compatible, since we should not do this.

Now, suppose we have two other functions in this program:

```void foo(int c)
{
c += 5;
}

void bar(int *jp)
{
*jp += 8;
}
```

What would happen when we performed each of the following statements in our `main()` function:

• ```foo(a);
```

Function `foo()` receives its integer parameter through a variable named `c`, so a new variable comes into existence and holds the value passed to it:

 Scope of main(): Scope of foo(): ```a @1000 b @2000 ------ ------ | 7 | | -2 | ------ ------ ip @3000 ------ |1000| ------ ``` ```c @4000 ------ | 7 | ------ ```

(Imagine that this new variable is at memory location `4000`.)

Now, when function `foo()` performs:

```c += 5;
```

it only affects its parameter `c`:

 Scope of main(): Scope of foo(): ```a @1000 b @2000 ------ ------ | 7 | | -2 | ------ ------ ip @3000 ------ |1000| ------ ``` ```c @4000 ------ | 12 | ------ ```

Finally, when the function `foo()` ends, its parameter `c` will no longer exist.

• ```bar(&a);
```

Passes `a` to `bar()` by reference. So, the parameter `jp` in `bar()` will hold the address of `a`:

 Scope of main(): Scope of bar(): ```a @1000 b @2000 ------ ------ | 7 | | -2 | ------ ------ ip @3000 ------ |1000| ------ ``` ```jp @5000 ------ |1000| ------ ```

(Suppose that `jp` is at memory location `5000`.)

Now, the statement in `bar()` that does:

```  *jp += 8;
```

does not change `jp`, but rather, the thing `jp` points to, i.e., `a` in `main()`:

 Scope of main(): Scope of bar(): ```a @1000 b @2000 ------ ------ | 15 | | -2 | ------ ------ ip @3000 ------ |1000| ------ ``` ```jp @5000 ------ |1000| ------ ```

Again, when the function `bar()` ends, its parameter `jp` will no longer exist.

• ```bar(ip);
```

This calls the same function but with a pointer variable, `ip`. Since `ip` currently points to `a`, and thus, so will `jp`, the function again changes `a`:

 Scope of main(): Scope of bar(): ```a @1000 b @2000 ------ ------ | 23 | | -2 | ------ ------ ip @3000 ------ |1000| ------ ``` ```jp @5000 ------ |1000| ------ ```

• ```ip = &b;
bar(ip);
```

Since `ip` now points to `b`, the parameter `jp` will receive `b`'s address. Thus, the function call will change `b` this time:

 Scope of main(): Scope of bar(): ```a @1000 b @2000 ------ ------ | 23 | | 6 | ------ ------ ip @3000 ------ |2000| ------ ``` ```jp @5000 ------ |2000| ------ ```

2. Pointers and Arrays:

The complete code we use in this section is available as ex2.c.

Suppose a `main()` function (or any other function) defines the following variables:

```double ar[4] = { 1.2, 3.5, -2.0 };
double *dp;
```

These would look something like the following in memory:

```ar @6000
---------------------
| 1.2| 3.5|-2.0| 0.0|
---------------------

dp @7000
------
|    |
------
```

I.e., the array `ar` has room for 4 elements (as its size indicated). Since only 3 initializers are given, the 4th position gets initialized to zero. The pointer `dp` is meant to point to the kind of things in the array, `double`s.

Now, what would each of the following statements do:

• ```ar[3] = 11.1;
```

Since `ar` is an array, we can use subscripts (in brackets, `[]`) to access an element, and for example, change its value. Now, we have:

```ar @6000
---------------------
| 1.2| 3.5|-2.0|11.1|
---------------------

dp @7000
------
|    |
------
```

• ```dp = ar;
```

Up until now, the pointer `dp` pointed to some arbitrary location. Now, we want it to point to `ar`. The above code achieves this by storing the address of the beginning of the array in `dp`.

```ar @6000
---------------------
| 1.2| 3.5|-2.0|11.1|
---------------------

dp @7000
------
|6000|
------
```

Notice that since the name of an array behaves like the "address of its first element" in certain contexts, we neither need or want to use ampersand (`&`) to take `ar`'s address, i.e., we just did:

```dp = ar;
```

• ```ar = dp;  /* Can't do! */
```

This is in fact illegal. Even though the name of an array behaves like the address of its first element in certain contexts, an array is not a pointer that can store different addresses. Thus, you cannot assign to the name of an array.

• ```*dp = 5.7;
```

This assigns 5.7 to the first element of the array:

```ar @6000
---------------------
| 5.7| 3.5|-2.0|11.1|
---------------------

dp @7000
------
|6000|
------
```

Again, using the dereference operator (`*`) on a pointer gives you the thing it points to. Since `dp` currently points to the first element of `ar`, the statement effectively assigns the value 5.7 to that element.

• ```dp[2] = 0.0;
```

This assigns 0.0 to the 3rd element of the array:

```ar @6000
---------------------
| 5.7| 3.5| 0.0|11.1|
---------------------

dp @7000
------
|6000|
------
```

Once a pointer is set to the beginning of an array, like `dp`, you can use that pointer to access the array in the same manner as you can use the array's name (above, for example, we use a subscript).

Equivalently, we could have done:

```*(dp + 2) = 0.0;
```

`dp[2]` and `*(dp + 2)` mean exactly the same things. I.e., subscripting is just shorthand for pointer arithmetic with dereferencing. For example,

```p[3]
```

means to create a new, temporary pointer that is 3 elements (not bytes) after where `p` points, then dereference that temporary pointer.

Now, suppose we add a function to print out all the values in a `double` array:

```void PrintEm(double br[], int n)
{
int i;

for (i = 0; i < n; i++)
printf("%f\n", br[i]);
}
```

Some things to note about `PrintEm()`:

• We want to pass an array of `double`s, so we declared its first parameter as:
```double br[]
```

The array size is not necessary inside of brackets. If we put a size, it won't even be used (we'll see why shortly).

• We need a 2nd parameter, the size of the array `n`. This is needed since there is no way to tell how big a passed array is. We'll need this to know how many elements to print.

• We use subscripting, `br[i]`, to access each element.

Now, to pass `ar` to `PrintEm()`, we'd do:

```PrintEm(ar, 4);
```

Since `ar` is an array and the function wants an array, it makes sense to just pass it along. When `PrintEm()` is called, its parameter `br` will come into existence:

 Scope of main(): Scope of PrintEm(): ```ar @6000 --------------------- | 5.7| 3.5| 0.0|11.1| --------------------- dp @7000 ------ |6000| ------ ``` ```br @8000 ------ |6000| ------ ```

You'll note however that `br` is not an array like `ar`. It's actually just a pointer, like `dp`. (Since it's really just a pointer, that is why we didn't have to give `br` an array size.)

This illustrates the different between using array notation to declare an array as a parameter versus as a local or global variable. When you do something like:

```int array[10];
```

as a local variable (in a function) or as a global variable, you really get an array. When you use that notation inside of a parameter list:

```void SomeFunc(int array[]);
```

you only get a pointer. I.e., arrays are always passed by reference, automatically.

So, it makes sense that we could just pass the array as:

```PrintEm(ar, 4);
```

since the name of an array, like `ar`, acts like the address of its first element in certain contexts...an address was exactly what `PrintEm()` was expecting since its parameter `br` really is just a pointer.

Now, let's perform some more statements:

• ```PrintEm(dp, 4);
```

This does exactly the same thing as the above statement:

```PrintEm(ar, 4);
```

since `dp` currently points to the beginning of `ar`.

• ```(*dp)++
```

This increments the first element of the array:

```ar @6000
---------------------
| 6.7| 3.5| 0.0|11.1|
---------------------

dp @7000
------
|6000|
------
```

You should read that statement as: "get what `dp` points to and then increment it."

• ```dp++;
```

This increments the pointer. I.e., it makes `dp` point to the next (2nd) element in the array. If `double`s are 8 bytes, that would give:

```ar @6000
---------------------
| 5.7| 3.5| 0.0|11.1|
---------------------

dp @7000
------
|6008|
------
```

Now, we said that the parameter `br` in `PrintEm()` is really just a pointer. So, we can write a second version of this function, `PrintEm2()` that makes that fact explicit:

```void PrintEm2(double *br, int n)
{
int i;

for (i = 0; i < n; i++)
printf("%f\n", *br++);
}
```

We now explicitly list the parameter as a pointer. Also, instead of using subscripting, we use some pointer arithmetic.

How should you read `*br++`?

Answer: Since there are no parentheses this time, you must go with operator precedence. But, `*` (dereferencing) and `++` (here, the post-increment) have the same precedence. So, you must go with associativity--they associate from right to left.

So, the first part to be done is "`br++`", which says to increment the pointer. But wait, its a post-increment, so we use it first... I.e., we use the variable to do `"*br"`, which means to use the `double` that `br` points to. Finally, we can do the post-increment and advance the pointer.

So, the expression "`*br++`" really means:

1. Use what `br` points to (i.e., print out that `double`).
2. Increment the pointer (i.e., make it point to the next `double`).

In summary, we now only use `i` to figure out how many elements to print. We use pointer arithmetic to advance from one element to the next.

We can now call this new version, `PrintEm2()`, passing along the array. Here are some statements that do that:

• ```PrintEm2(dp, 3);
```

Prints the last 3 elements in the array. Recall that `dp` now points to the 2nd element, so we skip the 1st one.

• ```PrintEm2(ar, 4);
```

Prints out all 4 elements in the array.

• ```PrintEm2(ar+1, 3);
```

Prints out the last 3 elements in the array. This time we use `ar` to construct the address of its 2nd element (i.e., +1 elements past the first one). Equivalently, we could have done:

```PrintEm2(&ar[1], 3);
```

since that is also a way to send the "address of the 2nd element".

3. Pointers and Strings:

The complete code we use in this section is available as ex3.c.

Although strings are stored in arrays, and thus, work like our array examples above, strings have a few special features:

• They use a special character, the nul character (`\0`), to represent the end of a string. Thus, we can figure out how big the string stored in an array is.

• There are a set of library functions (e.g., `strlen()`) that operate on strings of this form.

Now, suppose a `main()` function (or any other function) defines the following variables:

```char str[] = "cs113";
char *sp;
```

These would look something like the following in memory:

```str @9000
--------------------------
| c | s | 1 | 1 | 3 | \0 |
--------------------------

sp @10000
------
|    |
------
```

Note that the array has 6 elements, an extra one for the nul character.

Now, what would each of the following statements do:

• ```str[4] = '1';
```

We can access an individual character with the array name and subscripting. Above, we changed the 5th character:

```str @9000
--------------------------
| c | s | 1 | 1 | 1 | \0 |
--------------------------

sp @10000
------
|    |
------
```

Remember that this array holds characters, so we can assign characters (like `'1'`) to its elements.

• ```sp = str;
```

Up until now, the pointer `sp` pointed to some arbitrary location. The above statement makes it point to `str`:

```str @9000
--------------------------
| c | s | 1 | 1 | 1 | \0 |
--------------------------

sp @10000
------
|9000|
------
```

Again, no ampersand (`&`) is needed or desired.

• ```str = sp;  /* Can't do! */
```

Again, this is illegal since you can't move an array.

• ```*sp = 'm';
```

This assigns `'m'` to the 1st element of the array:

```str @9000
--------------------------
| m | s | 1 | 1 | 1 | \0 |
--------------------------

sp @10000
------
|9000|
------
```

• ```sp[1] = 'a';
```

This assigns `'a'` to the 2nd element of the array:

```str @9000
--------------------------
| m | a | 1 | 1 | 1 | \0 |
--------------------------

sp @10000
------
|9000|
------
```

Equivalently, we could have done:

```*(sp + 1) = 'a';
```

Now, suppose we add a function to print out the string (of course, `printf()` can do this already, but we'll do it ourselves character by character):

```void PrintStr(char astr[])
{
/* call strlen just once (more efficiency) */
int len = strlen(astr);
int i;

for (i = 0; i < len; i++)
printf("%c", astr[i]);

printf("\n");
}
```

Some things to note about `PrintStr()`:

• We use array notation for the parameter, but we know it will really just be a pointer.

• We use the library function `strlen()` for the length of the string (the length of "ma111" is 5). That's why we don't need a 2nd parameter, the size of the string.

• We use subscripting to access each character, as in "`astr[i]`".

Now, to pass `str` to `PrintStr()`, we'd just do:

```PrintStr(str);
```

When `PrintStr()` is called, its parameter `astr` will come into existence:

 Scope of main(): Scope of PrintStr(): ```str @9000 -------------------------- | c | s | 1 | 1 | 3 | \0 | -------------------------- sp @10000 ------ |9000| ------ ``` ```astr @11000 ------ |9000| ------ ```

Again, `astr` is not an array like `str`, but just a pointer.

Let's now write a second version of the printing function, `PrintStr2()` that takes advantage of this pointer:

```void PrintStr2(char *astr)
{
while (*astr != '\0')
printf("%c", *astr++);

printf("\n");
}
```

We've already used notation like "`*astr+++`" before. Moreover, this new version no longer needs `i`, `len` or `strlen()` to count until the end of the string. Instead, we just advance a pointer from one character to the next until we get to the nul character (`\0`).

We can now call this new version, `PrintStr2()`, passing along the array. Here are some statements that do that:

• ```PrintStr2(str);
```

Print out the whole string.

• ```PrintStr2(&str[2]);
```

Prints out the "111" part of the string. We could equivalently write that as:

```PrintStr2(str+2);
```

or even replace `str` with `sp` (since `sp` still points to the beginning of that string).

4. Final question:

So, pulling all that you have learned together, consider the following variable definitions:

```int m;
float fa[3];
char s[10];
```

How would you complete the following `scanf()` to read in: a value for `m`, the 2nd element in `fa`, and a string value for `s`?

```scanf("%__%__%__", __________, ___________, ___________);
```

BU CAS CS - Pointer, Array, String Review