Dereferenced vs non Dereferenced pointers ( and the explanation behind them ) [duplicate] - c

This question already has answers here:
Why Use Pointers in C?
(4 answers)
Closed 5 years ago.
Why is it we have to dereference a pointer ( that has already been linked to another variable ) every time we want to work on the variable its linked to? If there's a pointer that's linked to a variable ( an int for example ) isn't dereferencing it on-top of everything else a bit redundant? Do standard ( non-dereferenced ) pointers serve their own separate purposes? What can we do with a pointer that hasn't been dereferenced?
example : pPrice vs *pPrice
I'm learning my first programming language C and I've been wondering this for some time.

When working with people who haven't worked with pointers before, I like to point out that a pointer isn't special compared to other primitive types; it's simply an integer, just like ints or chars. What's special about it is how we interpret its value - specifically, we interpret its value as the location (address) of another value. This is a little bit similar to how even though chars are really just integers, we interpret them to be characters based the ASCII encoding. Simply because we interpret a pointer's value to be an address, we can perform operations such as reading or writing the memory at the address it's specifying.
Like you said, we can still access the pointed to memory as usual, but now we have some additional benefits.
For example, we can change the pointer's value, thereby pointing it to a different place in memory. This might be useful if we want to write a generic function that modifies a given object, but you want to dynamically decide which object to pass to it.
Also, the pointer itself is a constant, defined size (usually 32 or 64 bits), yet it could point to an object of any arbitrary size (e.g. a vector, string, or a user defined type). This makes it possible for us to pass around or store a handle to the object without passing/storing the entire object, which might be expensive.
I'm sure there are a million more use cases that I'm leaving out, but these are a couple to get you started.

tl;dr: An integer variable is distinct from a reference to an integer variable.
In C, the idea of a "variable" is very specific. In reality, it is the area in memory which holds the value of a variable. The symbol is a convenient symbol name by which the C code can refer to the value, to the content of the memory area. A "reference" is the address of the memory location. Since C is strongly typed, each symbol indicates how to interpret the memory to which it is associated. (Whew!)
So,
int i;
i refers to a memory location which holds an integer.
i=5;
fills that memory location with the binary representation for 5.
int *p;
means p is associated with a memory location which contains a pointer (aka address) to an integer location. So we can write,
p = &i;
where &i is the explicit address of the memory location of the integer value. So, p and i refer to quite different kinds of things. Since p is the address of an integer, we can dereference it (i.e., follow the address) to get to the actual integer value at the address location (the one assocated with i).
*p = 6;
i = 6;
Both assignment statements are functionally equivalent (they both set the same memory location to integer 6) since both i and the dereferenced p, *p, refer to the same memory location. Noteably, i is inextricably tied to the memory location, while *p can point elsewhere (though, p is inextricably to the integer-pointer memory location that refers to integers).

pPrice may be modified to point to a different price.
int a = 1,
b = 2,
*p = &a;
printf("%d\n", *p);
p = &b;
printf("%d\n", *p);

Related

How do I get the address of the value that a pointer is pointing to in C?

