Pointers and Indirection The basics of pointers versus cursors (or, at the 6502 assembler level, the indirect indexed addressing mode versus the absolute indexed ones) were covered in This essay seeks to explain the uses of the indirect modes, and how to implement pointer operations with them. It does not seek to explain why you'd want to use pointers for something to begin with; for a tutorial on proper pointer usage, consult any decent C textbook.
The absolute basics A pointer is a variable holding the address of a memory location. Memory locations take 16 bits to represent on the 6502: thus, we need two bytes to hold it. Any decent assembler will have ways of taking the high and low bytes of an address; use these to acquire the raw values you need. The 6502 chip does not have any simple pure indirect modes (except for JMP, which is a matter for a later essay); all are indexed, and they're indexed different ways depending on which index register you use.
The simplest example When doing a simple, direct dereference (that is, something equivalent to the C code c=*b;) the code looks like this: ldy #0 lda (b), y sta c Even with this simple example, there are several important things to notice. The variable b must be on the zero page, and furthermore, it cannot be \$FF. All your pointer values need to be either stored on the zero page to begin with or copied there before use. The y in the lda statement must be y. It cannot be x (that's a different form of indirection), and it cannot be a constant. If you're doing a lot of indirection, be sure to keep your Y register free to handle the indexing on the pointers. The b variable is used alone. Statements like lda (b+2), y are syntactically valid and sometimes even correct: it dereferences the value next to b after adding y to the value therein. However, it is almost guaranteed that what you *really* wanted to do was compute *(b+2) (that is, take the address of b, add 2 to that, and dereference that value); see the next section for how to do this properly. In nearly all cases, it is the Y-register's version (Indirect Indexed) that you want to use when you're dealing with pointers. Even though either version could be used for this example, we use the Y register to establish this habit.
Pointer arithmetic Pointer arithmetic is an obscenely powerful and dangerous technique. However, it's the most straightforward way to deal with enormous arrays, structs, indexable stacks, and nearly everything you do in C. (C has no native array or string types primarily because it allows arbitrary pointer arithmetic, which is strong enough to handle all of those without complaint and at blazing speed. It also allows for all kinds of buffer overrun security holes, but let's face it, who's going to be cracking root on your Apple II?) There are a number of ways to implement this on the 6502. We'll deal with them in increasing order of design complexity.
The straightforward, slow way When computing a pointer value, you simply treat the pointer as if it were a 16-bit integer. Do all the math you need, then when the time comes to dereference it, simply do a direct dereference as above. This is definitely doable, and it's not difficult. However, it is costly in both space and time. When dealing with arbitrary indices large enough that they won't fit in the Y register, or when creating values that you don't intend to dereference (such as subtracting two pointers to find the length of a string), this is also the only truly usable technique.