8
$\begingroup$

Thanks to feedback in this thread, I'm beginning to plan how to integrate a basic introduction to pointers into my unit on arrays. Here's a sample program I just wrote up:

#include <stdio.h>

int main(void)
{
    int number = 42;
    printf("Value of number: %d\n", number);
    printf("Address of number: %p\n", &number);

    int *pNumber = &number;
    printf("Value of number pointer: %p\n", pNumber); 
    printf("Value at address of number pointer: %d\n", *pNumber);    
}

I will probably add comments before actually presenting it and making it available to students. Seeing how the address of number and the value of pNumber always correspond will hopefully reinforce how pointers work. The first and last line will match as well. The idea is to show as clear and simple an example as possible.

My question comes in two parts:

  1. Is this an appropriate example for introducing pointers?

  2. Do you have suggestions for similar simple examples of basic pointer usage?

$\endgroup$
6
$\begingroup$

I would teach the use of arrays and array indices first (with pictures of a long row of physical mailboxes, or school lockers, etc.) Then later explain that all of a computer's and/or C program's (process) memory can be thought of as one big array with a pointer being a form of index (locker number) into that (virtual) memory array.

You can then draw a picture of how arrays of char (bytes) might be allocated in memory. And then show why pointers might be necessary in order to tell a standard string function how to find (or modify) a substring in an arbitrary C string array.

$\endgroup$
  • 1
    $\begingroup$ I would teach about the computer's memory as a big array first, then teach about how pointers and arrays interact with it. Because the memory is what is, and the notation is what works with it. Why does everyone want to go from Formal to Concrete, in complete defiance of Piaget? $\endgroup$ – user737 Jul 3 '17 at 17:06
  • $\begingroup$ An interesting question is whether memory is an example of a concrete array, or an array is an example of a concrete memory system (of capacitors, electron wells, magnets, sound waves, beads, knots, etc.) $\endgroup$ – hotpaw2 Jul 4 '17 at 15:27
  • 2
    $\begingroup$ How computers are constructed might change over time, but the ideas of variables and memory and pointers are unlikely to change. The students need to learn an abstraction in order to program, I am simply arguing for teaching the simplest and most straightforward and general abstraction possible. I have been thinking about a question along these lines, because it comes up a lot when teaching, but I have not finished formulating the question yet. $\endgroup$ – user737 Jul 4 '17 at 15:41
5
$\begingroup$

What you have there is an excellent start, and is completely appropriate. I would go next into a puzzle to try to get them hooked. I would type the following code in front of them on your projector, and ask them to pair with a neighbor to try to figure out what will happen next:

#include <stdio.h>

int main() {
    int a = 15;
    int b = 30;
    int c = 45;

    int *whatsthis = &a;
    printf("whatsthis is: %d\n",*whatsthis);

    whatsthis = whatsthis + 4;
    printf("whatsthis is: %d\n",*whatsthis);

    return 0;
}

(Depending on your compiler and environment, you may have to muck around with the code a bit to get 45 as your output for the second printf)

If your kids are like mine, they probably won't be able to figure this out. But once you compile it and execute, ask them to go back to their neighbor and try to figure out what in the world happened.

At this point, several of the groups should be able to figure out that it has something to do with the ints being stored next to each other, and, if pressed just a bit, that the number 4 was derived using the byte size of an int.

This gives you a perfect segue into arrays. Since you're taking all of this trouble to go into some depth (using references to get at arrays), I would try for a few takeaways from the lesson:

  1. Pointer arithmetic means changing the address you're looking at.
  2. The actual formula used to find the location of spot n in an array (which shows why that first address needs to be 0: (startlocation + (n * itemsize))
  3. Therefore, indexing in arrays can be characterized as a distance from the start.
  4. Array items are packed together with no wasted space and no separators between the data.
  5. That, in fact, these are the only two tools that computers possess to locate themselves in memory: having items packed next to each other so that they can go from one item to the next, to the next, or saving pointers in memory so that we can go back to places later. Every other thing that computers do with memory can be reduced to one of these two actions.
$\endgroup$
  • 2
    $\begingroup$ @Peter The code example is wrong, because the unit for pointer arithmetic is the size of the pointed-to type. whatsthis + 4 points 4 ints ahead of whatsthis (Or, rather, it would if whatsthis were pointing into an array large enough to do that. The code as written invokes undefined behavior.) $\endgroup$ – Eric M Schmidt Jun 18 '17 at 6:31
  • $\begingroup$ @EricMSchmidt I believe Ben I. was aware of this when posting the example. Even the undefined behavior can be teachable for students to learn pointers (and the precautions that one must take with them). At least I think this was intentional... $\endgroup$ – Peter Jun 18 '17 at 14:38
  • 1
    $\begingroup$ Yes, the undefined behavior was the purpose of the exercise. By arranging the demonstration so that the wrong variable gets modified, it should both pique their interest and give a great entrée to the idea of separating a memory address from the data it stores. $\endgroup$ – Ben I. Jun 18 '17 at 15:00
  • $\begingroup$ I don't get why you're adding 4 to go from a to c when they should be two addresses apart, and yet you say it's four bytes per int. Where is b, then? (Nevertheless, +1 for a great illustration.) $\endgroup$ – Wildcard Jul 25 '17 at 20:12
  • $\begingroup$ @Wildcard I tried to clarify the text. IIRC, on my compiler (I tested my code when I wrote this), ints were 2 byes. $\endgroup$ – Ben I. Jul 25 '17 at 20:44
4
$\begingroup$

I would use more visual examples that target conceptual knowledge first. I would do a TON of memory diagrams with code tracing. Then, introduce the idea of pointers as memory addresses like you do in your example.

I am a big fan of Nick Parlante's pointer materials. I know they are vintage at this point, but I haven't found anything better at explaining pointers conceptually or at targeting common pointer errors like dereferencing pointers that don't point to anything (seg fault!).

Binky Pointer Fun video

This claymation video (Original webpage, YouTube version in C) is hilarious and a crowd-pleaser, but also explains pointers conceptually---without talking about memory addresses explicitly. For that reason, it has versions in C, C++, Java, and more.

Three Pointer Rules

This is my version of Nick Parlante's Three Pointer Rules. Definitely see the Pointer Basics document for full details and the original rules.

1) Drawing Pointers and Pointees

