How do I change contents of a variable using a pointer? - c

I'm working with pointers for the first time in C. I tried to declare, initialize, and assign a memory address to 3 pointers, then print the addresses and values of each pointer and variable, then assign a value to the pointer so that the value of the data which has the memory address is changed. Here is the code:
int i = 5;
float f = 7.77;
char c = 'a';
int iNumber = 2;
float fNumber = 5.55;
char cCharacter = 'c';
int *iPtr;
float *fPtr;
char *cPtr;
iPtr = &i;
fPtr = &f;
cPtr = &c;
printf("\nThe current values are: ");
printf("%d %f %c", i, f, c);
printf("\nThe addresses of each pointer are: ");
printf("%d %f %c", iPtr, fPtr, cPtr);
iNumber = *iPtr;
fNumber = *fPtr;
cCharacter = *cPtr;
printf("\nThe modified values are: ");
printf("%d %f %c", i, f, c);
printf("\nThe addresses of each pointer are: ");
printf("%d %f %c", iPtr, fPtr, cPtr);
return 0;
is when I change the values of i, f, and c.
However, when I run the program the memory addresses for the int variables are not in hexadecimal format, they're in random numbers that change every time I run the program. The addresses for the char ones don't appear. Also, when I modifiy the values in the pointers the variables they're pointing to don't change. I thought this was how you referenced by value, i'm really confused.

This (second) call of printf
printf("\nThe addresses of each pointer are: ");
printf("%d %f %c", iPtr, fPtr, cPtr);
is wrong. You are trying to output pointers as objects of the type int, float and char that does not make sense.
If you want to output stored addresses in the pointers you need to write
printf("\nThe addresses of each pointer are: ");
printf("%p %p %p\n", ( void * )iPtr, ( void * )fPtr, ( void * )cPtr);
(do not forgot to place the new line character '\n' in the format string)
Also in this call of printf
printf("\nThe modified values are: ");
printf("%d %f %c", i, f, c);
you are not outputting modified values. The values of the variables i, f, and c were not changed. It seems you mean instead
*iPtr = iNumber;
*fPtr = fNumber;
*cPtr cCharacter;
printf("\nThe modified values are: ");
printf("%d %f %c\n", i, f, c);

Changing the value using Pointer
I think ultimately you want to change the value of i from 5 to the value of the variable iNumber, which is 2 using pointer.
Your code :
iNumber = *iPtr;
fNumber = *fPtr;
cCharacter = *cPtr;
What you've done here is, assigned the value of each pointer variable to the iNumber, fNumber, cCharacter variables.
So now if you print those variables you could see that the values of iNumber, fNumber, cCharacter is changed to 5, 7.77, a accordingly. Because, those pointer variables are pointing to the address of the first 3 variables, that are &i, &f and &c as you've might guessed.
Solution :
*iPtr = iNumber;
*fPtr = fNumber;
*cPtr = cCharacter;
As you can see in the above snippet, you need to assign the new values/variable to the pointer variable instead of doing the opposite.
Printing the Address of a Variable
Your code :
printf("\nThe addresses of each pointer are: ");
printf("%d %f %c", iPtr, fPtr, cPtr);
To print the memory addresses of variables in C, you need to use the %p format specifier in printf() instead of %d or %f. The %p format specifier is specifically used for printing memory addresses in hexadecimal format.
Also, when you're printing the memory address of a variable, you have to use the address-of operator (&), which is used to get the address of a variable.
Solution :
printf("\nThe addresses of each pointer are: ");
printf("%p %p %p", &iPtr, &fPtr, &cPtr); // hexadecimal
// not the standard way to represent memory addresses
printf("%u %u %u", &iPtr, &fPtr, &cPtr); // decimal
Tip : You can print the address in Decimal instead of Hexadecimal
for ease of mind, just by replacing %p to %u. (the adreess-of operator remains intact while printing memory addresses)
Why do the memory addresses change on each run?
When you run your C program, the computer assigns a memory address to each variable in your program. The memory address is typically represented as a large number, usually in hexadecimal format. The memory address is important because it allows the program to access and manipulate the value of the variable stored at that location in memory.
However, the memory address of a variable can change from one program run to another, for a number of reasons, such as randomization of the memory space, allocation of memory on the heap or stack, or optimization of the program code by the compiler or linker.
But as a beginner, you don't have to worry about it.

Related

Using scanf %p UB

