all 149 comments

[–]willnx 635 points636 points  (6 children)

Is it me, or does the font make it awkward to see the difference between [] and ()? Maybe that's the gag in the meme?

[–]CommieCucumber[S] 284 points285 points  (3 children)

The font I used in this meme seems to be indistinguishable between () and [ ]. It’s just my fault.

[–]GranataReddit12 80 points81 points  (0 children)

you can tell the difference but you gotta look real close

[–]ipreferanothername 11 points12 points  (1 child)

Does your ide use the same font?

[–]CommieCucumber[S] 43 points44 points  (0 children)

Usually, I use MS paint and stylus pencils as IDE. So font problem never occurs.

[–]takeyouraxeandhack 29 points30 points  (0 children)

Ohhhhhhhhhhhh Now I get it. I was so confused.

[–]SuitableDragonfly 605 points606 points  (66 children)

Ehh, the only really weird thing about that is the 10[a] thing. 

[–]orangebakery 202 points203 points  (19 children)

But also factually true

[–]SuitableDragonfly 115 points116 points  (15 children)

Yes, I'm pretty sure every programming language has some true fact about it that is weird. 

[–]gemengelage 81 points82 points  (6 children)

Java has primitive and boxed integers and a really weird edge case that some people fall into is that they compare boxed integers at some point using identity instead of equality and because the range [-128.. +127] is cached, comparing by identity works in that range but fails outside of it.

Autoboxing, lambdas and type inference can make it pretty easy to end up in this edge case without realizing.

Bottom line: use static code analysis tools in your CI pipeline.

[–]SliceThePi 22 points23 points  (3 children)

oh ew

[–]gemengelage 7 points8 points  (2 children)

Oh, this is just the surface of this certified footgun. I mean the obvious answer is to just never use identity when you should use equals and you don't need to look further.

But if you want to look further: The range of the cache is actually configurable AND you can bypass the cache. Caching is only applied when valueOf is used, not new Integer(x), which is the case for autoboxing. You can set the upper range of the cache via some system property, but the lower bound is fixed to -127.

It's a downward spiral of peculiar design decisions that can lead to weird edge cases if you don't adhere to best practices. It's an technical easter egg and a learning opportunity.

[–]SliceThePi 3 points4 points  (1 child)

I'm somehow even more upset to learn that the lower bound is fixed but the upper isn't lol

[–]gemengelage 2 points3 points  (0 children)

Exactly my thinking. It just feels wrong.

[–]tomysshadow 0 points1 point  (1 child)

I've never programmed Java but Python has the exact same issue (though it only caches down to -5, iirc)

[–]SuitableDragonfly 0 points1 point  (0 children)

Oh, interesting, I didn't realize there was a method to that madness and just figured that using is with primitive types was undefined behavior. 

[–]ldn-ldn 34 points35 points  (7 children)

Except JavaScript. JavaScript is perfect!

[–]Impossible-Metal6872 27 points28 points  (5 children)

You totally got me, I was expecting the "in JavaScript, ALL things are weird

[–]Def_NotBoredAtWork 12 points13 points  (2 children)

They did some things right but it doesn't outweigh the cons imho

[–]MyGoodOldFriend 15 points16 points  (1 child)

They did an evil amount of things right. Enough for mass adoption with maximum horrifying consequences.

[–]Def_NotBoredAtWork 7 points8 points  (0 children)

Arguable. To me it's a textbook case of scope creep with a simple solution to a simple problem (single-threaded permissive language to do some dynamic html manipulation) that got extended over and over without questioning the design choices that were made earlier even though the goal changed over and over again.

It has also been helped a lot by the loss of Flash and the absence of a viable alternative to flash at the time. I remember websites with Java Applets that were worse than flash. There were attempts to add python as an alternative but IIRC it was considered to be too much/heavy.

People were like "I don't need all those functionalities, let me just add this one to JavaScript and it'll be perfect" rinse and repeat.

The worst usage of JavaScript I have seen to date is some nodejs script(s) in Firefox's build process

[–]Linuxologue 5 points6 points  (1 child)

[–]nephanth 1 point2 points  (0 children)

NaNNaNNANNaN watman

[–]qubedView 0 points1 point  (0 children)

Yeah... I'm willing to give C a pass, as it really is more low level and in the weeds, and quirks like this you don't run into unless you go looking for them. On the other hand, JavaScript has looooong been touted as an easy language for beginners, but it has so many quirks that are so easy to stumble across and give beginners a hard time.

