4. Pointers

comp.lang.c FAQ list · Question 4.1

Q: What are pointers really good for, anyway?


A: They're good for lots of things, such as:

(Note that this is hardly a comprehensive list!)

See also question 6.8.




comp.lang.c FAQ list · Question 4.2

Q: I'm trying to declare a pointer and allocate some space for it, but it's not working. What's wrong with this code?

char *p;
*p = malloc(10);


A: The pointer you declared is p, not *p. When you're manipulating the pointer itself (for example when you're setting it to make it point somewhere), you just use the name of the pointer:

	p = malloc(10);
It's when you're manipulating the pointed-to memory that you use * as an indirection operator:
	*p = 'H';

(It's easy to make the mistake shown in the question, though, because if you had used the malloc call as an initializer in the declaration of a local variable, it would have looked like this:

	char *p = malloc(10);
When you break an initialized pointer declaration up into a declaration and a later assignment, you have to remember to remove the *.)

In summary, in an expression, p is the pointer and *p is what it points to (a char, in this example).

See also questions 1.21, 7.1, 7.3c, and 8.3.

References: CT&P Sec. 3.1 p. 28




comp.lang.c FAQ list · Question 4.3

Q: Does *p++ increment p, or what it points to?


A: The postfix ++ and -- operators essentially have higher precedence than the prefix unary operators. Therefore, *p++ is equivalent to *(p++); it increments p, and returns the value which p pointed to before p was incremented. To increment the value pointed to by p, use (*p)++ (or perhaps ++*p, if the evaluation order of the side effect doesn't matter).

References: K&R1 Sec. 5.1 p. 91
K&R2 Sec. 5.1 p. 95
ISO Sec. 6.3.2, Sec. 6.3.3
H&S Sec. 7.4.4 pp. 192-3, Sec. 7.5 p. 193, Secs. 7.5.7,7.5.8 pp. 199-200




comp.lang.c FAQ list · Question 4.4

Q: I'm trying to use pointers to manipulate an array of ints. What's wrong with this code?

	int array[5], i, *ip;
	for(i = 0; i < 5; i++) array[i] = i;
	ip = array;
	printf("%d\n", *(ip + 3 * sizeof(int)));
I expected the last line to print 3, but it printed garbage.


A: You're doing a bit more work than you have to, or should. Pointer arithmetic in C is always automatically scaled by the size of the objects pointed to. What you want to say is simply

	printf("%d\n", *(ip + 3));	/* or ip[3] -- see Q 6.3 */
which will print the third element of the array. In code like this, you don't need to worry about scaling by the size of the pointed-to elements--by attempting to do so explicitly, you inadvertently tried to access a nonexistent element past the end of the array (probably array[6] or array[12], depending on sizeof(int) on your machine).

See, however, question 7.19b.

References: K&R1 Sec. 5.3 p. 94
K&R2 Sec. 5.4 p. 103
ISO Sec. 6.3.6
H&S Sec. 7.6.2 p. 204




comp.lang.c FAQ list · Question 4.5

Q: I have a char * pointer that happens to point to some ints, and I want to step it over them. Why doesn't

((int *)p)++;
work?


A: In C, a cast operator does not mean ``pretend these bits have a different type, and treat them accordingly''; it is a conversion operator, and by definition it yields an rvalue, which cannot be assigned to, or incremented with ++. (It is either an accident or a deliberate but nonstandard extension if a particular compiler accepts expressions such as the above.) Say what you mean: use

	p = (char *)((int *)p + 1);
or (since p is a char *) simply
	p += sizeof(int);
or (to be really explicit)
	int *ip = (int *)p;
	p = (char *)(ip + 1);

When possible, however, you should choose appropriate pointer types in the first place, rather than trying to treat one type as another.

See also question 16.7.

References: K&R2 Sec. A7.5 p. 205
ISO Sec. 6.3.4
Rationale Sec. 3.3.2.4
H&S Sec. 7.1 pp. 179-80




comp.lang.c FAQ list · Question 4.6

Q: Why can't I perform arithmetic on a void * pointer?


A: See question 11.24.




comp.lang.c FAQ list · Question 4.7

Q: I've got some code that's trying to unpack external structures, but it's crashing with a message about an ``unaligned access.'' What does this mean?


A: See question 16.7.




comp.lang.c FAQ list · Question 4.8

Q: I have a function which accepts, and is supposed to initialize, a pointer:

	void f(int *ip)
	{
		static int dummy = 5;
		ip = &dummy;
	}
But when I call it like this:
	int *ip;
	f(ip);
the pointer in the caller remains unchanged.


A: Are you sure the function initialized what you thought it did? Remember that arguments in C are passed by value. In the code above, the called function alters only the passed copy of the pointer. To make it work as you expect, one fix is to pass the address of the pointer (the function ends up accepting a pointer-to-a-pointer; in this case, we're essentially simulating pass by reference):

	void f(ipp)
	int **ipp;
	{
		static int dummy = 5;
		*ipp = &dummy;
	}

	...

	int *ip;
	f(&ip);

Another solution is to have the function return the pointer:

	int *f()
	{
		static int dummy = 5;
		return &dummy;
	}

	...

	int *ip = f();

See also questions 4.9 and 4.11.




comp.lang.c FAQ list · Question 4.9

Q: Suppose I want to write a function that takes a generic pointer as an argument and I want to simulate passing it by reference. Can I give the formal parameter type void **, and do something like this?

	void f(void **);
	double *dp;
	f((void **)&dp);


A: Not portably. Code like this may work and is sometimes recommended, but it relies on all pointer types having the same internal representation (which is common, but not universal; see question 5.17).

There is no generic pointer-to-pointer type in C. void * acts as a generic pointer only because conversions (if necessary) are applied automatically when other pointer types are assigned to and from void *'s; these conversions cannot be performed if an attempt is made to indirect upon a void ** value which points at a pointer type other than void *. When you make use of a void ** pointer value (for instance, when you use the * operator to access the void * value to which the void ** points), the compiler has no way of knowing whether that void * value was once converted from some other pointer type. It must assume that it is nothing more than a void *; it cannot perform any implicit conversions.

In other words, any void ** value you play with must be the address of an actual void * value somewhere; casts like (void **)&dp, though they may shut the compiler up, are nonportable (and may not even do what you want; see also question 13.9). If the pointer that the void ** points to is not a void *, and if it has a different size or representation than a void *, then the compiler isn't going to be able to access it correctly.

To make the code fragment above work, you'd have to use an intermediate void * variable:

	double *dp;
	void *vp = dp;
	f(&vp);
	dp = vp;
The assignments to and from vp give the compiler the opportunity to perform any conversions, if necessary.

Again, the discussion so far assumes that different pointer types might have different sizes or representations, which is rare today, but not unheard of. To appreciate the problem with void ** more clearly, compare the situation to an analogous one involving, say, types int and double, which probably have different sizes and certainly have different representations. If we have a function

	void incme(double *p)
	{
		*p += 1;
	}
then we can do something like
	int i = 1;
	double d = i;
	incme(&d);
	i = d;
and i will be incremented by 1. (This is analogous to the correct void ** code involving the auxiliary vp.) If, on the other hand, we were to attempt something like
	int i = 1;
	incme((double *)&i);	/* WRONG */
(this code is analogous to the fragment in the question), it would be highly unlikely to work.


comp.lang.c FAQ list · Question 4.10

Q: I have a function

	extern int f(int *);
which accepts a pointer to an int. How can I pass a constant by reference? A call like
	f(&5);
doesn't seem to work.


A: In C99, you can use a ``compound literal'':

	f((int[]){5});

Prior to C99, you couldn't do this directly; you had to declare a temporary variable, and then pass its address to the function:

	int five = 5;
	f(&five);
In C, a function that accepts a pointer to a value (rather than simply accepting the value itself) probably intends to modify the pointed-to value, so it may be a bad idea to pass pointers to constants. [footnote] Indeed, if f is in fact declared as accepting an int *, a diagnostic is required if you attempt to pass it a pointer to a const int. (f could be declared as accepting a const int * if it promises not to modify the pointed-to value.)

See also questions 2.10, 4.8, and 20.1.




comp.lang.c FAQ list · Question 4.11

Q: Does C even have ``pass by reference''?


A: Not really.

Strictly speaking, C always uses pass by value. You can simulate pass by reference yourself, by defining functions which accept pointers and then using the & operator when calling, and the compiler will essentially simulate it for you when you pass an array to a function (by passing a pointer instead, see question 6.4 et al.).

Another way of looking at it is that if an parameter has type, say, int * then an integer is being passed by reference and a pointer to an integer is being passed by value.

Fundamentally, C has nothing truly equivalent to formal pass by reference or C++ reference parameters. (On the other hand, function-like preprocessor macros can provide a form of ``pass by name''.)

See also questions 4.8, 7.9, 12.27, and 20.1.

Additional links: A message of mine further explaining how a function can modify a caller's passed array.

References: K&R1 Sec. 1.8 pp. 24-5, Sec. 5.2 pp. 91-3
K&R2 Sec. 1.8 pp. 27-8, Sec. 5.2 pp. 95-7
ISO Sec. 6.3.2.2
H&S Sec. 9.5 pp. 273-4




comp.lang.c FAQ list · Question 4.12

Q: I've seen different syntax used for calling functions via pointers. What's the story?


A: Originally, a pointer to a function had to be ``turned into'' a ``real'' function, with the * operator, before calling:

	int r, (*fp)(), func();
	fp = func;
	r = (*fp)();
The interpretation of the last line is clear: fp is a pointer to function, so *fp is the function; append an argument list in parentheses (and extra parentheses around *fp to get the precedence right), and you've got a function call.

It can also be argued that functions are always called via pointers, and that ``real'' function names always decay implicitly into pointers (in expressions, as they do in initializations; see question 1.34). This reasoning means that

	r = fp();
is legal and works correctly, whether fp is the name of a function or a pointer to one. (The usage has always been unambiguous; there is nothing you ever could have done with a function pointer followed by an argument list except call the function pointed to.)

The ANSI C Standard essentially adopts the latter interpretation, meaning that the explicit * is not required, though it is still allowed.

See also question 1.34.

References: K&R1 Sec. 5.12 p. 116
K&R2 Sec. 5.11 p. 120
ISO Sec. 6.3.2.2
Rationale Sec. 3.3.2.2
H&S Sec. 5.8 p. 147, Sec. 7.4.3 p. 190




comp.lang.c FAQ list · Question 4.13

Q: What's the total generic pointer type? My compiler complained when I tried to stuff function pointers into a void *.


A: There is no ``total generic pointer type.''

void *'s are only guaranteed to hold object (i.e. data) pointers; it is not portable to convert a function pointer to type void *. (On some machines, function addresses can be very large, bigger than any data pointers.)

It is guaranteed, however, that all function pointers can be interconverted, as long as they are converted back to an appropriate type before calling. Therefore, you can pick any function type (usually int (*)() or void (*)(), that is, pointer to function of unspecified arguments returning int or void) as a generic function pointer. When you need a place to hold object and function pointers interchangeably, the portable solution is to use a union of a void * and a generic function pointer (of whichever type you choose).

See also questions 1.22 and 5.8.

References: ISO Sec. 6.1.2.5, Sec. 6.2.2.3, Sec. 6.3.4
Rationale Sec. 3.2.2.3
H&S Sec. 5.3.3 p. 123




comp.lang.c FAQ list · Question 4.14

Q: How are integers converted to and from pointers? Can I temporarily stuff an integer into a pointer, or vice versa?


A: Once upon a time, it was guaranteed that a pointer could be converted to an integer (though one never knew whether an int or a long might be required), and that an integer could be converted to a pointer, and that a pointer remained unchanged when converted to a (large enough) integer and back again, and that the conversions (and any mapping) were intended to be ``unsurprising to those who know the addressing structure of the machine.'' In other words, there is some precedent and support for integer/pointer conversions, but they have always been machine dependent, and hence nonportable. Explicit casts have always been required (though early compilers rarely complained if you left them out).

The ANSI/ISO C Standard, in order to ensure that C is widely implementable, has weakened those earlier guarantees. Pointer-to-integer and integer-to-pointer conversions are implementation-defined (see question 11.33), and there is no longer any guarantee that pointers can be converted to integers and back, without change.

Forcing pointers into integers, or integers into pointers, has never been good practice. When you need a generic slot that can hold either kind of data, a union is a much better idea.

See also questions 4.15, 5.18, and 19.25.

References: K&R1 Sec. A14.4 p. 210
K&R2 Sec. A6.6 p. 199
ISO Sec. 6.3.4
Rationale Sec. 3.3.4
H&S Sec. 6.2.3 p. 170, Sec. 6.2.7 pp. 171-2




comp.lang.c FAQ list · Question 4.15

Q: How do I convert an int to a char *? I tried a cast, but it's not working.


A: It depends on what you're trying to do. If you tried a cast but it's not working, you're probably trying to convert an integer to a string, in which case see question 13.1. If you're trying to convert an integer to a character, see question 8.6. If you're trying to set a pointer to point to a particular memory address, see question 19.25.




comp.lang.c FAQ list · Question 4.16

Q: What's wrong with this declaration?

char* p1, p2;
I get errors when I try to use p2.


A: See question 1.5.




comp.lang.c FAQ list · Question 4.17

Q: What are ``near'' and ``far'' pointers?


A: See question 19.40d.





Read sequentially: prev next up



about this FAQ list   about eskimo   search   feedback   copyright

Hosted by Eskimo North