C - What does int *p; p=15; does? - c

What is the difference between these two code samples? When I print the variable p, it prints the assigned value like below.
int *p;
p = 51;
printf("%d",p);
Output: 51
When I try to assign p=15, am I making memory address "15" in the ram as a pointee to the pointer p? When I try to add int c = 5 +p; it gives output as 71. Why am I getting 71?
I thought that the memory address "15" could store any information of the OS, programs, etc. But it exactly stores int for precise. Though I change the value p = 150; it gives int . How is that possible? What's happening under the hood?! I really don't understand.

Your code is illegal. Formally, it is not C. C language prohibits assigning integral values to pointer types without an explicit cast (with the exception of constant 0)
You can do
p = (int *) 51;
(with implementation-defined effects), but you cannot do
p = 51;
If your compiler allows the latter variant, it is a compiler-specific extension that has nothing to do with standard C language.
Typically, such assignment makes p to point to address 51 in memory.
On top of that, it is illegal to print pointer values with %d format specifier in printf. Either use %p or cast pointer value to proper integer type before using integer-specific format specifiers.

So you're telling that pointer that it points to 0x15. Then, you tell printf to print it as a decimal integer, so it treats it as such.
This reason this works is that on a 32 bit system, a pointer is 4 bytes, which matches the size of an int.

p points to a place in memory. *p is the contents of that space. But you never use the contents, only the pointer.
That pointer can be viewed as just a number, so printf("%d",p) works. When you assign a number to it, it interprets that as an offset into memory (in bytes). However, the pointer is supposed to contain ints, and when you add a number to a pointer, the pointer advances by that many spaces. So p+5 means "point to the int 5 spaces past the one you're pointing at now", which for 4-byte ints means 20 bytes later, hence the 71.
Otherwise, you've said you have a pointer to an int, but you're actually just doing all your stuff to the pointer, not the int it's pointing to.
If you actually put anything into the place you were pointing, you'd run into all kinds of trouble. You need to allocate some unused memory for it (e.g. with malloc), and then read and write values to that memory using *p.

Related

How do bytes and addresses correlate in C?

I have seen that there are many questions related to this topic, but I could not infer an answer, so I decided to ask my first question here on stack overflow. Currently, my question is regarding the bytes and addresses, does each address actually represent one address, meaning that if I would initialize one address e.g. 0x55555555d156 but if I were to initialize an int, it would take 4 addresses, meaning that it will range from e.g. 0x55555555d156 to 0x55555555d160 ? So what confuses me is that, a pointer will hold an address, right?
Let's say the pointer holds the address e.g. 0x55555555d156 and if I were to deference that address I would get the value of that int, right? what about the other 3 addresses, if I deference them? I could not manage to acquire that information by writing a C program.
if I were to deference that address I would get the value of that int, right?
Yes.
what about the other 3 addresses, if I deference them?
If you have int *p = &some_integer;, then *(int *)((char *)p + 1) (dereferencing p "shifted" by one byte) would attempt to read 4 bytes from that new address and interpret them as an integer. Whether your program has permission to read that last byte that's right next to some_integer in memory, is another story: if it doesn't, you'll get a segmentation fault or other memory access issues.
Or you may get no errors and read garbage data.
Example
#include <stdio.h>
int main(void) {
int my_int = 0x12345678;
int *ptr = &my_int;
printf("%x\n", *ptr);
printf("%x\n", *(int *)((char *)ptr + 1));
}
Output:
~/test $ clang so.c && ./a.out
12345678
80123456
^^
|-- This "random" byte was read as part of
--- the "new" int shifted by 1 byte
Different microprocessors have different addressable units of memory. Most, including the x86 series and ARM, are addressable in units of one byte. So, for example, a 32-bit int will be stored in four consecutive memory addresses as you say (LSB first, unless the ARM is set to "Big Endian" mode).
Other processors, like PIC, may have one address point to a 16-bit memory word.
Your C code should probably not make assumptions either way, unless you're sure what the code will be run on.
You can't "dereference an address" -- you can dereference a pointer. A pointer value is an address, but the pointer also has a type. The result of the dereference depends on the pointer's type.
The result of derefencing a pointer is NOT the value stored at the memory location being pointed to. It is an expression that designates an object. This is known as an lvalue in C .
If all of this is unclear; first check that you understand what is happening in the code:
int x = 0;
x = 5;
In the second line, the use of x does not retrieve the value 0. The expression x is an lvalue which means that it designates a region of memory consisting of several bytes. Each byte has its own address. If you output &x you will likely see the same result as if you output the address of the first byte of x (although this is not a Standard requirement), but the types are different.
Whether or not the stored value is retrieved when an lvalue expression appears in the code, depends on the context of the expression. For example if it appears on the left-hand side of the assignment operator, the value is not retrieved.
Once you have understood x = 5; , then *p = 5; behaves identically; the meaning of *p is exactly as if the label x existed for the memory region that p points to.

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

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);

What address is this pointer assignment returning?