I'm trying to get the address of a value which I'm not allowed to directly reference to.
int main() {
int a = {1, 2, 3, 4};
int* ptr = &arr[0];
// ptr is incremented an unknown number of times
}
After the pointer has moved an unknown number of times, I need to know the address of the value the pointer is pointing to. Say if *ptr is now 3, I need to know the address of 3 without referencing the array. Is it possible?
An address must point at an object or function, and is thus also known as a pointer to object or function. Let's deconstruct your question into premises:
¹/ you have an int, just one (not an array) with extra (erroneous) initialisers. That's a bit strange. Maybe you meant int a[] = /* ... */. On this note, there is no 3 stored because you only have space for one value in this object.
²/ you have a pointer to int object, this is called ptr and it's initialised to &a[0], which is a reference op &a combined with a dereference op ([0]); these ops cancel each other out so your ptr declaration is actually equivalent to int *ptr = a;, which is also erroneous. Perhaps you meant int *ptr = &a; or, assuming you corrected the declaration for a (as per point 1), then your code (or the shorthand version, without the unnecessary dereference+reference) is okay.
I need to know the address of the value the pointer is pointing to.
As previously noted, pointers don't point at values; they point at objects or functions (or nothing or garbage, both exceptions for which this question isn't relevant)... and addresses are pointers that point at objects or functions, so if you have a pointer pointing at an object you already have the address.
Say if *ptr is now 3, I need to know the address of 3 without referencing the array.
You already have the address, and you're dereferencing it (*ptr) to obtain the value; ptr is storing an address, right? This is why Jonathan Leffler commented describing this question as tautologous; the very pointer you dereference to obtain the value is also (by definition) an address for the object you intended to be storing 3.
Your confusion is common and (among other common confusions that you're bound to ask about) would be best corrected by a decent textbook, such as K&R2e (do the exercises as you stumble across them). Alternatively, there are literally hundreds of frequently asked questions; you could read the 220ish pages and it'd be quicker and more reliable than asking all of these questions and trusting all of the answers...

Is a pointer variable treated differently in memory than a normal variable, in C?

I'm trying to wrap my head around pointers but it's confusing at the moment.
When a C compiler comes across a variable in memory it naturally reads the value present. If "X" was equal to 8 then the value of X would be read out as 8.
But when a compiler comes across a pointer in memory, it doesn't read the value of the pointer (the value of the pointer is random) but it instead goes to the address stored in the pointer.
But the thing is, every variable has a value and an address. Why does C specifically go the address of a pointer variable?
I'm not sure how to word this in a way that makes sense.
What is the point of declaring a pointer variable, when we can access the address of any variable using the & operator and print the pointer?
I'm having trouble visualising a pointer variable.
The way I see it now in my head is, every variable has an address and a value. This is a fact. I'm not sure what a pointer variable does since, like a normal variable, it also has a value and an address.
Pointer variables are treated the same as any other variable when it comes to storage.
Given the following declarations
int i = 1;
int *p = &i;
you get something like this:
Item Address Value
–––– ––––––– –––––
i 0x8000 1 // address values for illustration
p 0x8004 0x8000 // purposes only
The integer variable i is stored at address 0x8000 and contains the value 1. The pointer variable p is stored at address 0x8004 and contains the address of i.
IOW, the only difference between i and p is the type of value they store and what operations are allowed on them.
As for why we use pointers, they are required in the following cases:
To track dynamically allocated memory;
To allow a function to modify the value of an input parameter
They’re also useful in building dynamic data structures.

Why can't I increment an array?

char a[] = "hello";
My understanding is that a acts like a constant pointer to a string. I know writing a++ won't work, but why?
No, it's not OK to increment an array. Although arrays are freely convertible to pointers, they are not pointers. Therefore, writing a++ will trigger an error.
However, writing
char *p = a;
p++;
is fine, becuase p is a pointer, with value equal to the location of a's initial element.
a++ is not well-formed since a decays to a pointer, and the result of the decay is not an lvalue (so there is no persistent object whose state could be "incremented").
If you want to manipulate pointers to the array, you should first create such a pointer:
char* p = a; // decayed pointer initializes p
a++; // OK
++a; // even OKer
This is a very good question actually. Before discussing this, let's back to the basic concepts.
What happens when we declare a variable ?
int a=10;
Well, we get a memory location to store the variable a. Apart from this an entry is created into Symbol table that contains the address of the variable and the name of the memory location (a in this case).
Once the entry is created, you can never change anything into the symbol table, means you can't update the address. Getting an address for a variable is not in our hand, it's done by our computer system.
Let's say, we get address 400 for our variable a.
Now computer has assigned an address for the variable a, so at a later point, we can't ask computer to change this address 400 because again, it's not in our hand, our computer system does it.
Now you have an idea about what happens when we declare a variable.let's come to our question.
Let's declare an array.
int arr[10]
So, when we declare this array, we create the entry into the symbol table and, store the address and the name of the array into the symbol table.
let's assume we get address 500 for this variable.
Let's see what happens when we want to do something like this :
arr++
when we increment arr, we want to increment 500, that is not possible and not in our hand, because it has been decided by the computer system, so we can't change it.
instead of doing this we can declare a pointer variable
int * p= &arr;
What happens in this situation is: again an entry is created into the symbol table that stores the name and the address of the pointer variable p.
So when we try to increment p by doing p++, we are not changing the value into the symbol table, instead we are changing the value of the address of the pointer variable, that we can do and we are allowed to do.
Also it's very obvious that if we will increment the a the ultimately we are going to loss the address of our array. if we loss the address of array then how will we access the array at a later point ?
It is never legal in C to assign to an expression of array type. Increment (++) involves assignment, and is thus also not legal.
What you showed at the top is a special syntax for initializing a char array variable.
I think this answer here explains "why" it's not a good idea;
It's because array is treated as a constant pointer in the function it is declared.
There is a reason for it. Array variable is supposed to point to the first element of the array or first memory instance of the block of the contiguous memory locations in which it is stored. So, if we will have the liberty to to change(increment or decrement ) the array pointer, it won't point to the first memory location of the block. Thus it will loose it's purpose.

The size of data of an address

The address that pointed by a pointer in c language contains how much data (byte , 2 byte ) , or is it dependent on the data type that point to ?
I'm not entirely sure what you mean by "The address that pointed by a pointer". I'll assume you're referring to the object it points to, not to the size of the pointer itself.
The answer to your question can depend on just what you mean by "address".
A C pointer value is not just a raw memory address (though it's usually implemented that way). A pointer value refers to an object of a specific type, and that type specifies among other things, the size of the pointed-to object. And the C standard fairly consistently uses the word "address" to refer to a (non-null) C pointer value.
On the other hand, the word "address" is commonly used to refer to a raw memory address, which can be thought of as pointing to a single byte. But on the other hand, even on the machine code level, what size of data an address refers to can depend on what you do with it. (I've even worked on systems where a machine address can only point to a 64-bit word; byte operations were done entirely in software.)
A pointer of type int* points to an int object. The size of that object is, by definition, sizeof (int) bytes (commonly 4 bytes, but it could be 8, or 2, or even 1 if a byte is at least 16 bits). Similarly, a pointer of type struct foo* points to a struct foo object, which could be of just about any arbitrary size.
An int* pointer doesn't just point to the first byte of an int object, it points to the entire int object. (But if you convert an int* pointer to char*, the result will point to the "first" byte.)
And as a special case, a pointer of type void* points to some location in memory, but does not specify the size of the object it points to. You can't dereference it until you convert it to some other pointer type.
Recommended reading: Section 4 of the comp.lang.c FAQ.
This is quite a philosophic question, let me give you three completely incompatibel answers:
The pointer itself obviously points to exactly 1 byte
depending on the type of the pointer, the pointer points to the first byte of a chunk of data the size of which is defined by the pointer type
the pointer points to the first byte of some data, the usable length of which is neither deterministic nor determinable from inside the program
While I consider all three answers to be technically correct, the second one is what you would use while programming in C.
Edit
For the details if what an "address" can, may or should be, please look at #KeithThompson's input in the comments below!

How does pointer type casting work in c

I understand that in c, a pointer points to a memory address. In the following code
char *cp;
someType *up; // Assuming that someType is a union of size 16 bytes
cp = sbrk(nu * sizeof(someType));
// Here is what confuses me
up = (someType *)cp;
According to this link http://en.wikibooks.org/wiki/C_Programming/Pointers_and_arrays
If cp points to an address of 0x1234, so 0x1234 should be the beginning of the newly allocated memory, right?
So when "cp" is casted to a pointer to someType and assigned to "up", it actually says "up" is a pointer that points to 0x1234, assumes in 32-bits system, each memory address takes 4 bytes, a someType object will use 4 memory address to store its value, so the addresses 0x1234, 0x1235, 0x1236, 0x1237 collectively store a someType object, is this correct?
Thanks in advance.
Pointer type casting doesn't do anything at the machine level. The value in memory is still just a plain old value in memory.
At the language level, that value is used as an address. In other words it is often used as the value passed to operations that require memory locations, such as the assembly "load" operation.
At the language level, extra constructs are added to the machine operations, and one of those "extras" are data types. The compiler is responsible for checking if type-rule violations exist, but at run time there is not such a constraint.
As a result, the cast does nothing at run time, but at compile time it directs the compiler to not emit an error as the type of the pointer's value will now be considered a compatible type to the variable holding the address.
Even on a 32-bit system, a memory address typically refers to a single byte, not four. So your Header will be covering the 16 memory addresses between 0x1234 and 0x1243.
To answer your questions:
cp points to the beginning of the newly allocated memory.
However, up will contain the same address as cp. Note it is bad form to try and assign a pointer from one type to a different type without "casting" it first - just to tell the compiler you really meant to do such a dangerous thing.
Typically assigning between types can cause all kinds of problems - as a result compilers will throw warnings if you do this without casting. The casting, however, doesn't actually have any effect on the program code itself - it is more a method of the programmer telling the compiler they really meant what they did.
By the way, the pointer up is allocated on the stack in your function. Assigning a value to up actually places the value in the memory location on the stack. So by assigning cp to up you are merely copying the value of the pointer in cp to the location in the stack assigned to up. There is nothing placed into the memory allocated by the sbrk() call.
First of all, remember that a pointer is an abstraction of a memory address; do not assume a one-to-one correspondence between a pointer value and a physical location in RAM. Pointers also have type semantics associated with them; adding 1 to a pointer value advances it to point to the next object of the pointed-to type:
char *cp;
int *ip;
struct huge *hp;
cp = cp + 1; // advances cp to the address of the next char (1 byte)
ip = ip + 1; // advances ip to the address of the next int (anywhere
// from 2 to 8 bytes depending on the architecture)
hp = hp + 1; // advances hp to the address of the next struct huge (however
// many bytes struct huge takes up)
This is exactly how array indexing works; the expression a[i] is treated as *(a + i); you offset i elements of whatever size from the base address, not i bytes.
As far as the cast is concerned...
A pointer to char is a different, incompatible type than a pointer to Header. They may have different sizes and representations depending on the underlying architecture. Because of this, the language won't allow an implicit conversion of one to the other through a simple assignment; you must use a cast to convert the rhs value to the type expected by the lhs.
If cp points to a address of 0x1234, so 0x1234 should be the beginning of the newly allocated memory, right?
Right.
So when cp is casted to a pointer to Header and assigned to up, it actually says up is a pointer that points to 0x1234, assumes in 32-bits system, each memory address takes 4 bytes, a Header object will use 4 memory address to store its value, so the addresses 0x1234, 0x1235, 0x1236, 0x1237 collectively store a Header object, is this correct?
Wrong. C is strictly byte addressed. The Header object will occupy addresses 0x1234 through 0x1234 + sizeof(Header) - 1, inclusive, whatever sizeof(Header) is (perhaps 16 in this case). To confuse the issue, adding 1 to any pointer increments its numeric value by the sizeof whatever it points to, so it is the case that up + 1 points beyond the end of allocated memory. However cp + 1 points to the second byte in the representation of the header object, whatever that is. (sizeof(char) is 1 by definition.)
This has nothing to do with your question, but I must warn you that calling sbrk with a nonzero argument will cause your program to crash at some indefinite point after the next call to malloc, realloc or free, and that nearly all standard library functions are allowed to call those functions "under the hood". If you want to make a large allocation directly from the operating system, use mmap.

Resources