Draw a pointer as a box. [C-specific modification] Before it points to anything, that box has a "?" in it.

int *x;

enter image description here

When you allocate memory (make a pointee), draw it in the heap. Setting that pointee equal to x makes an arrow go from the pointer to the pointee.

x = malloc(sizeof(int));

enter image description here

Dereferencing changes the pointee---the thing the pointer points to (see next rule)

*x = 42;

enter image description here

2) Dereferencing

The dereference operation starts at the pointer and follows its arrow over to access its pointee. Important: The dereference operation on a pointer only works if the pointer has a pointee -- the pointee must be allocated and the pointer must be set to point to it. You will save students so many seg faults if you emphasize this!

3) Pointer Assignment

Pointer assignment between two pointers makes them point to the same pointee. So the assignment y = x; makes y point to the same pointee as x.

Connecting Pointer rules to code

To drive it home, walk through code line-by-line while drawing diagrams. Have students work on their own code tracing and diagrams in groups.

Note that Nick Parlante emphasizes dynamically allocated memory in his code examples (malloc), and avoids the "address of" operator & . I think this is a smart choice because it's what is most common in real code. But of course & can be introduced in this method.

Here are some simple sample code snippets to start the walk-throughs and memory drawings:

// non-pointer code
double num;
num = 42.7;
printf(num);

// pointer code
double* num_ptr;;
num_ptr = malloc(sizeof(double));
*num_ptr = 42.7;
printf(*num_ptr);

// Binky's code
int* x;
int* y;
x = malloc(sizeof(int));
*x = 42;
*y = 13; // yes it crashes, but that's the point >:)
y = x;
*y = 13;
$\endgroup$
3
$\begingroup$

Yours is a fine first lesson, although it does not show the value of pointers. I would suggest also demonstrating how pointers can be used to implement a swap function.

Ask the students (or step them through) what this code does:

void swap(int x, int y) {
    int temp = x;
    x = y;
    y = temp;
}

int main() {
    int a = 1;
    int b = 2;
    printf("Before calling swap(): a = %d, b = %d\n", a, b);
    swap(a, b);
    printf("After calling swap(): a = %d, b = %d\n", a, b);
}

As you know, the local variables a and b do not get changed, because C uses call by value.

At that point, I show and discuss this cartoon:

Cartoon in which doctor tells patient: "Your x-ray shows a broken rib, but we fixed it with photoshop."

(This cartoon might be too risqué.)

I then teach and step through the correct way to write and call a swap procedure:

void swap(int *x, int *y) {
    int temp = *x;
    *x = *y;
    *y = temp;
}

int main() {
    int a = 1;
    int b = 2;
    printf("Before calling swap(): a = %d, b = %d\n", a, b);
    swap(&a, &b);
    printf("After calling swap(): a = %d, b = %d\n", a, b);
}

This provides a simple demonstration of the benefits of pointers and will help them understand why primitives (not counting pointers) are passed by value, while everything else appears to be passed by reference.

$\endgroup$
2
$\begingroup$

Obviously, beginners in C will have to deal with addresses and pointers really soon.

First, you owe them an explanation about adresses for

int aNumber;
scanf ("%d", & aNumber);   // an address  
printf("%s",   aNumber);   // a value

which will appear in your first examples. So the "address of" operator is known from the start.

Second, pointers appear as soon as you define functions with parameters "by reference".

Defining functions is a fundamental activity in programming. It is about giving names to pieces of code, thus introducing "user defined abstractions" to reduce the complexity of problems. And choosing them well so they can be reused. So the introduction of functions should come very quickly.

Third: historically arrays (in prehistoric C) were introduced after pointers. An array is (was) simply a pointer automatically initialized with the address of the first byte of an empty space automatically allocated on the call stack. Later in C it became a constant pointer (except in function parameters....). This poor conception explains why the arrays in C have a strange status (you can't assign them like structures, for example - but when you pass them as arguments, you dont need the stinking &) which is a difficulty for beginners. Maybe the problem is with the arrays, not with pointers.

Four: As long as you use pointers for arguments transmission, you don't have any necessity to talk about dynamic allocation, which is an entirely different topic. Except you use a pointer to store the result of malloc().

And last: another point is the data structures built from pointers (linked lists, trees,...) and the basic algorithms.

EDIT: as an answer to your question: in general I try to avoid artificial examples, because students don't see the link with their usual programming tasks. Function that modify their arguments are more natural: swaping/ordering things, modifying a struct, etc.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.