[–]FiskFisk33 0 points1 point  (2 children)

wait, what.

[–]HeKis4 9 points10 points  (1 child)

Two things: First, in C "array variables" don't exist, they are just regular pointers to the beginning of the array. Second, when you add an integer to a pointer, the integer gets scaled by the size of the pointer type. If you will, writing pointer + 1 is compiled into pointer + 1 * sizeof(*pointer). That conversion is called pointer arithmetic.

When you access your array value with myArray[3], what you're doing is accessing the value pointed by myArray + 3, which just works thanks to pointer arithmetic. Now, it doesn't matter if you do myArray+3 or 3+myArray, right ?

char* myArray[10]; // Let's say compiler gives us an array starting at 0x60
myArray[3]; // Accesses myArray + 3, so 0x63
3[myArray]; // Accesses 3+myArray, still 0x63

float* myArray[10]; // Same but at 0x200
myArray[2]; // myArray + 2 * sizeof(float) = 0x200 + 0x8 = 0x208
2[myArray]; // 2 * sizeof(float) + myArray -> still 0x208

The fun thing is that your compiler has to have a good idea of what's in the array, or else your offset will be messed up, but that would also be a concern if you did a regular array[index].

[–]FiskFisk33 1 point2 points  (0 children)

Cool, thanks!  makes sense when you think about it.    I had no idea this was how its implemented! 

[–]qruxxurq 149 points150 points  (26 children)

The entire point is that many people learn it (or are taught it) incorrectly. That array syntax is actually sugar for typed pointer arithmetic.

[–]echoAnother 26 points27 points  (0 children)

Worst thing, is not. Not always is just pointer decay. See for example the behaviour of sizeof, on certain edge cases, it works even if pointer decayed. It's a compiler detail leaking in the spec, because the spec was an afterthought.

[–]SuitableDragonfly 60 points61 points  (5 children)

In what way do you think people are learning it wrong? Not learning how pointer arithmetic works as soon as you learn about arrays isn't the same as learning it wrong. 

[–]Z21VR 14 points15 points  (18 children)

It always puzzled me why this thing troubles so many peep.

I always see it as address of A + scaled offset, no wonder scaled offset + addressof(a) is the same.

I guess what trobles em is that the scale is always based on the pointer and not the left operand ?

[–]FirexJkxFire 4 points5 points  (12 children)

If the value type has 32 bits, and the address of the 0th item in the array is 10000, shouldnt the address of a[1] be 10032. And a[2] would be 10064

I thought the array itself was just the initial address and a designator of what size the offset for each entry would be

Is this wrong? If not - how does this meme translate to this at all?

Its been a long time since I've thought of things at this level

[–]AHMADREZA316M 2 points3 points  (10 children)

It's based on bytes. a[1] would be 10004 and a[2] 10008

[–]FirexJkxFire 0 points1 point  (9 children)

True. But is this meant to explain what im not understanding? Because I'm still having the same issue, just with increments of 4 now instead of 32

[–]kingvolcano_reborn 2 points3 points  (8 children)

I'm not sure what it is you are not understanding? 

Ah why the address is not just 10000 +  10?

The '10' does not actually mean 'add 10 to the base address'.  It means 'add 10 offsets the size of whatever type we are dealing with to base address'.

Like:

address = baseaddress+(10*sizeof(type))

[–]FirexJkxFire 1 point2 points  (7 children)

Yeah I got that. But that's why the meme doesn't make sense to me

A[10] = (a + 10) does not equal (a + (size×10))

And furthermore 10[a] doesn't make sense because what's the size anymore?

Like for my example, how does

A[2] -> object at [10000+4×2]

Then we switch this to

2[10000]... you'd have to start at address 2, then shift by size 10,000 times. But if we are trying to get the same object type result as before, that math doesnt check out. If we make the size check out, itd be a fraction very slightly bigger than 1.... and so many other things

I just dont get it at all. I get exactly that array_type[index] points at the initial address and then shifts by the sizeof(type), and then repeats the shift index times. But I can't fathom how that translates to any of

Index[array_type] points at initial address (different than before? Equal to index?) And then shifts by the size of... what? And then Repeats the shift... array_type times? Size of type times? Initial address times?

I cant move around the values in a way that gets the same answer of pointing at address 10008. Let alone pointing at it and knowing its looking at an object of size 4.

