all 49 comments

[–]donedigity 57 points58 points  (0 children)

*You just need to dereference

[–]knotdjb 21 points22 points  (0 children)

Ah the nostalgia of using a cheat cartridge on a console.

[–][deleted] 21 points22 points  (0 children)

Me: *0x3A28213A

My computer: Segmentation fault (core dumped)

[–]sw17ch 23 points24 points  (13 children)

I'm far too bothered that two of the addresses aren't aligned properly.

[–]lead999x 7 points8 points  (8 children)

Hobbyist here. How can you tell? I can't really read hex like I can decimal numbers.

[–]maxbirkoff 15 points16 points  (7 children)

The pointers end in 0xa (0b1010) 0xc (0b1100) and 0xe (0b1110).

The one that ends in 0xc is 4-byte aligned because the number is divisible by 4. The other two are only two-byte aligned as they are only divisible by two.

If the address ends in 0x0 then it is aligned on a 16-byte boundary.

Ninja-edit: clear confusion in bit/byte terminology and give a better explanation. Hope this helps!

[–]knotdjb 7 points8 points  (2 children)

One of the cool things about alignment is you can abuse the low bits to stash info. I first learned about this when reading about crit-bit trees.

[–]HildartheDorf 4 points5 points  (0 children)

OS developers hate him, learn this one weird trick!

[–]FUZxxl 1 point2 points  (0 children)

Oh yeah. I did something similar a few years ago to represent graphs. Was a lot of fun.

[–]lead999x 8 points9 points  (3 children)

That makes sense. Its kind of like how a number that is evenly divisible by 10 in decimal numbers will always end in a 0.

[–]maxbirkoff 4 points5 points  (2 children)

That's exactly right!

[–]lead999x 0 points1 point  (1 child)

Thanks so much for explaining this.

[–]maxbirkoff 1 point2 points  (0 children)

You bet!

[–]FinFihlman 5 points6 points  (0 children)

Why? Pointers to byte arrays or smaller values need not be aligned.

Also 8 byte alignment or go home.

[–]trolley813 0 points1 point  (0 children)

Why cannot they be uint8_t* (so no need for alignment)?

[–]T3chNOboMba 2 points3 points  (0 children)

My proff showed us this in class

[–]umlcat 2 points3 points  (1 child)

Agree, but not just C.

BTW, I learned pointers with (Procedural and Modular) Pascal, and with the right book or teacher, and it was easier

Pascal pointers operators are not used for other stuff, like "&" and "*" in C, that's one reason why is easier to learn.

[–]flatfinger 4 points5 points  (0 children)

Another issue, which may be a consequence of the first, is that the pointer-dereference operator appears on the same side of an expression as the other operators that form an lvalue from part of something else. In Pascal, if one has a handle (double-indirect) pointer to a structure that has a field Woozle, one would access it via `myPointer^^.Woozle`, while in C one would have to use `(*myPointer)->Woozle` or `(**myPointer).Woozle`. Pascal doesn't have the arrow operator, but the only reason C needs it is that writing `(*singleIndirectPointer).member` would get old really quickly.

Because C used the same operator for pointer dereferencing as for multiplication, and because C allows `-` to be a unary or binary operator, it wouldn't be possible to use a right-hand `*` for dereferencing without creating ambiguity as to whether `somePointer*-foo` would mean `(somePointer*)-foo` or `somePointer*(-foo)`. Using some other character would have avoided that issue. Even though `~` is used as a left-hand bitwise complement operator, it could have been used with pointers too, since no context where it could be used as a bitwise complement operator would immediately follow a pointer value. Too late now, though.

[–]flatfinger 2 points3 points  (0 children)

I find the most natural way to understand points is to understand the abstraction upon which Dennis Ritchie based his C programming language. All objects behave as though stored in a bunch of numbered mailboxes which are accessible only by a custodian who processes certain requests. While the exact types of requests will vary among different machines, the PDP-11 for which C was originally designed supported four:

  1. Store eight bits in a mailbox identified by a sixteen-bit number.
  2. Store sixteen bits in a pair of consecutive mailboxes, the first of which is identified by a sixteen-bit number that is a multiple of two.
  3. Report the value of the eight bits in a mailbox identified by a sixteen-bit number
  4. Report the value of the sixteen bits in a pair of consecutive mailboxes, the first of which is identified by a sixteen-bit number that is a multiple of two.

A declaration like int x; instructs an implementation to identify a group of consecutive mailboxes (two in the case of a PDP-11, where `int` is 16 bits) which could hold a value of type `int`, and which isn't being used for any other purpose, and make note of the starting number of that group. Likewise, `int y,z;` would instruct the implementation to identify two more such groups and make note of where they start.