From the C11 Standard (draft): 7.21.6.2/12:
If the input item is a value converted earlier during the same program
execution, the pointer that results shall compare equal to that value;
otherwise the behavior of the %p conversion is undefined.
Can someone provide a code for this part of standard please. Can not understand the use of getting %p from input too.
First, here is a small demo that uses string versions of input and output (demo):
int val = 123;
char buf[100];
sprintf(buf, "%p", (void*)&val);
printf("Original =%s\n", buf);
void *ptr;
sscanf(buf, "%p", &ptr);
printf("Read back=%p\n", ptr);
int *iPtr = ptr;
if (iPtr == &val) {
printf("Pointers match\n");
}
The sprintf at the top writes the pointer to the output buffer; sscanf reads it back.
The string fed into sscanf matches exactly the string that was produced by sprintf, so the standard guarantees that iPtr == &val is going to evaluate to true, and the behavior is defined. Passing a string that does not match anything that has been produced by the same running program would be undefined behavior.
int main(){
int c =5;
int *p;
printf("Address of C: %p\n Please Enter the above address: " , &c);
scanf("%p", &p);
*p=10;
printf("\nNew value of C: %d", c);
}
You could manually set pointers via scanf. Dangerous if you have a typo however.

pointer arithmetic: address with no assignment holds value of another address

why is the address px+1 holding the value 0.3? (on every execution) the variable f has also the value 0.3, but it has an other address(px-1)!? (even the values on px+2, px+3 and px-2 hold the value 0.3..., when I print it out)
#include <stdio.h>
int main(){
int* px;
int i = 1;
float f= 0.3;
double d=0.005;
char c = '*';
px=&i;
printf("Values: i=%i f=%f d=%f c=%c\n",i,f,d,c);
printf("Addresses: i=%lX f=%lX d=%lX c=%lX\n",&i,&f,&d,&c);
printf("Pointer Values (size of int = %d):\n px=%lX; px+1=%lX; px+2=%lX; px+3=%lX\n",sizeof(int),px,px+1,px+2,px+3);
printf("Dereference: at px+1=%lX, value is:%f \n",px+1,*(px+1));
/* Output :
Values: i=1 f=0.300000 d=0.005000 c=*
Addresses: i=7FFF5C546BB4 f=7FFF5C546BB0 d=7FFF5C546BA8 c=7FFF5C546BA7
Pointer Values (size of int = 4):
px=7FFF5C546BB4; px+1=7FFF5C546BB8; px+2=7FFF5C546BBC; px+3=7FFF5C546BC0
Dereference: at px+1=7FFF5C546BB8, value is:0.300000
*/
}
You have several problems, all leading to undefined behavior. First of all, you should use "%p" to print pointers, and the pointers should be casted to void * for maximum compatibility. Secondly, dereferencing a pointer out of bounds, like when you do *(px + 1) leads to undefined behavior. Thirdly, the pointer px points to an integer, but you try to print it using float conversion which also leads to undefined behavior.
By writing *(px+1), you're trying to access out of bound memory. It invokes undefined behaviour.
Also,
to print an address, you should be using the %p format specifier.
to print an int you should use %d or %i

Integer Pointer Subtraction

I've written a few lines of code predominantly from a book that gets you to declare an integer array, then subtract and pass two addresses from the array to another integer, in order to pass into a printf statement. I'm not sure why, but my actual pointers: aPointer and bPointer seem to be 8 bytes, which poses a problem when I try and pass the subtracted addresses to an integer.
I then changed the latter to a long. The errors are not present in Xcode now, but I cannot print the address of pointerSubtraction properly using the %p specifier which does indeed expect an int and not a long.
int arrayOfInts[10];
for (int i = 0; i < 10; i++) {
arrayOfInts[i] = i;
printf("%d", arrayOfInts[i]);
// prints out 0123456789
}
printf("\n");
int *aPointer = &arrayOfInts[1]; // get address of index 1
int *bPointer = &arrayOfInts[7]; // get address of index 7
long pointerSubtraction = bPointer - aPointer; // subtract index 7 with 1
printf("The size of aPointer is %zu bytes \n", sizeof(aPointer));
printf("The size of aPointer is %zu bytes \n", sizeof(bPointer));
printf("The address of aPointer is %p \n", aPointer);
printf("The address of bPointer is %p \n", bPointer);
printf("The address of final is %p \n", pointerSubtraction);
printf("The value of pointerSubtraction is %ld \n \n", pointerSubtraction);
You might like to use a variable typed ptrdiff_t to store the difference of two pointer values, two addresses.
To printf() out a ptrdiff_t use the length modifier "t". As ptrdiff_t is a signed integer use the conversion specifier "d".
#include <stddef.h>
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 0, * pa = &a;
ptrdiff_t ptr_diff = pa - &b;
printf("pd = %td\n", ptr_diff);
return 0;
}
Also the conversion specifier "p" is only defined for pointers to void. So the printf() calls shall look like:
printf("The address of aPointer is %p \n", (void *) aPointer);
printf("The address of bPointer is %p \n", (void *) bPointer);
Also^2 : The result of adding or substrating a value v from a pointer p is only a valid address if the result pv of the operation still refers to (an element/member of) the object the original pointer p pointed to.
In your code aPointer is the value pointed by *aPointer. Same thing for bPointer.
As the comment says pointerSubtraction is the value obtained by the subtraction, not the address.