I was playing around with pointers the other day and came up with the following code where I explicitly cast an int variable to int * and print out the address of the explicitly casted variable
#include <stdio.h>
int main (void)
{
int d;
int *p1, *p2;
printf("%p\n", p1 = &d);
printf("%p\n", p2 = (int *) d);
return 0;
}
Here's the output:
ffbff71c
ffbff878
My question is what is that second address and what is contained there?
Garbage - you're printing out the value of an uninitialized variable. It's just total coincidence that it looks like your other address; initialize d to get a meaningful answer.
In the second print, you are not printing an address, but a value converted to an address!
In the first assignment, you're taking the address of the variable, which is just some RAM address. In the second assignment, you're converting the variable's value to a pointer. Since the variable is not initialized, that's the garbage value located at that RAM address.
It is just a random address in memory since d is not initialized.
As others have pointed out, you are converting an indeterminate value to a pointer. Performing that conversion, or indeed doing anything with that value other than overwriting it, produces undefined behavior.
If d's value were set prior to the conversion, then it would matter that C explicitly permits integers to be converted to pointers. However, for this case and most others, the standard says:
the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
[C2011, 6.3.2.3/5]
So basically, don't do that unless you know enough to determine reliably for yourself what the result will be with your particular combination of code, C implementation, compile and link options, and platform.

Add operation on pointer

int a[3];
int *j;
a[0]=90;
a[1]=91;
a[2]=92;
j=a;
printf("%d",*j);
printf("%d",&a[0])
printf("%d",&a[1]);
printf("%d",*(j+2));
here the pointer variable j is pointing to a[0],which is 90;and address of a[0] is -20 is on my machine. So j is holding -20.
And the address of a[1] is -18. So to get next variable I should use *(j+2). because j+2 will result in -18. but this is actually going on. To access a[1]. I have to use *(j+1). but j+1=-19. Why is j+1 resulting in -18 ?
Addresses are unsigned. You're printing them as if they were an int, but they're not an int. Use "%p" as the format specifier. That's how you print the address of a pointer.
Additionally, pointer arithmetic is different than the arithmetic you are used to. Internally, adding one to a pointer p increments the address by sizeof *p bytes, i.e., it increments the to the next object.
This is convenient as it saves the programmer from having to always use sizeof when performing arithmetic on a pointer (rarely do you actually want to increment by something other than sizeof *p. When you do, you cast to a char* first.)
pointer addition is not same as simple addition.
It depends on what type of variable the pointer is pointing.
In your case it's an int whose size is machine dependent (you can check of doing sizeof(int)).
So when adding a number to pointer like (j+i) it internally converts to (j+i*sizeof(datatype)) so when you type (j+2) the address is increased the 4 times (assuming int to be 2 bytes) which is not the intended result.
(j+1) will give you the right result (it's like saying point to the next element of int type of data)
Actually the pointer logic works on the basis of the pointer type since integer pointer type moves by size of integer on your machine it moves by the 2 bytes on your machine so p+1 = p+(sizeof(type of pointer))
*(x+y) is always exactly equivalent to x[y] (or y[x]). So to print a[1], you want *(j + 1) (or just j[1]). Note that, in a[1], a is converted to a pointer ... there's no difference between the way a is handled and the way j is handled here.

Another C pointer Question

The following code :
int *a;
*a = 5;
will most likely result in a segmentation fault and I know why.
The following code :
int a;
*a = 5;
won't even compile.
(gcc says : invalid type argument of unary *).
Now, a pointer is simply an integer, which is used
for storing an address.
So, why should it be a problem if I say :
*a = 5;
Ideally, this should also result in a segmentation fault.
A pointer is not an integer. C has data types to
a) prevent certain programming errors, and
b) improve portability of programs
On some systems, pointers may not be integers, because they really consist of two integers (segment and offset). On other systems, the "int" type cannot be used to represent pointers because an int is 32 bits and a pointer is 64 bits. For these reasons, C disallows using ints directly as pointers. If you want to use an integral type that is large enough to hold a pointer, use intptr_t.
When you say
int a;
*a = 5;
you are trying to make the compiler dereference something that is not a pointer. Sure, you could cast it to a pointer and then dereference it, like so,
*((int*)a) = 5;
.. and that tells the compiler that you really, really want to do that. BUT -- It's kind of a risky thing to do. Why? Well, in your example, for instance, you never actually initialized the value of a, so when you use it as a pointer, you are going to have whatever value is already at the location being used for a. Since it looks like it is a local variable, that will be an un-init'd location in the function's stack frame, and could be anything. In essence, you would be trying to write the value 5 to some undetermined location; not really a wise thing to do!
It's said to illustrate that pointers merely store addresses, and that addresses may be thought as numbers, much like integers. But usually addresses have a structure (like, page number, offset within page, etc).
You should not take that by word. An integer literally stores a number, which you can add, subtract etc. But which you cannot use as a pointer. An integer is an integer, and a pointer is a pointer. They serve different purposes.
Sometimes, a cast from a pointer to an integer may be necessary (for whatever purposes - maybe in a OS kernel to do some address arithmetic). Then you may cast the pointer to such an integer type, previously figuring out whether your compiler guarantees correct sizes and preserves values. But if you want to dereference, you have to cast back to a pointer type.
You never actually assign "a" in the first case.
int* a = ?
*a = 5; //BAD. What is 'a' exactly?
int a = ? //but some int anyway
*a = 5; //'a' is not a pointer!
If you wish to use the integer as a pointer, you'll have to cast it first. Pointers may be integers, but conceptually they serve different purposes.
The operator * is a unary operator which is not defined for the integer data type. That's why the statement
*a = 5;
won't compile.
Also, an integer and a pointer are not the same thing. They are typically the same size in memory (4 bytes for 32 bit systems).
int* a — is a pointer to int. It points nowhere, you haven't initialized it. Please, read any book about C before asking such questions.

Resources