Pointers

J

j.wagner1024

Hi, I have started programming in C recently and started learning about pointers. Insofar, all the material has been easy to digest and understand. But pointers are really giving me a hard time! I've read quite a few articlesand some pdfs on pointers, but I'm still having trouble. If someone could point me to (no pun intended) some good tutorials or try to explain it, I'dbe indebted! Thanks!
 
E

Eric Sosman

Hi, I have started programming in C recently and started learning about pointers. Insofar, all the material has been easy to digest and understand. But pointers are really giving me a hard time! I've read quite a few articles and some pdfs on pointers, but I'm still having trouble. If someone could point me to (no pun intended) some good tutorials or try to explain it, I'd be indebted! Thanks!

Take a look at Section 4 on the comp.lang.c Frequently Asked
Questions (FAQ) page at <http://www.c-faq.com/ptrs/index.html>, and
post again if you're still puzzled. (The FAQ isn't a tutorial on
pointers, but it touches on a lot of their uses. You may find the
examples helpful.)
 
J

j.wagner1024

I read the entire FAQ for pointers, and I'm still stuck :(. What I (think) I understand is that when you declare pointer such as:

int *ptr;

Then that points the address of a variable and not the value inside the address. What I'm not understanding is, what do these do:

1. &ptr
2. null pointers
3.ptr++ vs ++ptr vs (*ptr)++ etc...
4. void *ptr
 
I

Ian Collins

I read the entire FAQ for pointers, and I'm still stuck :(. What I
(think) I understand is that when you declare pointer such as:

int *ptr;

Then that points the address of a variable and not the value inside
the address. What I'm not understanding is, what do these do:

"int*" is a type which is used to store the address of an int. Just
declaring one does not assign a value to it.

int n 42;
int *ptr = &n;

declares ptr as a pointer to int and initialises it with the address of n.

printf( "%d %d\n", n, *ptr );

will print "42 42"

This is the address of ptr.
2. null pointers

The null pointer is a pointer with a value of 0. Zero is nearly always
an invalid address, so it gets used as an error value for most
operations that return a pointer.
3.ptr++ vs ++ptr vs (*ptr)++ etc...

ptr++ and ++ptr increment the value of ptr be the size of the type it is
pointer to "move on to the next item" if p is pointer to something in an
array. (*ptr)++ increments the value pointed to by ptr.
4. void *ptr

"void*" is C's generic pointer type.
 
S

Shao Miller

I read the entire FAQ for pointers, and I'm still stuck :(. What I (think) I understand is that when you declare pointer such as:

int *ptr;

Then that points the address of a variable and not the value inside the address.

Roughly speaking:

A pointer is an object. An object contains a value. So: A pointer
object contains a pointer value.
What I'm not understanding is, what do these do:

1. &ptr

'&identifier' gives a pointer value, which points to the identified
object. Since 'ptr' is a pointer object, '&ptr' points to a pointer
object; a pointer to a pointer to an 'int'.
2. null pointers

A null pointer value means "points to no object nor function". A
pointer object can hold a null pointer value.
3.ptr++ vs ++ptr vs (*ptr)++ etc...

The first two increment a pointer value, which means "Increment 'ptr' to
point to the next 'int' object in the array of 'int' objects."
(Assuming there _is_ an 'int' array, and that you've pointed to one of
its elements.)
4. void *ptr

A 'void *' value points to any object, which means that since different
objects have different sizes, you cannot increment a 'void *'; there's
no way to know how to advance to "the next object" if you do not know
the size of each object.
 
E

Eric Sosman

I read the entire FAQ for pointers, and I'm still stuck :(. What I (think) I understand is that when you declare pointer such as:

int *ptr;

Then that points the address of a variable and not the value inside the address. What I'm not understanding is, what do these do:

Here, ptr is a variable. Its value (once you give it one) will
not be an int, but a value that locates an int somewhere else. By
way of analogy, ptr is a telephone number and the thing it points at
is the telephone.

Like most operators, the unary & operator produces a value. The
value it produces is a pointer to its operand, so &ptr is a value
that points at the variable ptr.

... which is itself a pointer, so maybe we're getting a little
deep for beginners. Let's go back to shallower water for a while:

int foo = 42;
int bar = 56;
int *ptr;