What is the meaning of printf("%p", int 1)?

I'm trying to understand the difference between int a and int *a, my first step was to see the value I could get by printi %p of an int a. Of course the compiler shows warnings, but does complete the job for the following code.
#include <stdio.h>
int main() {
int a;
printf("a - declared");
printf("int a = [%d]\n", a); // example - 1745899614
printf("int a pointer = [%p]\n", a); // example - 0x6810505e
a = 10;
printf("a - initialized to value of 10\n");
printf("int a = [%d]\n", a); // exmaple - 10
printf("int a pointer = [%p]\n", a); // example - 0xa
return 0;
}
And as I've mentioned in the source code, I do get a somewhat satisfactory result of 0xa which is equal to 10 in hexadecimal for the value of %p of an int a. But is it actually the case that int points to to that address, or is this just the compiler trying to make sense of %p in such a case?
Where is the memory allocated for ints? How do I test for that?
To print the address of an object named a, use:
printf("The address of a is %p.\n", (void *) &a);
Merely using %p does not tell printf to print the address of the object you use as the argument. You must use the “address of” operator, &, to take the address. Otherwise, you are passing the value of a to printf, not the address of a.
Additionally, it is proper to convert the address to void *, as shown above, because the %p specifier expects a pointer to void. Other types of pointers often work (or appear to work) in many C implementations, but the technical requirement is that a pointer to void be passed.
I imagine the formater ( in printf ), is just interpreting the memory as it is told to. So yeah, "%p" is for pointer, but you gave it an int. You wanted to give it the address of a:
printf( "%p", &a );
for the whole shabang:
int a = 10;
int *b = &a;
printf("value of a: %d\n", a );
printf("location of a: %p\n", &a );
printf("value of b: %p\n", b );
printf("location of b: %p\n", &b );
printf("dereference b: %d\n", *b );
But is it actually the case that int points to to that address, or is
this just the compiler trying to make sense of %p in such a case?
It's the latter. Compiler tries to interpret the integer as a pointer. When you print the value of a using %p compiler finds that the type of a is int and warns you that it's not a pointer.
To print the address of a use:
printf("int a pointer = [%p]\n", (void*)&a);
If a is a pointer (e..g int *a;) then you need to initialize it with a valid address and then you can print:
printf("int a pointer = [%p]\n", (void*)a);
%p is merely a way to tell printf to print your value as an address memory. You're passing the value of 10to it (the value of a) and you get printed this value in the hexadecimal notation 0xa. There is no special interpretation, it is just a formatting option.
If you want the value of the a's address memory printed you can simply do printf("%p", &a);. &a is the address of a.
Or if you want to use a pointer:
int* p;
p = &a;
printf("%p", p); //Prints the p value, that is the a address. Equivalent to printf("%p", &a).

Need help understanding char and int pointers

In this code to print the value of int and char pointer variables, why do I access them differently? For the char pointer I write sampleclient but for the int I write *intid. Why does one use * but not the other?
int main()
{
char client[] = "ABCD";
int intid = 10;
samplepass(&client, &intid);
return 0;
}
void samplepass(char *sampleclient, int *intid)
{
printf("%s %d\n", sampleclient, *intid);
}
This is because %s format specifier expects a char pointer, while %d expects an integer argument. If you want to see the value of the pointers themselves(i.e. the address they point to) use %p.
In C, you can't pass a string (character array) to a function like printf, so you do the next best thing: pass it its address in memory. The function can then treat the memory address like an array using pointer arithmetic. So the way printf reads strings is by taking in a pointer to the string. Then %s displays the dereferenced string (ABCD here), not the pointer address (which you could get by using %p instead of %s).
The integer problem is more straightforward: the * in *intid means 'get the value stored at this address'. That's why it prints out 10, not the memory address.
The 'correct' format specifier to get a memory address is %p. But you could write:
int main()
{
char client[] = "ABCD";
int intid = 10;
samplepass(&client, &intid);
return 0;
}
void samplepass(char *sampleclient, int *intid)
{
printf("%d %d\n", sampleclient, intid);
}
On my machine, the output was
-2140958000 -2140958004
(and those are the addresses in memory of client and intid). Substituting %p for %d gives nicely formatted pointers with a 0x in front and conforms to the standard, so I'd use that.
For an output that looks like:
ABCD 10
change your line
from samplepass(&client,&intid);
to samplepass(client,&intid);

Resources