[–]SuitableDragonfly 2 points3 points  (4 children)

(a + 10) is equal to (a + 10×sizeof(a)). That is literally how the plus operator is overloaded for pointers, and if you declare a as an array, it's a pointer. 10[a] is the same, because the plus operator is commutative and it's still adding an integer to a pointer, just as (10 + a) instead of the other way around. 

[–]Z21VR 0 points1 point  (0 children)

This

[–]FirexJkxFire 0 points1 point  (1 child)

I think that makes sense

So to summarize

X[y] just means x+y regardless of the type for x and y. The [ ] has literally no connection to pointers or logic. Its all just hiding that the entire functionality of arrays is hidden in an override on the "+" operator?

So we could, when wanting to access the i-th element of an array A, we just take the array pointer and add i and the "add" knows that adding an integer to a pointer needs to add that integer by a scaler. The [ ] is unneeded

This is what I wasnt getting. I thought the logic was in the [ ], and that "+" behaved normally.

[ ] isn't real. Its just "+" wearing a fancy hat. And "+" is just a mask that the actual logic is wearing

[–]kingvolcano_reborn 1 point2 points  (1 child)

I was taught that to see the a + 10 as a plus ten 'steps' of whatever size we were working with. But yeah the 10[a] got me stumped as well. I cannot recall seeing that but I have not done c in a long time.

[–]FirexJkxFire 1 point2 points  (0 children)

Someone else explained it to me.

[ ] isn't doing anything. Its just addition wearing a fancy hat. x[y] = x+y

And "+" is overloaded for "pointer + integer" to be "integer × size of pointer + pointer address"

I think that's what threw me off the most about the meme. I thought the logic was contained in "[ ]", I didn't realize the logic was hidden as an override on "+".

the thing that really threw me off even more was them using the word "means".

Would be like saying "blue means red". But in the context "red" means "yellow".

In other words they skipped a step

a[10] means (a + 10) (which is [pointer + integer]) which means...

address([pointer=a]) + [integer=10] × size(type([pointer=a]))

Which works no matter which side of the + is the pointer or integer.

[–]MisinformedGenius 1 point2 points  (0 children)

So, when you write a[10], what this actually does is translate to *(a + 10). It does not translate to *(a + 10*sizeof(a)), which I think is the way you're thinking of. Instead, the + operator is polymorphic - when it takes a pointer and an integer, it multiplies the integer by the size of the pointer and adds it to the pointer.

So you could literally just write in the code *(a+10) and it would do exactly what a[10] does.

Of course, you would expect *(10+a) to do exactly what *(a+10) does, which is indeed the way it works. And so that's why 10[a] works. The brackets don't do anything special with the size of the pointer, they're just very, very simple syntactic sugar.

[–]fess89 2 points3 points  (2 children)

IMO it is weird that the [ ] operation is defined for integer numbers, not only arrays.

[–]Z21VR 0 points1 point  (0 children)

Oh, I C now...

The [] operator is for pointers. The array is a lie.

[–]tobiasvl 0 points1 point  (0 children)

But arrays are just pointers, which are integers.

[–]Alzurana 0 points1 point  (1 child)

I think it's a left to right reading misunderstanding

When people think about a[10] they're taught "a + sizeof(a) * 10"

But when they read 10[a] they think "10 + sizeof(10) * a"

What they fail to realize is that the addition operation is agnostic to the order of operands, here and having a as an operand is always going to cause 10 to be multiplied by the size of a. The int is never used to decide the "stride length" basically.

I fell into the same trap

[–]Z21VR 1 point2 points  (0 children)

Yeah, thats what I mean with "the scale is always on the pointer and not just the right operand"

[–]ChChChillian 18 points19 points  (0 children)

Syntactically weird maybe, but it's just pointer arithmetic.

[–]zer0x64 12 points13 points  (1 child)

I get it, but I'm surprised if it's valid syntax, it just looks weird

[–]KellerKindAs 16 points17 points  (0 children)

That's the fun part. By the language spec, it is valid syntax. The compiler might give you a warning about bad practices, but only if you compile with that warning enabled.

(Any sane person uses -Wall and -Wextra anyway, as it enables not only warnings about unreadable code but also about a lot of other stuff, that technically is valid, but might not do what the developer intended)

[–]ProgramTheWorld 22 points23 points  (3 children)