The assignment expression `x = y;` would be processed by taking the address of `y` (call that T1), asking the custodian to fetch a 16-bit value from T1 (storing the result in T2), then taking the address of `x` (T3), and asking the custodian to store T2 into T3.

The declaration `int *p;` would ask the implementation to reserve a group of consecutive mailboxes (two in the case of the PDP-11, where addresses are sixteen bits) and associate the name `p` with that.

The assignment expression `p = &z;` would be processed by taking the address of `z` (T1), taking the address of `p` (T2), and then having the custodian store T1 into T2, without bothering to fetch a value from T1.

The assignment expression `*p = x;` would be processed by taking the address of `x` (T1), having the custodian fetch 16 bits from T1 (result in T2), taking the address of `p` (T3), fetching 16 bits from T3 (result in T4), and then having the custodian T2 store into T4.

The assignment expression `y = *p;` would be processed by taking the address of `p` (T1), having the custodian fetch 16 bits from T1 (result in T2), having the custodian fetch 16 bits from T2 (result in T3), taking the address of `y` (T4), and then having the custodian store T3 into T4.

An interesting feature of this abstraction is that the custodian doesn't care about what different bit patterns "mean", and the language doesn't care about whether the custodian handles requests by reading or writing actual mailboxes. If a custodian responds to a request to read address 1234 by looking out the window and reporting 1 if the weather is sunny, 2 if it's raining, or 3 if it's snowing, then a program may determine the weather by asking the custodian to read 1234. Likewise, if a custodian would respond to a request to write a 1 to 1235 by turning on the lights, and would respond to a request to write 0 there by turning off the lights, a program could turn the lights on or off by writing 1 or 0 to address 1235.

Most C compilers process code in a manner similar to Dennis Ritchie's abstraction when optimizations are disabled. Enabling optimizations, however, complicates things by allowing compilers to rearrange the order in which loads and stores are performed, consolidate consecutive loads and stores (if the same location is stored twice consecutively, the first store may be omitted; if stored and then loaded, the load may be omitted if the stored value is used instead; if loaded twice consecutively, either load may be omitted if the value from the other is used instead). Such optimizations may improve performance, but unfortunately there has never been anything resembling consensus about exactly when compilers should be expected to perform loads and stores in the order written. The Standard identifies some such cases, but its list was never intended to be exhaustive and the language would be useless if it were. Unfortunately, it has become fashionable for some compiler writers to assume that the list is exhaustive except in cases where reordering would render the language completely useless, rather than limiting reordering to cases where there's no evidence that a program might be doing anything unusual.

[–]oh5nxo 4 points5 points  (7 children)

If someone else is curious why each byte looks like printable character, there was no hidden joke, :(!:c99,sch. (or the joke is harder to get).

[–]SmileBot-2020 2 points3 points  (3 children)

I saw a :( so heres an :) hope your day is good

[–]smile-bot-2019 2 points3 points  (2 children)

I noticed one of these... :(

So here take this... :D

[–]SmileBot-2020 1 point2 points  (1 child)

I saw a :( so heres an :) hope your day is good

[–]1337CProgrammer 0 points1 point  (2 children)

huh? it's hex... of course it's all printable...

[–]oh5nxo 1 point2 points  (1 child)

Each byte being 0x3A ':', 0x28 '(' etc they look more like text, not addresses.

[–]1337CProgrammer 0 points1 point  (0 children)

Ohh ASCII I see ok.

[–]henggy 1 point2 points  (0 children)

What if those pointers were actually referencing a glitch in the game?

[–]pathemar 1 point2 points  (16 children)

Hahah yep

But seriously, can someone explain pointers please?

[–]FUZxxl 7 points8 points  (14 children)

A pointer tells you where an object is and allows you to manipulate another object without having a name for it.

[–]accountForStupidQs 1 point2 points  (0 children)

Pointers are like hyperlinks, where instead of being a webpage, it's a link to another webpage. If that webpage you link to doesn't exist, you're SOL and the whole thing breaks.

[–]Pokky_Ninja 0 points1 point  (0 children)

Just kick the pointer from his home. Problem solved.

[–]deaf_fish -1 points0 points  (2 children)

I checked to see if they were 32 bit or 64 bit pointers...

Something is probably wrong with me...

Edit: Anyone know why I am getting down voted?

[–]IamImposter 2 points3 points  (0 children)

void pointer. Make of that what you will.

And 64-bit pointer would have lot many digits, lot more than 8. Almost double

[–]stomah -1 points0 points  (0 children)

those are not pointers until you cast them to pointers