Here we have two int variables, each with its own integer value.
We've also got a pointer variable capable of pointing at ints, but
it hasn't been given a value yet (just as in `int x;' the x has
not yet been given a value). So, let's assign a value:

ptr = &foo;

The &foo part produces a pointer value aiming at the variable
foo, and then we store that value in ptr, making ptr point at foo.
Later on, we might change our mind:

ptr = &bar;

Again &bar produces a pointer value, this one aimed at bar, and we
store that value in ptr. Now ptr points at bar instead of at foo.

Why is this useful? Because we can do things like

printf("The Answer is %d\n", *ptr);

.... without caring whether ptr is aimed at foo or at bar or perhaps
at some other int altogether. The prefix * operator looks at its
operand -- a pointer -- finds out what it points at, and delivers
the value of the pointed-at thing. By using ptr, we can make this
single printf() call able to print the value of any int variable in
the program: We just aim ptr at it, and execute the call.

We can also use this on the left-hand side of an assignment:

*ptr = -17;

This stores minus seventeen in ... well, in whatever ptr is
aimed at when the statement is executed. We don't have to write
different assignments for foo and for bar, the same assignment
works for either of them -- or for anything else we've aimed ptr at.
2. null pointers

It's useful to have a special pointer value that means "I'm
not pointing at anything whatsoever." That's what a null pointer
is for; the FAQ goes into some detail on how they're used.
3.ptr++ vs ++ptr vs (*ptr)++ etc...

When the pointer's target variable is not isolated but is one
element of an array, it makes sense to do arithmetic on the pointer
values: "Whatever you're pointing at, find the next-door neighbor."
You can move forward and back in single steps with ++ and --, or
in larger steps by adding/subtracting bigger integers.
4. void *ptr

This is a special case: A pointer to something whose nature
is not stated. It might be pointing at an int, or at a char, or
at a float, or at anything at all. That flexibility makes it
useful for writing "generic" code that can operate on many different
kinds of data, rather than writing separate routines for int, char,
float, and so on.

The flexibility comes at a price: Since the type of the target
is unknown, you can't use *ptr to fetch a value from it, nor to store
a value in it. Nor can you do arithmetic on the pointer, since you
don't know how big a step takes you from one unknown-type variable to
its neighbors. You can pass arbitrary pointer values around in your
program by using void*, but you can't actually do much with them
until you say "Aha: I happen to know that the target is a double,
so I'll convert my void* to a double* and proceed."

... which brings up another part of the price: Loss of type
safety. Since you can convert any kind of data pointer to void*
easily, and then convert a void* to a data pointer again equally
easily, it's absurdly easy to get the types wrong. You start with
&foo (an int* from an earlier example), convert it to void*, then
arrive at the "Aha" moment and convert the void* to a double*. You
are now In Trouble, because you're trying to do double-ish things
on an int. It's like packing all the picnic lunches in identical
paper bags, then giving the ham and Swiss on whole wheat to the
vegetarian Jewish celiac sufferer because all the bags looked alike.
Be watchful always, and be extra watchful when converting pointers
from one type to another.
 
J

Joe Pfeiffer

I read the entire FAQ for pointers, and I'm still stuck :(. What I (think) I understand is that when you declare pointer such as:

int *ptr;

Then that points the address of a variable and not the value inside
the address. What I'm not understanding is, what do these do:

One small point: it *is* the address of the object it "points" to. To
digress, doing some assembly language programming did more to help me
understand pointers than anything else ever did.

That's the address of the pointer itself. Let's suppose you've got

int a;
int *ptr;
int **ptrptr;

Now you can say:
ptr = &a; // ptr is now contains the address of a --
// it's a pointer to a
ptrptr = &ptr; // ptrptr now contains the address of ptr --
// it's a pointer to ptr, or a pointer to a pointer
// to a


and we can make some assertions:
*ptr == a
*ptrptr = ptr
**ptrptr = a
2. null pointers

A pointer need not "point to" (contain the adddress of) any actual
object. We can set the pointer to NULL to give it a specific value we
can test against, to see if it's valid. It's really common that
functions that return a pointer (like malloc()) will return NULL to let
you know they've failed.

Unfortunately, there are myriad ways a pointer can just contain what
amounts to a random number; then it won't point to an object we'd like
it to, probably won't point to any object at all, and almost certainly
won't be NULL. Making sure an invalid pointer contains NULL is the
programmer's responsibility.
3.ptr++ vs ++ptr vs (*ptr)++ etc...

