[comp.lang.c] pointer increment

dkonerding@eagle.wesleyan.edu (08/12/89)

        Hi folks.  I'm a confused beginner C programmer who'd like to
understand pointer variables a bit better.  I have a small program.  I've done
the following:  int *ptr;

        Now, say I make ptr=1000 or hex 3e8.  I want to add one to the ptr, to
make it point to 1001, or hex 3e9.  Every time I do a ptr=ptr+1, it becomes
3ec.  How can I simply increment ptr by one?

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/12/89)

In article <484@eagle.wesleyan.edu> dkonerding@eagle.wesleyan.edu writes:
>  int *ptr;
>        Now, say I make ptr=1000 or hex 3e8.  I want to add one to the ptr, to
>make it point to 1001, or hex 3e9.  Every time I do a ptr=ptr+1, it becomes
>3ec.  How can I simply increment ptr by one?

Wu!  (If you're not familiar with Zen: that means you should unask your
question.)

C pointers are more abstract than machine storage addresses, and once
you properly grok them (look up "grok" in "Stranger in a Strange Land"),
they more naturally lend themselves to expressing object reference than
raw untyped addresses would.  If you're having to fight them, it's
probably a sign that you need to improve your understanding of them.

Except under extremely unusual circumstances, which as a C beginner
you are probably not faced with, proper use of pointers REQUIRES that
you not even consider what "numerical values" they are supposed to
have.  If you have a pointer to one of a contiguous series (i.e. an
array) of data each of which has type int, and you wish to make the
pointer point at the next member of the array, express that by
"adding one" to the pointer.  The meaning of "adding N" to a
pointer-to-a-whatever is to produce a pointer-to-the-whatever-N-
whatevers-farther-along-the-array.  Forget about machine address
arithmetic; of course there must be some going on behind the scenes,
but you're not supposed to consider how it's accomplished.

If you wish to access individual members of an array of bytes, use a
pointer-to-char instead of pointer-to-int.  In C, a char is a byte.
(A byte need not be 8 bits, although that is the size most commonly
encountered.)

If, instead of dealing with nice, regular arrays, you're really
trying to access a "misaligned" int datum using a pointer to an
aligned int as a starting point, then you need to convert the original
pointer-to-int to a pointer-to-char (-byte) to do the bytewise pointer
arithmetic, then convert it back again afterward.  This series of
operations cannot be made to work on some computer architectures.
(It is expressed by
	ptr = (int*)((char*)ptr + 1);	/* NON-PORTABLE */
which does as I just said.)  Be sure that you really need to do
this; in many years of varied C programming I've rarely needed to
do anything like that.

john@chinet.chi.il.us (John Mundt) (08/12/89)

In article <484@eagle.wesleyan.edu> dkonerding@eagle.wesleyan.edu writes:
>
>        Hi folks.  I'm a confused beginner C programmer who'd like to
>understand pointer variables a bit better.  I have a small program.  I've done
>the following:  int *ptr;
>
>        Now, say I make ptr=1000 or hex 3e8.  I want to add one to the ptr, to
>make it point to 1001, or hex 3e9.  Every time I do a ptr=ptr+1, it becomes
>3ec.  How can I simply increment ptr by one?


It is doing exactly what K & R want it to do.  When you do pointer
arithmetic, your addition is scaled by the size of the object the 
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pointer points to.  You must have a 4 byte int on the machine you are
using, since making ptr one larger caused it to point to the next int.

For example, if you had an array of pointers starting at memory location
1000, you'd have this:

1000+
0   4   8   12  16  20  24  28  32  36  40  44  48  52  56
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1st 2nd 3rd 4th 5th 6th 7th 8th 9th etc

*ptr would have the value held at 1000, *(ptr + 1) would hold the
value at 1004, *(ptr+2) the value at 1008, etc.

If you had made ptr a pointer to char, as in

char *ptr;

then doing ptr = ptr + 1; would give you 1001, since the size of a
char is one byte.

Alternatively, if pointer was a pointer to a structure

struct foo {			/* this structure is 40 bytes long */
	char foo1[20];
	char foo2[20];
} ary[2];

struct foo *ptr = &ary[0];	/* make ptr point to first ary */
				/* which we will assume as at 1000 again */

then ptr = ptr + 1 would equal 1040, since stepping ptr by one
moves it from the first structure to the second, which is what
we want to do. 
-- 
---------------------
John Mundt   Teachers' Aide, Inc.  P.O. Box 1666  Highland Park, IL
john@chinet.chi.il.us
(312) 998-5007 (Day voice) || -432-8860 (Answer Mach) && -432-5386 Modem  

cpcahil@virtech.UUCP (Conor P. Cahill) (08/12/89)

In article <484@eagle.wesleyan.edu>, dkonerding@eagle.wesleyan.edu writes:
>         Now, say I make ptr=1000 or hex 3e8.  I want to add one to the ptr, to
> make it point to 1001, or hex 3e9.  Every time I do a ptr=ptr+1, it becomes
> 3ec.  How can I simply increment ptr by one?

