Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What do people find difficult about C pointers? [closed]

Tags:

c

pointers

People also ask

Why are pointers so difficult?

This complexity and the seeming (bold seeming) interchangeability with references ,which is often another caveat of pointers and an error of newcomers, makes understanding pointers hard.

Are pointers difficult to learn?

Pointers are arguably the most difficult feature of C to understand. But, they are one of the features which make C an excellent language. In this article, we will go from the very basics of pointers to their usage with arrays, functions, and structure.

What are the two common problems with pointers?

# What are the two common problems with pointers? Dangling pointers (dangerous) and Lost heap-dynamic variable.

Are pointers easy to understand?

Once you know how memory works, what's the stack, what's the heap, why there are different segments of memory, pointers will come easy enough, because as I said, the pointer itself is not really a complex concept, and neither is pointer arithmetic (which is just basic addition and subtraction).


When I first started working with them, the biggest problem I had was the syntax.

int* ip;
int * ip;
int *ip;

are all the same.

but:

int* ip1, ip2;  //second one isn't a pointer!
int *ip1, *ip2;

Why? because the "pointer" part of the declaration belongs to the variable, and not the type.

And then dereferencing the thing uses a very similar notation:

*ip = 4;  //sets the value of the thing pointed to by ip to '4'
x = ip;   //hey, that's not '4'!
x = *ip;  //ahh... there's that '4'

Except when you actually need to get a pointer... then you use an ampersand!

int *ip = &x;

Hooray for consistency!

Then, apparently just to be jerks and prove how clever they are, a lot of library developers use pointers-to-pointers-to-pointers, and if they expect an array of those things, well why not just pass a pointer to that too.

void foo(****ipppArr);

to call this, I need the address of the array of pointers to pointers to pointers of ints:

foo(&(***ipppArr));

In six months, when I have to maintain this code, I will spend more time trying to figure out what all this means than rewriting from the ground up. (yeah, probably got that syntax wrong -- it's been a while since I've done anything in C. I kinda miss it, but then I'm a bit of a massochist)


I suspect people are going a bit too deep in their answers. An understanding of scheduling, actual CPU operations, or assembly-level memory management isn't really required.

When I was teaching, I found the following holes in students' understanding to be the most common source of problems:

  1. Heap vs Stack storage. It is simply stunning how many people do not understand this, even in a general sense.
  2. Stack frames. Just the general concept of a dedicated section of the stack for local variables, along with the reason it's a 'stack'... details such as stashing the return location, exception handler details, and previous registers can safely be left till someone tries to build a compiler.
  3. "Memory is memory is memory" Casting just changes which versions of operators or how much room the compiler gives for a particular chunk of memory. You know you're dealing with this problem when people talk about "what (primitive) variable X really is".

Most of my students were able to understand a simplified drawing of a chunk of memory, generally the local variables section of the stack at the current scope. Generally giving explicit fictional addresses to the various locations helped.

I guess in summary, I'm saying that if you want to understand pointers, you have to understand variables, and what they actually are in modern architectures.


Proper understanding of pointers requires knowledge about the underlying machine's architecture.

Many programmers today don't know how their machine works, just as most people who know how to drive a car don't know anything about the engine.


When dealing with pointers, people that get confused are widely in one of two camps. I've been (am?) in both.

The array[] crowd

This is the crowd that straight up doesn't know how to translate from pointer notation to array notation (or doesn't even know that they are even related). Here are four ways to access elements of an array:

  1. array notation (indexing) with the array name
  2. array notation (indexing) with the pointer name
  3. pointer notation (the *) with the pointer name
  4. pointer notation (the *) with the array name

 

int vals[5] = {10, 20, 30, 40, 50};
int *ptr;
ptr = vals;

array       element            pointer
notation    number     vals    notation

vals[0]     0          10      *(ptr + 0)
ptr[0]                         *(vals + 0)

vals[1]     1          20      *(ptr + 1)
ptr[1]                         *(vals + 1)

vals[2]     2          30      *(ptr + 2)
ptr[2]                         *(vals + 2)

vals[3]     3          40      *(ptr + 3)
ptr[3]                         *(vals + 3)

vals[4]     4          50      *(ptr + 4)
ptr[4]                         *(vals + 4)

The idea here is that accessing arrays via pointers seems pretty simple and straightforward, but a ton of very complicated and clever things can be done this way. Some of which can leave experienced C/C++ programmers befuddled, let alone inexperienced newbies.

The reference to a pointer and pointer to a pointer crowd

This is a great article that explains the difference and which I'll be citing and stealing some code from :)

As a small example, it can be very difficult to see exactly what the author wanted to do if you came across something like this:

//function prototype
void func(int*& rpInt); // I mean, seriously, int*& ??

int main()
{
  int nvar=2;
  int* pvar=&nvar;
  func(pvar);
  ....
  return 0;
}

Or, to a lesser extent, something like this:

//function prototype
void func(int** ppInt);

int main()
{
  int nvar=2;
  int* pvar=&nvar;
  func(&pvar);
  ....
  return 0;
}

So at the end of the day, what do we really solve with all this gibberish? Nothing.

Now we have seen the syntax of ptr-to-ptr and ref-to-ptr. Are there any advantages of one over the other? I am afraid, no. The usage of one of both, for some programmers are just personal preferences. Some who use ref-to-ptr say the syntax is "cleaner" while some who use ptr-to-ptr, say ptr-to-ptr syntax makes it clearer to those reading what you are doing.

This complexity and the seeming (bold seeming) interchangeability with references ,which is often another caveat of pointers and an error of newcomers, makes understanding pointers hard. It's also important to understand, for completion's sake, that pointers to references are illegal in C and C++ for confusing reasons that take you into lvalue-rvalue semantics.

As a previous answer remarked, many times you'll just have these hotshot programmers that think they are being clever by using ******awesome_var->lol_im_so_clever() and most of us are probably guilty of writing such atrocities at times, but it's just not good code, and it's certainly not maintainable.

Well this answer turned out to be longer than I had hoped...


I blame the quality of reference materials and the people doing the teaching, personally; most concepts in C (but especially pointers) are just plain taught badly. I keep threatening to write my own C book (titled The Last Thing The World Needs Is Another Book On The C Programming Language), but I don't have the time or the patience to do so. So I hang out here and throw random quotes from the Standard at people.

There's also the fact that when C was initially designed, it was assumed you understood machine architecture to a pretty detailed level just because there was no way to avoid it in your day-to-day work (memory was so tight and processors were so slow you had to understand how what you wrote affected performance).


There is a great article supporting the notion that pointers are hard on Joel Spolsky's site - The Perils of JavaSchools.

[Disclaimer - I am not a Java-hater per se.]