Live data from Hacker News

Beej’s Guide to C Programming [pdf]

beej.us

51–60 of 178 posts

Re: Beej’s Guide to C Programming [pdf]

#51
post #7

I've enjoyed this guide a number of times but each time I hit a brick wall trying to understand pointers. I'm still keen to learn but it just doesnt 'click' for me... Edit: poor grammar

Try watching this: https://youtu.be/443UNeGrFoM

Its long and is filled with other stuff about C programming but it goes in to dept about how to think about pointers. Good Luck!

Re: Beej’s Guide to C Programming [pdf]

#52

Earlier quoted context omitted.

Yup. I spent a ton of time trying to make sense of pointer syntax (* operator/modifier), until I realized that it didn't really make sense (except for the simplest cases) and then I could get on my life.

There's actually a logic to it, although not an intuitive one at all, and it's that declaration should follow use. That is `int *ptr;` is a pointer to an int and to get the int you have to use * on it.

The logic is that by declaring `int *ptr;` you effectively say that `*ptr` is an `int`. Only the first token (which must be a type) is syntactically special, the rest is normal expression syntax.

Same goes for arrays, `int *x[30]` just says that `*x[30]` is an `int` (well, technically it's out of bounds by 1), thereby we're declaring an array of 30 int-pointers.

Of course, that hasn't been entirely true since function declaration changed with ANSI C in the late 80s or so.

Re: Beej’s Guide to C Programming [pdf]

#53
post #30

Earlier quoted context omitted.

I don't disagree with that, but most cases fall within a pretty clear pattern: - typedef struct { ... } foo - foo *foo_create() - void foo_destroy(foo *) - a bunch of functions that take foo* as their first arg which is kind of the same as a class and only more error-prone. I say this as someone who actually _likes_ C, but the manual memory management model is very often unnecessary, confusing, repetitive. There was…

That's why I tend to always prefer automatic and static storage to dynamic allocation wherever possible, especially in cases where you don't have "N" items or "N" cannot possibly exceed a certain small value. Also, allocation/deallocation of the certain object need not be defined within its module. It should be up to the caller to decide whether to allocate the object on the stack, statically or dynamically depending…

That is of course fine, with the drawback that it requires a public definition of the foo type.

I would write the allocation as

    foo * const g = malloc(sizeof *g);
to avoid repeating the type name and "lock" the allocation to the variable. If the type on the left hand side ever would change, this still does the right thing.

Re: Beej’s Guide to C Programming [pdf]

#54
post #30

Earlier quoted context omitted.

I don't disagree with that, but most cases fall within a pretty clear pattern: - typedef struct { ... } foo - foo *foo_create() - void foo_destroy(foo *) - a bunch of functions that take foo* as their first arg which is kind of the same as a class and only more error-prone. I say this as someone who actually _likes_ C, but the manual memory management model is very often unnecessary, confusing, repetitive. There was…

That's why I tend to always prefer automatic and static storage to dynamic allocation wherever possible, especially in cases where you don't have "N" items or "N" cannot possibly exceed a certain small value. Also, allocation/deallocation of the certain object need not be defined within its module. It should be up to the caller to decide whether to allocate the object on the stack, statically or dynamically depending…

Interesting, I tend to prefer a create and destroy function that allocates and frees the structure. That way you can have foo without it being initialized, and you cant have foo been freed without being de-initialized. Where do see the value in being able to move it between different memory types?

Re: Beej’s Guide to C Programming [pdf]

#55
post #28
post #16

Earlier quoted context omitted.

What's difficult to understand about pointers isn't the concept of a pointer itself, or even * and &, it's the fact that working with pointers requires you to simultaneously understand different abstraction levels. While it's not unique to pointers, and it's in fact the case for most nontrivial programming tasks, what's unique about C is that pointers are so pervasive you can't really do anything if you don't underst…

These are good points. I can sometimes feel that Python is more pointer-y (?) than people expect, with stuff like: a = {"one": 1, "two": 2 } b = a b["two"] = 99 print(a["two"]) The above prints 99, since "b = a" does not copy the value (the dictionary) but just the reference to the value ("the pointer", kind of). This is surprising to some people.

Reminds me of the Python trap that I fall into every few months because I forget about it:

def foo(mylist=[]): mylist.append("a") return mylist

mylist is only initialized once, so the function will actually return one more "a" with each function execution

Re: Beej’s Guide to C Programming [pdf]

#56
post #6

IMO, pointers are less difficult to comprehend than other abstractions, like lambdas are. If you know how to walk down a street and stop at the right street number, then you have used pointers. And if you've ever observed that one tall building may "cover" a range of street numbers, such as 200-220, then you should understand how to move from one 4-byte "value" to the next in an array in memory. Anyway, many more ana…

C is an abstraction over assembly, really (benefits being that it is simpler by being more abstract and portable across CPU types).

I've always thought that an introduction to CPUs (can take a simpler one as example) and how they work, how memory is (usually) organised, and to assembly would go a long way in helping understand many programming issues and C.

My experience is that C or programming concepts are often taught in a very abstract/mathematical way, which can be hard to grasp compared to a more practical approach.

If you take a concrete example where memory is effectively an array and indices are addresses (which holds true for most cases and, in any case is a good example) then understanding pointers becomes basically common sense and notations are simply conventions of the language you're using.

Re: Beej’s Guide to C Programming [pdf]

#57

Earlier quoted context omitted.

Yup. I spent a ton of time trying to make sense of pointer syntax (* operator/modifier), until I realized that it didn't really make sense (except for the simplest cases) and then I could get on my life.

There's actually a logic to it, although not an intuitive one at all, and it's that declaration should follow use. That is `int *ptr;` is a pointer to an int and to get the int you have to use * on it.

But int-pointer is the type of it. It makes no sense that it “sticks” to the variable name.

Re: Beej’s Guide to C Programming [pdf]

#58
post #20

> It’s especially insidious because once you grok pointers, they’re suddenly easy. But up until that moment, they’re slippery eels. I'm sort of a C beginner myself. I understand pointers, and I do remember they clicked in my mind suddenly. The moment before, I didn't understand at all. I also love the quirkiness of this guide. Definitely going to give this a read.

Do you mean the general concept or like: a is a pointer to an array of functions which return pointers to functions which return ints and take double arrays as parameters. This somehow never really clicked (or actually it clicked and declicked somehow)

If you always read from right to left (and put occasional braces for readability) you can get through anything. Most tricky ones are in job interviews, while ones found in the wild will often make use of typedefs to break down the complexity.

Re: Beej’s Guide to C Programming [pdf]

#60

Earlier quoted context omitted.

That's why I tend to always prefer automatic and static storage to dynamic allocation wherever possible, especially in cases where you don't have "N" items or "N" cannot possibly exceed a certain small value. Also, allocation/deallocation of the certain object need not be defined within its module. It should be up to the caller to decide whether to allocate the object on the stack, statically or dynamically depending…

Interesting, I tend to prefer a create and destroy function that allocates and frees the structure. That way you can have foo without it being initialized, and you cant have foo been freed without being de-initialized. Where do see the value in being able to move it between different memory types?

Coming from the embedded world, I am far more used to the style bluetomcat showed where the caller handles allocation. It takes more work to use, and you have to make sure to not use it before initializing or after destroying, as you said. The advantage is that the caller has full control of memory allocation. The object can be a local variable, a static, malloc:ed, come from a custom allocator (say a slab allocator), or be a part of a larger struct.
Post reply on HN