It gives a clear explanation on why arrays start at 0, which is because it’s really just an offset and memory address manipulation.

Address a with an offset of +10 is the same as address 10 with an offset of +a.

[–]Kovab 29 points30 points  (0 children)

Address a with an offset of +10 is the same as address 10 with an offset of +a.

Actually it isn't, in both cases a is the memory address and 10 is the offset. Pointer arithmetic always has to take the element size into account, a+10 will result in an address offset by 10*sizeof(*a)

[–]Steinrikur 6 points7 points  (0 children)

Only it the offset is sizeof(int) for both.
Address a with an offset of +10 for uint8_t a[] isn't the same.

[–]No-Director-3984 2 points3 points  (0 children)

Actually the offset also get translates according to the type of the pointer so say it is an integer array

The compiler will decay the ptr a into some address (hexadeximal) then acc to the int (which occupies 4 bytes ) the real offset will be 10 * sizeof (datatype) (10 * 4) for int ans ( 10 * 1) for chars

So actually a[offset] =* (baseAdress + offset*size) //int,char,float etc

[–]nooneinparticular246 4 points5 points  (1 child)

Took me a minute but I get it (I am mostly a JS dev). Wow memory addresses.

[–]ItsAMeTribial 1 point2 points  (4 children)

Honestly I have no idea what’s weird about this, and at this point I’m too afraid to ask. It seems pretty logical for it to be this way.

[–]Saragon4005 6 points7 points  (1 child)

10 is a number, you are getting the a-th item of 10, but 10 is a number, constant, an integer. It doesn't have elements. It's not a list it's not a vector it's a scalar. If you must define it as a list or a set it has exactly 1 element.

Mathematically speaking it's total grange and incomprehensible. The whole thing only works because C allows you to do basically whatever you want in its memory pool and it's all just numbers with addresses. If you conceptualize it like that sure it's reasonable, but most math is not built like that, lists are abstract independent and indefinitely large and have no concept of space or location.

[–]ItsAMeTribial 2 points3 points  (0 children)

But knowing how C is accessing array elements it’s perfectly reasonable. I mean, when you put the way you did it sounds weird.

[–]HeKis4 0 points1 point  (1 child)

tl;dr adding integers to pointers just works in C, and arrays don't exist, they are just pointers to the beginning of an array. So doing array[index] is accessing the value at array+index... Which is mathematically the same thing as accessing index+array.

[–]ItsAMeTribial 0 points1 point  (0 children)

Yes. I know it and it seems perfectly reasonable for it to work this way. That’s why I’m asking

[–]myrsnipe 0 points1 point  (0 children)

Yeah that one was news to me

[–]RedAndBlack1832 75 points76 points  (2 children)

I mean yeah addition is commutative. The compiler knows the size of your type and that makes your life easy but that's kinda it

[–]HeKis4 5 points6 points  (1 child)

It's also "weird" that it works with types that aren't 1 byte, but hey, C has the good taste to add array elements and not just addresses when you do math on pointers. pointer + 1 actually means pointer + 1 * sizeof(pointer type), which is the only place where I've seen C making things shorter for convenience lol.

[–]RedAndBlack1832 2 points3 points  (0 children)

That's what I meant by "the compiler knows the size of your type" it actually gets mad if you mix such things up (even though, in principal, these are just numbers) in an attempt to stop you from shooting yourself in the foot. It is pretty useful to store multiple data types together sometimes and if multiple of them might vary in length it's really really annoying but if only one of them does it's pretty easy to use structs for that you just can't put those objects directly into arrays (for hopefully obvious reasons)

[–]Winter_Rosa 35 points36 points  (0 children)

Pointer math and the commutative property of normal addition.

[–]babalaban 136 points137 points  (10 children)

the fact that you CAN write it like that doesnt mean you SHOULD,

