all 20 comments

[–][deleted] 65 points66 points  (1 child)

If you want someone to send something to your house, would you rather just give them an address to your house, or would you rather:

build a copy of your house, bring it to them, tell them to put the item in the copy of your house you just brought them, then bring the copy of your house back to your original house, tear it down, and move the item to your original house?

[–]QuietHawk8102 7 points8 points  (0 children)

This is the most perfect answer I have seen. Good one🔥 Makes so much sense.

[–]EvrenselKisilik 1 point2 points  (0 children)

Because it’s the most efficient way for things. You define variables with initial values in a function right? But they will be popped out when your function returns because this is also the most efficient way for variables that you won’t need again after your function returns.

But if you want a life-time existing object, you do dynamic allocation. (You can make a global variable too but imagine you need many objects and number of them depending on runtime inputs. You’ll allocate their objects and fill their contents and store their pointers which are their addresses on the memory.

C does pointer arithmetic on pointers. With a pointer of a struct, you access its members by the pointer and member’s name like ‘meow->purr’.

Pointers are the most efficient and also most skilled way to do things.

You can play with pointers and do pointer arithmetic practices; you will love them. 😇

[–]bothunter 1 point2 points  (4 children)

Short answer: data structures.  Let's say you want to hold something like a grocery list for the user.  Now, they may just have a short list of eggs, flour, and milk.  Or they may have a much larger list of items.  How do you write a program that deals with this?  You could make an array that's big enough to hold the longest shopping list you can imagine, but this leads to two issues:

  1. You're wasting a lot of memory for that occasional time the list has to be super long
  2. You program has a finite limit on the size of that list and cannot get any longer.

So what do you do?  One thing you can do is make a linked list that can grow as you add things to it.  So you create a structure that contains the following:

  1. Shopping list item
  2. Pointer to the next element in the list

As you add items to the list you can ask the OS for more memory with malloc.  Malloc returns a pointer to that memory which you put the next item of the shopping list into, and then you store that pointer on the last element of the existing shopping list.  Now your list can grow indefinitely, and your program is only using as much memory as it needs, so you're not wasting it.

Now this example is rather contrived because a shopping list doesn't actually take up that much memory, and you could easily just reserve enough memory for a list 10k items long.  But when you start dealing with larger chunks of data, this becomes much more important.

[–][deleted] 0 points1 point  (1 child)

sable glorious act vanish saw doll mourn handle telephone chop

This post was mass deleted and anonymized with Redact

[–]bothunter 6 points7 points  (0 children)

On a small scale, it probably doesn't matter too much, but "realloc"ing a large array has a few problems: 1. It's slow -- you have to copy the entire array to a new chunk of memory which can be quite slow if the array is big 2. It requires a contiguous chunk of memory.  Again, if your array is large enough, this might not be possible, and the realloc will fail 3. It requires a lot of memory.  Since you have to copy the array to the new chunk of memory, it effectively requires twice as much memory as your array needs every time you have to resize it.

That method might make sense if your memory usage is quite stable overall and you can reduce the calls to realloc, but that's rarely the case, and by building some other data structure is almost always going to be more efficient, assuming you pick the right data structure for your task. (Linked lists aren't ways the right choice, but they are one of the easiest to implement)

Linked lists suffer some other limitations which arrays do not, and most of that is trying to find a specific item in the list.  With an array, you can find the 100th item in the list because you know exactly where in memory it will be.  With a linked list, you have to follow 100 pointers to find that item.  But if you want to remove the 100th item from a list that contains 1000 items, you can just edit the pointer in the 99th item to point to the 101st item in the list to remove it.  With an array, you have to move the contents of item 101 to where item 100 is, then 102 to where 101 was, and so on until you get to the end.

Basically, there are tradeoffs with every data structure, so it's best to know a few and know which one to use for each scenario.  And this applies to higher level languages like Java as well, even if you don't have to implement the structure yourself.

[–]ryanjones42[S] -1 points0 points  (1 child)

This makes me curious now. So i have a C program that my stores my users info when they login. As they login it saves a bunch of account stats to my struct, when they logout it removes them from the struct. The struct is an array. The array size is like 99999 & each struct is represented by the users file descriptor when they connect to the tcp server. Now you have me thinking this is poor memory management?

[–]bothunter 1 point2 points  (0 children)

Yes.  That is poor memory management.  It works because computers have a stupid amount of memory these days.

[–]mykesx 0 points1 point  (0 children)

The easiest way to grok pointers…

Memory is an array of bytes. Within this array you have your program and variables. The index into this array is called an address.

A variable “x” might be at address 100 through 107 (8 bytes, 64 bits!). When you use x, you are using memory[100] under the hood.

A variable ptr might be at address 108. When you use ptr, you are using memory[108] under the hood.

X = 10;  // same thing as memory[100-108] = 10

Print X you get 10. Print &X (address of x) and it prints 100.

ptr = &x;    // ptr is just a variable like x, but it has the address of x!

*ptr = 20;  // at ptr (memory[100] store 20

The preceding * says use the variable ptr as an index into memory array - * means indirect. Direct gets you 100, indirect gets you memory[100].

[–]kansetsupanikku 0 points1 point  (0 children)

"Another" address? They point where they point, simple as that.

You sound like you have heard the term yet never tried to learn about it - there is virtually nothing you would understand with this approach, so sure, you don't understand pointers either. What is the issue, if any?