By declaring the pointer as char * ptr;

an increment of a pointer moves the pointer to the next occurance of the
item to which it points to.  In your case I am assuming an integer is 4
bytes and the compiler correctly moved the pointer to point to the next
integer that ptr may point to.  This goes the same for structures.

brian@trantext.UUCP (Brian Bainter) (08/13/89)

In article <484@eagle.wesleyan.edu>, dkonerding@eagle.wesleyan.edu writes:
> 
>         Hi folks.  I'm a confused beginner C programmer who'd like to
> understand pointer variables a bit better.  I have a small program.  I've done
> the following:  int *ptr;
> 
>         Now, say I make ptr=1000 or hex 3e8.  I want to add one to the ptr, to
> make it point to 1001, or hex 3e9.  Every time I do a ptr=ptr+1, it becomes
> 3ec.  How can I simply increment ptr by one?

You must realize what you are incrementing here. Since you are working with
an integer pointer here, you are incrementing the pointer to the next integer.
Since you seem to be working on a machine where integers are equivalent in
size to longs, your incrementation (is that a word?) of the pointer will place
you four bytes down the road (at the next integer position).

If you want a pointer to increment to the next byte, you must use a character
pointer of type "char *". Since character arrays are built on one byte
increments, incrementing a character pointer will place the pointer at the
next byte or character position.

The same holds true with any kind of pointer. If you have a pointer to a
structure of say 35 bytes, every time you increment the pointer, it will point
to the next structure of 35 bytes (unless you are working on a CPU similar
to the 68x00 family where odd word boundaries are not allowed which may place
each structure every 36 bytes apart).

The main thing to remember with pointer arithmetic is what type of variable
am I pointing to and how much memory does that variable take up, and when I
increment a pointer to that variable I will be incrementing the pointer by the
number of bytes the variable takes up times the number I am adding to the
pointer.

The same holds true with I believe any arithmetic operation done on a pointer
(add, subtract, multiply, devide, etc.).

Hope this helps,
-- 

Brian R. Bainter  KA7TXA
gatech!kd4nc!trantext!brian or
gatech!tomcat!brian

ping@cubmol.BIO.COLUMBIA.EDU (Shiping Zhang) (08/13/89)

In article <484@eagle.wesleyan.edu> dkonerding@eagle.wesleyan.edu writes:
>
>        Hi folks.  I'm a confused beginner C programmer who'd like to
>understand pointer variables a bit better.  I have a small program.  I've done
>the following:  int *ptr;
>
>        Now, say I make ptr=1000 or hex 3e8.  I want to add one to the ptr, to
>make it point to 1001, or hex 3e9.  Every time I do a ptr=ptr+1, it becomes
>3ec.  How can I simply increment ptr by one?

Points hold the locations or addresses of the varibles they point to.
So they change in units of the size (in bytes) of the varible type they
point to. On most of machines, the int size is 4 (bytes,or 32 bits).
So increasing a point to int by 1 advances the point to the address of
the next int, which is 4 bytes further, therefore the value of the point
is increased by 4.


-ping

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/13/89)

In article <10717@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> Wu!  (If you're not familiar with Zen: that means you should unask your
> question.)

Of course I meant "Mu!".  Another in a continuing series of misfiring
neurons in my memory circuits..

The proclaimed "meaning" given above has been challenged.  I don't claim
to be a Zen expert and may have misunderstood the koan that this relates
to.  On the other hand, Zen can't really be understood, so who knows.