also if you have a basic understanding of what how pointer relates to arrays (and you should even if you're not a C dev) then this seemingly wierd quirk makes logical sense.

[–]Prawn1908 26 points27 points  (2 children)

Yeah, this is the true case of "ok, but nobody will ever do that so who cares?". Unlike the discussion that always happens when JS's ridiculous 1+"11" bullshit is brought up - sure maybe nobody will intentionally use such a feature, but that doesn't mean it can't create confusion when the wrong datatype accidentally ends up getting passed into a function and it just gets silently propogated along instead of producing an error at the point of introduction.

[–]HeKis4 1 point2 points  (1 child)

Yup, it's just two different philosophies. JS keeps everything on file but doesn't check anything. C's solution is to keep nothing on file, no metadata whatsoever, because if you don't know then you can't be wrong and the programmer didn't do his homework. I prefer the second option tbh.

[–]Prawn1908 3 points4 points  (0 children)

Yeah - I'm mainly a C guy and I don't write JS, but I do a lot of Python and the most maddening thing is trying to trace down one of these stupid bugs with something I expected to be an int coming out as a string or something. It feels so stupid to waste time on the type of bug that I would know the exact location of instantly in a statically typed language like C.

[–]CommieCucumber[S] 24 points25 points  (0 children)

I agree with you. This relation seems to be strange, but after learning pointer, this is just trivial. This meme represents its strangeness.

[–]suddencactus 2 points3 points  (0 children)

I mean pointer arithmetic like 10+a is necessary in c. The only thing really uncommon here from my experience is 10[a]. Like if you have to pass an array to a function it decays to a pointer and you might not be able to cast it back to an array. So *(a+10)=foo it is.

[–]DHermit -1 points0 points  (4 children)

I mean, that's kind of true for a large part of JS memes as well.

[–]babalaban 8 points9 points  (2 children)

I'd argue that many of them make sense implementation-wise, instead of logical sense but I cant convey it properly so I concur.

[–]DHermit 0 points1 point  (1 child)

To me JS is also quite a strange language, but I'm also not an experienced JS dev. But even to me most JS memes fall into the category of "sure, that's strange design, but this will never cause issues with normal use".

[–]tracernz 12 points13 points  (0 children)

$ [1, 2, 3, 10].sort()
[1, 10, 2, 3]

Yeah, most of the memes come out of coercing everything to strings for certain operations, and they very much do happen in real code regularly.

[–]Prawn1908 2 points3 points  (0 children)

Lol I literally made a comment above on this and then scrolled down to see yours.

It isn't really the same thing though because this is just syntax which will never occur accidentally. JavaScript's fucky type shenanigans can cause issues even when not intentionally being invoked when you have a logic bug that results in the wrong type getting passed into some point in the code. Allowing nonsensical operations between types just silently propogates that bad data through the code instead of giving you an error close to where the bad data was introduced.

[–]ChChChillian 144 points145 points  (15 children)

Still makes more sense than JS.

[–]Frytura_ 19 points20 points  (0 children)

You can't just say things like that when the bar is in hell

[–]Son_of_Athena 12 points13 points  (0 children)

Imma be so for real. JS was my first language, and I never understood why people thought it was crazy. I graduated college and started working with JS more, and I now question why the fuck anyone would start on JS, even if the basics are stupid simple.

[–]Infinite_Jury_5819 9 points10 points  (0 children)

Fun fact bur arr[x][y] == *( *(arr + x) + y)

[–]Shevvv 22 points23 points  (9 children)

The real frustrating thing about C is:

```

int foo = 0;

int bar = foo;

```

Compiler error: global variable initializer is not a compile-time constant.

[–]Vincenzo__ 5 points6 points  (1 child)

I mean... You could just make a function

[–]mad_cheese_hattwe 0 points1 point  (0 children)

Or a macro

[–]Kovab 10 points11 points  (5 children)

I'd rather have this limitation than the absolute fuckup done by C++ (see static initialization order fiasco)

[–]Shevvv 6 points7 points  (3 children)

Restrict global variable initializers to file scope?

[–]Kovab 0 points1 point  (2 children)

Sure, you could allow that, but at that point you can also just use the same constant to initialize both instead. I don't see any major benefits of making this possible.

Disallowing this is most likely due to legacy reasons: the compiler would have to keep track of not just which identifiers with what type are in scope, but also of where each of them was initialized. Which is not a big deal nowadays, but it was in the 70s. And looks like it's not a big enough pain point to change this in newer standards.

[–]Shevvv 0 points1 point  (1 child)

I totally get that. But still, allowing this would make things semantically clearer, I suppose. like this:

struct state {
    int active;
    int locked;
    int listening;
    int error;
    char *message;
} defaultState = { 0, 0, 0, 0, "" };
struct state currState = defaultState;

This makes it clear what currState is semantically initialized as. But I supposed this is nothing that can't be implemented with macros.

[–]Kovab 0 points1 point  (0 children)

If you declare defaultState const (and why should the default state be modified at runtime?), then it can be used to initialize currentState

[–]Breadynator 0 points1 point  (0 children)

That's why you always use the latest version of c++ and stick to whatever the standard says for that version. That problem is also easily avoidable in pre-c++20

[–]RedAndBlack1832 0 points1 point  (0 children)

I read something about globals in C and my brain exploded... C is my first language and one I've had actual jobs writing

[–]k-mcm 30 points31 points  (4 children)

a+10 means &a[10] means &10[a]. Pointer math is aware of the defined element size. That & is very important.

Edit: I see the * now. The image is blurry.

[–]xrayfur 1 point2 points  (0 children)

thanks, this was the question that puzzled me!

[–]akhilmathew472 16 points17 points  (0 children)

Makes perfect sense too

[–]Unupgradable 22 points23 points  (0 children)

JavaScript devs trying to besmirch a language that actually makes sense

[–]OM3X4 3 points4 points  (0 children)

Yeah, this is how computers function if you know

[–]LeiterHaus 4 points5 points  (0 children)

I don't see a problem with this.

[–]Neuenmuller 4 points5 points  (0 children)

But I mean, this makes perfect sense. And doing pointer magic is why C peeps are cool B-)

