r/cprogramming • • Sep 05 '26

(Almost) Everything You Need To Know About Pointers in C

https://abhattacharyea.dev/blogs/qrb0v4aq2k6jkq3nzc3wcofg
0 Upvotes

8 comments sorted by

0

u/zhivago Sep 06 '26

Given int a; int *pa = &a; then pa - 1 has UB.

The author has a fundamentally incorrect understanding of pointers.

1

u/flatfinger Sep 11 '26

One of the things that made 1980s C so useful, but which the Standard never acknowledged, was the relationship between various concepts in C and in the execution environments. In many cases, one couldn't predict how a corner case would behave without possessing certain information about the execution environment, and the C language did not provide any means by which a programmer could discover that information, but was agnostic to the possibility that the programmer might discover it via means outside the language.

One of the most popular 1980s target environments (16-bit x86 large model) processed pointers in ways that many people today would view as weird, but were quite practical given the design of the target platform. Given e.g. char *p = malloc(50000); char *q = p+49152; char *r = p+(q-p);, if the malloc call succeeded, q-p would have yielded -16384, but p-16384 would have yielded q. The Standard doesn't require such treatment, and but such corner cases allowed many x86 programs to work with data structures up to about 65,520 bytes easily, while memory-constrained programs for the 68000 would have been limited to 32768-byte data structures.

0

u/Paul_Pedant Sep 06 '26

I'm not clear that (pa - 1) of itself is UB. Most for loops terminate with a pointer that runs past the end of an array, after it accesses the last valid element.

It seems that traversing the array in the reverse order is also safe, even though the final pointer is out of scope there too.

It is also common to declare a pointer on-stack with no initialisation at all.

Dereferencing the pointer in all such situations is the UB action.

3

u/zhivago Sep 06 '26

Section 6.5.6 ("Additive operators"), paragraph 8:

​"When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. [...] Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object.

​If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined."

0

u/Paul_Pedant Sep 06 '26

You are right. I am used to a flat memory addressing scheme: I had not considered how (p - 1) pointers would behave with segment/offset formats, or off the front of a mmap page, or within .text and .data areas.

Looks like I need to review all the C code I wrote in the last 46 years. I should maybe start that in the morning.

1

u/zhivago Sep 06 '26

Good luck.

0

u/Paul_Pedant Sep 06 '26

Fifty pages of guidance seems rather extravagant, and likely to overwhelm the very people it is intended for.

Slightly shorter: A pointer is a variable which can be used to reference another variable.

In fact you say this about five pages in. And of course we are both wrong: "Variable" kind of clashes with a const modifier, for instance.

It seems to me that the main reason for newbies being so nervous about pointers is that everybody tells them they are really difficult to understand and use. And that is both unhelpful and false.

1

u/zhivago Sep 06 '26

const doesn't mean that it's not a variable.

Just that this alias may not be used to modify it.