I have no idea where followups on this topic should go.  (Probably there
shouldn't be any!)

wolfgang@ruso.UUCP (Wolfgang Deifel) (08/15/89)

dkonerding@eagle.wesleyan.edu writes:


>...  int *ptr;
>        Now, say I make ptr=1000 or hex 3e8.  I want to add one to the ptr, to
>make it point to 1001, or hex 3e9.  Every time I do a ptr=ptr+1, it becomes
>3ec.  How can I simply increment ptr by one?

    ptr is a pointer to an int or array of ints. When you add 1 or increment
ptr it always refers to the next element e.g. it becomes sizeof(*ptr) more.
If you want to increment ptr only by one you should use a cast.

    ((char*)ptr)++ ;
or
    ((char*)ptr) + 1 ;

Now ptr becomes 1 ( = sizeof(char) ) more.

----------------------------------------------------------------------------
Wolfgang Deifel
Dr. Ruff Software GmbH, 5100 Aachen, Juelicherstr. 65-67, W-Germany
uucp: ...!uunet{!mcvax}!unido!rwthinf!ruso!wolfgang - phone : +49 241 156038

chris@mimsy.UUCP (Chris Torek) (08/16/89)

In article <829@ruso.UUCP> wolfgang@ruso.UUCP (Wolfgang Deifel) writes:
>If you want to increment ptr only by one [byte] you should use a cast.
>
>    ((char*)ptr)++ ;
>or
>    ((char*)ptr) + 1 ;

The former is illegal: the result of a cast is an rvalue (thing that
goes on the right of an `=' sign), not an lvalue (thing that goes on
the left).  ++ may only be applied to lvalues.  Many compilers simply
got this wrong; at least one (gcc) allows it as an `extension', although
it is not clear to me what gcc might do with it on a machine in the
DG MV series, where a cast from (int *) to (char *) generates a
shift-and-mask sequence (possibly an efficient one; this one is
for demonstration purposes):

	/* char *cp; int *ip; cp = (char *)ip; more(); */
	load	reg1,-4(frame)		// fetch ip
	lsh	#1,reg1			// shift it left
	store	reg1,-8(frame)		// and store in ip
	call	more_

Perhaps on such a machine, gcc might compile `((char *)ip)++' as

	load	reg1,-4(frame)		// fetch ip
	lsh	#1,reg1			// shift it left
	call	more_

thus incrementing a temporary by one and then discarding the result.

(If gcc maps `((cast)(lvalue))++' internally to `{temp = lvalue;
lvalue = (cast)lvalue + 1; resultis temp;}', it would do something
a bit more reasonable---in the example I am thinking of, it would
result in incrementing the word-pointer ip by zero.  Word-pointers
on many machines simply cannot point to a byte within a word.  The
byte number, carried around in character pointers, is irrelevant
to the machine instructions that deal with words, and must be discarded
---in this example, by shifting right one bit.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

maart@cs.vu.nl (Maarten Litmaath) (08/16/89)

wolfgang@ruso.UUCP (Wolfgang Deifel) writes:
\...
\    ((char*)ptr)++ ;
\or
\    ((char*)ptr) + 1 ;
\
\Now ptr becomes 1 ( = sizeof(char) ) more.

Aaaaaaarrrrrgghh!  Wayne Throop's Sacred Mission isn't finished yet...
-- 
"Mom! Eric Newton broke the day! In 24   |Maarten Litmaath @ VU Amsterdam:
  parts!" (Mike Schmitt in misc.misc)    |maart@cs.vu.nl, mcvax!botter!maart

karzes@mfci.UUCP (Tom Karzes) (08/17/89)

In article <829@ruso.UUCP> wolfgang@ruso.UUCP (Wolfgang Deifel) writes:
>dkonerding@eagle.wesleyan.edu writes:
>If you want to increment ptr only by one you should use a cast.
>
>    ((char*)ptr)++ ;

This is not legal C, since a cast expression is not a valid LHS.  You can
no more use this than you can use:

    ((char *) ptr) = ...;

Some compilers may accept this, but it isn't legal C.

wolfgang@ruso.UUCP (Wolfgang Deifel) (08/18/89)

maart@cs.vu.nl (Maarten Litmaath) writes:

> I wrote:
>\...
>\    ((char*)ptr)++ ;
>\Now ptr becomes 1 ( = sizeof(char) ) more.

>Aaaaaaarrrrrgghh!  Wayne Throop's Sacred Mission isn't finished yet...
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Thank god that you are born as expert...

maart@cs.vu.nl (Maarten Litmaath) (08/22/89)

wolfgang@ruso.UUCP (Wolfgang Deifel) writes:
\maart@cs.vu.nl (Maarten Litmaath) writes:
\> I wrote:
\>\...
\>\    ((char*)ptr)++ ;
\>\Now ptr becomes 1 ( = sizeof(char) ) more.
\
\>Aaaaaaarrrrrgghh!  Wayne Throop's Sacred Mission isn't finished yet...
\ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
\ 
\ Thank god that you are born as expert...

There's no need to feel p*ssed off, Wolfgang; I wasn't trying to insult you
or something.
Of course I should have added a detailed explanation, but I figured someone
else would supply that.
Having read your article I remembered Wayne Throop's 1985 (1986?) crusade
against "the vile heresy which claimeth that ((char*)ptr)++ will increment
ptr" (free after Henry Spencer's Ten Commandments for C Programmers).

Allright.  A compiler that allows the abovementioned construct is wrong for
two reasons:

1)	It allows the `++' operator to be applied to an Rvalue expression;
	only Lvalue expressions may be operand of an increment operator, e.g.

		x++
		a[i]++

	This isn't so strange:

		x++
	
	is equivalent to

		x = x + 1

	which doesn't make sense for arbitrary (Rvalue) expressions.
2)	It increments the wrong variable; a cast is equivalent to an
	assignment to an invisible temporary variable (with the usual
	restrictions and conversions):

		foo	x;

		... (bar) x ...

	becomes

		foo	x;
		bar	cast_tmp;	/* `invisible' temp variable */

		... (cast_tmp = x) ...
	
	If we write the latter expression as

		(cast_tmp = x, cast_tmp)

	it's clearly `cast_tmp' which should be incremented (if a `++'
	operator is appended), were this possible at all; definitely NOT `x'.
-- 
"rot H - dD/dt = J, div D = rho, div B = 0, |Maarten Litmaath @ VU Amsterdam:
  rot E + dB/dt = 0" and there was light.   |maart@cs.vu.nl, mcvax!botter!maart