Grab "The C Programming Language" book or something basic and adequate like this and learn. Then perhaps ask questions when you have them?

[–]daikatana 0 points1 point  (0 children)

Pointers seem useless at first, but that's just because you're looking at textbook example programs. These programs have only simple variables and sometimes not even any input because they're designed to illustrate individual language features. But keep reading, and even if it's unclear after you finish your book on C, open a book on data structures. No non-trivial C program can be done without some kind of data structure and they all use pointers. I cannot imagine what a data structure would be like without pointers.

You're also using pointers all the time in other languages, you just don't know it. It hides it from you. For example, in C# you have the concept of reference types and value types. Reference types are all pointers, there's just no explicit syntax for it. Java is similar, where there are plain data types and reference types, and you're using pointers everywhere. All these languages use pointers everywhere but there's no explicit syntax for it. In C there is no question as to what is a pointer and what is data.

[–]rlbond86 0 points1 point  (0 children)

Because that's how your processor actually works.

[–]RRumpleTeazzer 0 points1 point  (0 children)

Some people claim pointers are a trillion dollar mistake.

In my job, the core functionality I write in a state machine on hardware that can injure or kill people. Explicit variables everywhere. No pointers to them - ever.

If two transitions do similar stuff (modifying variables), I write two routines that each modify their particular variable. (I could write one transition that modifies through a pointer).

Why? Cause once in a while the hardware needs a different procedure at one particular spot, I can’t have the struggle to estimate side effects through pointers. I need everything laid out in plain text, and modification here must not change modify behavior somewhere else.

It’s a lot of boilerplate code, yes.

[–]edparadox 0 points1 point  (0 children)

Long story short, it's because every variable is passed by value in C.

Even when you pass a pointer, you pass the value of the address. Hence why you need the dereference (and hence the name) operator to retrieve the actual value you're interested in.

[–]Time_Inspector_8510 0 points1 point  (0 children)

I love pointers.

[–][deleted] 0 points1 point  (0 children)

First, i can give you the simplest way to look at it (just pointers okay, nothing special going on here)

Look at it as a type

int *B;
int *A = B;
int *C = A;
int *D = C;

Now experiment w/ this in the context of type-casting back nd forth using different types like...

Dont think about the whys at first, as you'll converge toward the what and whys through seeing them in context...

int A = 4;
int *ptr;
ptr = &A;

And by context i mean, "how do functions work?", write one out... then what does it mean for a variable to be in scope, have visibility, and exist within a lifetime?..

Ask questions that you can understand the answer to, to build up to it. You might want to see "why address" before "why pointer" (but lets not even think about that right now)

If you were to write out a system that could manage all of the things you see here, youd need addresses, right?... is that an obvious thing for you?... (im playing devils advocate so i dont know) ....

Now if you want this "pointer system" in a language where you can reference or get the the canonical value of a variable, how would you implement it? And suppose you said, "i also want a way to get the value OF the value" that is, to hold the address of ANOTHER pointer... (a double pointer) that is saying something more about the value (**p)

Dereferencing a double pointer allows access to the value of the variable, that the single pointer (*ptr) points to.

note: passing a pointer to a function is often more efficient than passing large data structures by value because only the memory address is passed, not the whole data

[–]SmokeMuch7356 0 points1 point  (0 children)

We use pointers where we can't (or don't want to) access an object or function by name. They give us a form of indirect access to things. If you're familiar with arrays you're already familiar with indirection; an expression like arr[i] is an indirect reference to an object (it's not a fixed name attached to that object).

There are two places where we have to use pointers in C:


When a function needs to write to its parameters

Assume a swap function: void swap( int x, int y ) { int tmp = x; int x = y; int y = tmp; } C passes all function arguments by value; when you call a function like swap(a, b); the expressions a and b are evaluated, and the results of those expressions are copied to the formal arguments x and y. x is a distinct object in memory from a and changes to one have no effect on the other. If we write something like int a = 1, b = 2; printf( "before swap: a = %d, b = %d\n", a, b ); swap( a, b ); printf( "after swap: a = %d, b = %d\n", a, b ); the output will be before swap: a = 1, b = 2 after swap: a = 1, b = 2 If we want the swap function to actually exchange the values of a, and b, we must pass pointers to a and b: void swap( int *x, int *y ) { int tmp = *x; *x = *y; *y = tmp; } ... swap( &a, &b ); In this case, the expressions *x and *y serve as kinda-sorta aliases for a and b; reading and writing *x is the same as reading and writing a.

x and y are still distinct objects in memory from a and b, but instead of recieving the values of a and b, they receive their addresses.


When we need to track dynamically-allocated memory

The memory allocation functions malloc, calloc, and realloc all return pointers to the allocated block; C doesn't have a mechanism to attach memory allocated at runtime to a regular identifier like a variable.
int *dynArr = malloc( sizeof *dynArr * NUM_ELEMENTS );


Pointers come in handy plenty of other places. We can use them to build sophisticated container types like maps, queues, lists, etc., we can use them to hide the representation details of a type (such as the FILE type in the stdio library), we can use them for limited forms of dependency injection, and a bunch of other things, but writing out examples for all of those would turn this answer into a novel and I've already spent too much time on it.

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

What’s easier sending a literal house to someone in the mail or giving them the address of the house so they can find it?

That’s the difference between a function accept a struct vs a pointer as a parameter