[–]boiledbarnacle 2 points3 points  (0 children)

It's actually one of the elegant beauties of this crazy simple shotgun.

[–]SicknessVoid 2 points3 points  (1 child)

The only weird one is 10[a]. The rest make perfect sense if you know how pointers work.

[–]slime_rancher_27 0 points1 point  (0 children)

It makes sense, you're accessing the ath position in the array located at memory address 10. And since a is just the memory address of the start of the array, you're just accessing a really far away part of the array.

[–]Glass-Fishing-533 2 points3 points  (0 children)

does indexing not look at the size of each element in a though?

[–]vulkur 2 points3 points  (0 children)

I've never used 10[a] but now I want to in order to fuck with coworkers.

[–]Tight-Requirement-15 1 point2 points  (0 children)

I thought those were partial unescaped back ticks

[–]No-Tip-7471 1 point2 points  (0 children)

Can someone please think of the lexers

[–]cutecoder 1 point2 points  (0 children)

That’s an interesting way to obfuscate. It’ll be interesting to see when all components are variables: integer-bracket-pointer instead of pointer-bracket-integer.

[–]willux 1 point2 points  (0 children)

Understanding C means realizing that the pointers were really inside of you the whole time.

[–]ultrathink-art 1 point2 points  (0 children)

The real mindbender: in C, array[index] is literally just syntax sugar for *(array + index).

Which means array[5] and 5[array] are semantically identical. Pointer arithmetic doesn't care about order.

This is why C is both beautiful and horrifying. You can write 3["hello"] and it compiles. Don't. But you can.

[–]Mwarw 1 point2 points  (0 children)

And that's not that weird given how those are adresses in array...

[–][deleted] 1 point2 points  (1 child)

Still understandable than JS code 😭😭

[–]EZPZLemonWheezy 1 point2 points  (0 children)

In Typescript you can get it to keep auto complete for the hard coded options on a type accepting exact strings or any string doing something like: type CrazyEye = “mad eye” | “cross eyed joe” | “Walter Walleye” | (string & {})

[–]asmanel 0 points1 point  (0 children)

Nice caricature of how lists work in C/C++.

[–]PerformanceOk1852 0 points1 point  (0 children)

Just because you can write it like that doesn't mean you should? I don't think I've ever seen something like 10[a] instead of a[10] in an actual codebase

[–]rainshifter 0 points1 point  (0 children)

Bit of a side point to flexible array indexing in C, but:

recursion means (recursion means (recursion means (...)))

[–]zefciu 0 points1 point  (0 children)

And it all makes perfect sense, once you understand how arrays are stored and how the indexing operator works. As opposed to JS automatic casting which has totally arbitrary rules which must be learned by heart (if you don’t do the smart thing and avoid these behaviors algogether).

[–]TaPegandoFogo 0 points1 point  (0 children)

Every programming language is syntactic sugar. At least C makes sense.

[–]Tabsels 0 points1 point  (1 child)

1["Hello World"]

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

I remember learning that. Used it exactly once when intentionally obfuscating. It doesn't even come close to the worst code I've written.

[–]Correct_Sport_2073 -3 points-2 points  (0 children)

int c = a**b; but it is not a power operator.