This program is supposed to take in a three digit number and change it into its palindrome. 123
would become 321
.
The logic is correct, and the program compiles correctly. :) However, the logic of these does not come easily.
My prof explains things with "stack diagrams" and I find them to be helpful. I created this program based off another program because I noticed the similarities between this and a different program I made, but how does the pointing work?
#include <stdio.h>
void reverse_number(int in_val, int *out_val) {
int ones, tens, hundreds;
ones = in_val % 10;
tens = (in_val % 100 - ones) / 10;
hundreds = (in_val - (ones + tens)) / 100;
*out_val = (ones * 100) + (tens * 10) + hundreds;
}
int main() {
int in_val;
int out_val;
printf("Give a three digit num to reverse: \n");
scanf("%d", &in_val);
reverse_number(in_val, &out_val);
printf("New number is: %d \n", out_val);
return 0;
}
Also, I am now beginning to understand how to write programs based on a kind of template with these pointers, and I understand very basically what the star inside a parameter means (declared as a pointer variable).
For example, I know that m = &q;
gives variable m
the address of another variable q
and I know that m = *g;
would mean that the value at the address g
would go into m
but I am really unfamiliar with how these work in the context of a function and a main file.
If someone could lay out the fundamental logic of how it would work (in this program) that would be awesome. As a math major, I can understand the operations of the math and stuff but the pointers have me not confused but it just seems to me that there are ways to do it without needing to deal with the address of a variable, etc.
Well, since you understood &
and *
operators perfectly, the rest is very very simple.
Let's say you have:
int q;
int *m;
m = &q;
Then if you say:
int *m2;
m2 = m;
m2
will contain the same value as m
, that is, it will have the address of q
. Therefore, *m
and *m2
will give you the same value (which is the value of q
) (you do understand that *
is the inverse operator of &
right? So *(&q) = q
and &(*m) = m
(in the later case, m
needs to be a pointer for *
to be applicable.))
So, how does this work with functions? Simple! When you pass arguments to functions, you pass them by value. When you pass by pointer, you are actually passing by value, the pointer of the variable.
So let's examine your function call in detail:
reverse_number(in_orig, &out_orig);
I renamed your in_val
and out_val
in the main to in_orig
and out_orig
so it won't get mixed with those of reverse_number
.
Now, &out_orig
is the address of out_orig
. When passed as arguments, this gets copied into out_val
argument of reverse_number
. This is exactly like writing:
int *out_val = &out_orig;
Now, if you had the above line in your main
, you could just write *out_val = something;
and it would change out_orig
, right? Well, since you have the address of out_orig
in out_val
, then who cares if *out_val
is being set in main
or reverse_number
?
So you see? When you have a pointer, you can just copy it around, whether by copying it to another variable or passing it as argument of a function (which is basically the same thing), you can still access the same variable it is pointing to. After all, all the copies have the same value: address of out_orig
. Now if you want to access it in a function or in main
, it doesn't really matter.
Edit: *
in pointer definition
*
can be used to define a pointer too and this has nothing to do with the previous usage of *
as an operator that gets the value of an address.
This is just definition, so you have to learn it:
If you have a value of type type
(for example int
), then the address of that variable (using operator &
) has type type *
(in this example int *
). Since a pointer takes that address, the type of the pointer is type *
.
On the contrary, if a pointer has type type *
(for example int *
), then getting the value where the pointer points to (using operator *
) has type type
(in this example int
).
In summary, you can say something like this:
operator &, adds one * to the type of the variable
operator *, removes one * from the type of the expression
So let's see some examples:
int x;
x has type int
&x has type int *
float *y;
y has type float *
&y has type float **
*y has type float
struct Data ***d;
d has type struct Data ***
&d has type struct Data ****
*d has type struct Data **
*(*d) has type struct Data *
*(*(*d)) has type struct Data
If you noticed, I said that &
adds one *
to the type of variable, but *
removes one *
from the type of expression. Why is that? Because &
gives the address of a variable. Of course, because nothing else has an address. For example a+b
(possibly) doesn't have any address in the memory, and if it does, it's just temporary and useless.
operator *
however, works on addresses. No matter how you compute the address, operator *
works on it. Examples:
*(0x12345678) -> Note that even if the compiler let's you do this,
your program will most likely crash
*d -> like we saw before
*(d+4) -> This is the same as writing d[4]
And now you know why arrays and pointers are treated as one
In case of a dynamic 2d array:
*(*(d+4)+6) -> This is the same as writing d[4][6]