ptr++ : access the pointer, then increment it.
If you say
ptr2 = ptr++;
then ptr2 points to the object ptr used to point to, and ptr points to
the next object (I'll describe what the "next" object is in a moment)

++ptr : increment the pointer, then access it.
If you say
ptr3 = ++ptr;
then ptr and ptr3 both point to the next object.

The increment in these cases may not be by 1, like you'd (well, OK, like
I'd) expect. It's by the right amount to get to get past the object
you're pointing to.

So if ptr is a pointer to char like
char *ptr;
then the increment works like you'd think: it adds 1 to ptr.

But if it's a pointer to an int like
int *ptr;
and the system has four chars to an int (which is almost, but not quite,
universally true), then it increments by 4.

And if it's a pointer to some sort of struct like
struct bogus *ptr;
and struct bogus is 42 bytes (a number picked in honor of Douglas Adams,
whose birthday was yesterday), then it increments by 42.

*(ptr++)

dereferences the pointer, and then increments it. So going back to the
earlier example where
ptr = &a;
then
b = *(ptr++);
will set b to a, and then increment ptr to point to the next object of
the same size as a.
4. void *ptr

This amounts to being a pointer to an undefined type. The idea is that
a function like malloc() can return a plain ol' pointer, and let your
program deal with what type of pointer it is. So you can say things
like

int *ptr;

ptr = malloc(sizeof *ptr);

and
(1) the sizeof operator will understand that the size of what ptr
points to is 4 (if there are 4 chars to an int, as above), and
tell malloc() that you need an object of size 4 (in practice, an
object 4 bytes long).
(2) malloc() will return a pointer to 4 bytes in memory
(3) ptr will be pointed at these 4 bytes.
 
L

Les Cargill

I read the entire FAQ for pointers, and I'm still stuck :(. What I (think) I understand is that when you declare pointer such as:

int *ptr;

Then that points the address of a variable and not the value inside the address. What I'm not understanding is, what do these do:

1. &ptr

That is a pointer to ( a pointer to ) an int.

int **qtr = &ptr;
2. null pointers

NULL pointers are a marker for "this pointer points to nothing. Yet."
In many archiectures, dereferencing a NULL pointer would generate an
exception which would stop your program.

We're Pavlovian-ly conditioned away from this ( your program crashed! )
but it's really a *safety* thing - if the program tried to soldier on,
who knows what it might have damaged?

3.ptr++ vs ++ptr vs (*ptr)++ etc...

Post increment (ptr++) is evaluated after other things happen.
Pre increment (++ptr) is evaluated before other things happen.

(*ptr)++ is the same as ptr[0]++ - the thing pointed to by
ptr is incremented.
4. void *ptr


"... and the world was *void* and *without form*..."

A void * is an opaque type with no meaning which can be
converted to another type of pointer, but it's tactically
convenient for that type to not be specified then - like as an argument
to the compare function in qsort().

It means "we'll assign this to a meaningful pointer later on."

typedef struct {
....
int el;
....
} twoomba;

twoomba *t = (twoomba *)ptr;
// now it has a meaning.

*ptr = 0;
// there is no type void... error

t->el = 42;
// allowed.
 
B

Bart van Ingen Schenau

I read the entire FAQ for pointers, and I'm still stuck :(. What I
(think) I understand is that when you declare pointer such as:

int *ptr;

Then that points the address of a variable and not the value inside the
address.

You are slightly off with your understanding.
The most important thing to remember is that variables _store_ something.
If you have
int foo;
int *ptr;
then foo stores an integer and ptr stores the address of an integer
(pointer variables store addresses).

If you like real-world examples, then variables are like pieces of paper
with things written on them. An integer variable is then a piece of paper
with a number written on it. A pointer variable is then a piece of paper
with directions on it where to find something else, like your street
address if it is a pointer to your house, or where you left that piece of
paper with the number on it.
What I'm not understanding is, what do these do:

1. &ptr

That gives you the address of the pointer variable, so you can find out
where the pointer variable itself is located and possibly store it in
another pointer variable (one that stores pointer addresses, like `int
**bar`).
As C does not support pass-by-reference semantics for function arguments,
this can be useful if you want to pass ptr to some function that causes
it to point to some other integer. To see the change in the calling
function, you need to pass the address of ptr.
For example:

int a;
void assign(int** p)
{
*p = &a;
}
void foo()
{
int* ptr = NULL;
assign(&ptr);
// ptr now points at a
}
2. null pointers
A null pointer is a pointer that explicitly states that it points at
nothing.
The big advantage of null pointers over uninitialized pointers is that
you can actually test if a pointer is a null pointer.
3.ptr++ vs ++ptr vs (*ptr)++ etc...

Pointers can not only point to single values, but also to elements of an
array.
With ++ptr and ptr++, you go to the next element of the array (if you
remember the pointer pointing at your house, ++ptr makes it point to your
next door neighbor's house.
With (*ptr)++, you are dealing with two operators. operator* takes the
address stored in a pointer and gives you whatever is stored at that
address. In (*ptr)++, operator++ increments the result of operator*.

When multiple operators are used in an expression, you get to deal with
operator precedence (basically, which operator gets to do its job first).
That is too large a topic to cover here, so you should look it up in your
textbook.
4. void *ptr

A void* is special, because it stores addresses without knowing what
might be located at that location.
It could have been
anything *ptr
but for some reason they did not want to add to many keywords to the
language, so they decided to reuse the keyword void for this purpose.

Bart v Ingen Schenau
 
J

James Kuyper

The null pointer is a pointer with a value of 0. ...

That's true only in the sense that an integer constant expression with a
value of 0 is a null pointer constant, and therefore is converted to a
null pointer when used in an appropriate context. A null pointer need
not refer to memory address 0, and when stored in an object need not
cause all of the bits of that object to be 0, and there are real systems
where neither of those things are true.
... Zero is nearly always
an invalid address, ...

Possibly, though that's not guaranteed, and therefore not really
relevant. What's relevant is the fact, that is guaranteed by the C
standard, that a null pointer never compares equal to a pointer to any
object or function. It is used as a special pointer value to indicate
that the pointer doesn't point at anything.
 
A

army1987

That's true only in the sense that an integer constant expression with a
value of 0 is a null pointer constant, and therefore is converted to a
null pointer when used in an appropriate context.

And also in the sense that a null pointer is treated as false when used
as a condition.
 
J

j.wagner1024

On 13/03/2013 03:23, (e-mail address removed) wrote:
What have you read so far?

So far I've gone through a few pdf's, such as Gray Hat C, and C Programming, and I am currnetly working on Let Us C. I think I should probably read K&R next. Thansk for the link!
 
J

James Kuyper

And also in the sense that a null pointer is treated as false when used
as a condition.

The standard merely says "unequal to 0" in all of the relevant places:
!, &&, ||, ?:, _Static_assert(), if(), while(), do while(), for(). It's
the fact that 0 is a null pointer constant, and is therefore implicitly
converts to a null pointer whenever compared for equality with a
pointer, and the fact that all null pointers must compare equal, that
causes null pointers to be treated the same way as 0 in those contexts.
 
K

Keith Thompson

Shao Miller said:
Roughly speaking:

A pointer is an object. An object contains a value. So: A pointer
object contains a pointer value.

The unqualified word "pointer" is ambiguous; it could mean either
a pointer object (an object of pointer type) or a pointer value
(a value of pointer type). In fact, the C standard uses the word
"pointer" to refer to a pointer value not stored in any object;
see the description of the value returned by malloc, for example.

If there's any chance of misunderstanding (such as in a discussion
with someone who's still stuck on pointers), I suggest using the word
"pointer" only as an adjective, not as a noun: "pointer object",
"pointer value", "pointer expression", "pointer type".

[...]
 
K

Keith Thompson

Bart van Ingen Schenau said:
The most important thing to remember is that variables _store_ something.
If you have
int foo;
int *ptr;
then foo stores an integer and ptr stores the address of an integer
(pointer variables store addresses).

A clairification: foo stores an integer *value*, and ptr stores the
address of an integer *object* (or an integer variable).

[...]
 
J

James Kuyper

hey
this doesn't work in my enviorment.

What do you mean by "doesn't work"? Can you provide evidence supporting
that claim, such as a program with defined behavior that's inconsistent
with what he said?
*ptr is actually the value pointed to and ptr is the pointer.

Agreed - and he wrote nothing that's inconsistent with that statement.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top