c:pointers
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
c:pointers [2016/08/05 13:34] – created peter | c:pointers [2020/07/15 09:30] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 8: | Line 8: | ||
Basic ribbon of memory | Basic ribbon of memory | ||
+ | |||
+ | {{: | ||
+ | |||
Try: | Try: | ||
C Code Listing 1 | C Code Listing 1 | ||
+ | |||
+ | <code c> | ||
| | ||
2:int main() | 2:int main() | ||
Line 19: | Line 24: | ||
| | ||
7:} | 7:} | ||
+ | </ | ||
+ | |||
C++ Code Listing 1 | C++ Code Listing 1 | ||
+ | |||
+ | <code c++> | ||
| | ||
2:int main() | 2:int main() | ||
Line 27: | Line 36: | ||
| | ||
7:} | 7:} | ||
- | At line (4) in the program above, the computer reserves memory for fl. In our examples, we'll assume that a float requires 4 bytes. Depending on the computer' | + | </ |
+ | |||
+ | At line (4) in the program above, the computer reserves memory for fl. In our examples, we'll assume that a float requires 4 bytes. | ||
Variable fl allocated | Variable fl allocated | ||
+ | |||
+ | {{: | ||
When fl is used in line (5), two distinct steps occur: | When fl is used in line (5), two distinct steps occur: | ||
- | The program finds and grabs the address reserved for fl--in this example 924. | + | - The program finds and grabs the address reserved for fl--in this example 924. |
- | The contents stored at that address are retrieved | + | |
+ | |||
To generalize, whenever any variable is accessed, the above two distinct steps occur to retrieve the contents of the variable. | To generalize, whenever any variable is accessed, the above two distinct steps occur to retrieve the contents of the variable. | ||
- | The illustration that shows 3.14 in the computer' | + | **NOTE**: |
- | Separating the Steps | + | |
+ | |||
+ | ===== Separating the Steps ===== | ||
Two operators are provided that, when used, cause these two steps to occur separately. | Two operators are provided that, when used, cause these two steps to occur separately. | ||
- | operator meaning example | + | ^operator^meaning^example^ |
- | & do only step 1 on a variable & | + | |&|do only step 1 on a variable|&fl| |
- | * do step 2 on a number(address) *some_num | + | |*|do step 2 on a number(address)|*some_num| |
Try this code to see what prints out: | Try this code to see what prints out: | ||
C Code Listing 2 | C Code Listing 2 | ||
+ | |||
+ | <code c> | ||
1: #include < | 1: #include < | ||
2: int main() | 2: int main() | ||
Line 55: | Line 75: | ||
6: | 6: | ||
7: } | 7: } | ||
+ | </ | ||
+ | |||
C++ Code Listing 2 | C++ Code Listing 2 | ||
+ | |||
+ | <code c++> | ||
1:#include < | 1:#include < | ||
2: int main() | 2: int main() | ||
Line 63: | Line 87: | ||
6: | 6: | ||
7: } | 7: } | ||
+ | </ | ||
+ | |||
On line (5) of the example, The & operator is being used on fl. On line (5), only step 1 is being performed on a variable: | On line (5) of the example, The & operator is being used on fl. On line (5), only step 1 is being performed on a variable: | ||
- | 1. The program finds and grabs the address reserved for fl... | + | * The program finds and grabs the address reserved for fl... |
- | It is fl's address that is printed to the screen. If the & operator had not been placed in front of fl, then step 2 would have occurred as well, and 3.14 would have been printed to the screen. | + | It is fl's address that is printed to the screen. |
- | The (unsigned long int) phrase will be discussed later. It is there so that &addr will print out as a large, non-negative number. It has been shown in gray to indicate that you must include it for the program to compile properly but that it is not relevant to this current discussion. | + | **NOTE**: |
- | Keep in mind that an address is really just a simple number. In fact, we can store an address in an integer variable. Try this: | + | |
+ | Keep in mind that an address is really just a simple number. | ||
C Code Listing 3 | C Code Listing 3 | ||
+ | |||
+ | <code c> | ||
1: #include < | 1: #include < | ||
2: int main() | 2: int main() | ||
Line 81: | Line 110: | ||
7: | 7: | ||
8: } | 8: } | ||
+ | </ | ||
+ | |||
C++ Code Listing 3 | C++ Code Listing 3 | ||
+ | |||
+ | <code c++> | ||
1: #include < | 1: #include < | ||
2: int main() | 2: int main() | ||
Line 90: | Line 123: | ||
7: | 7: | ||
8: } | 8: } | ||
+ | </ | ||
+ | |||
The address of fl is stored in addr | The address of fl is stored in addr | ||
- | The above code shows that there is nothing magical about addresses. They are just simple numbers that can be stored in integer variables. | + | {{: |
+ | |||
+ | The above code shows that there is nothing magical about addresses. | ||
- | The unsigned long keywords at the start of line (5) simply means that the integer will not hold negative numbers (unsigned), and that it can hold quite large numbers (long). As before, the (unsigned long int) phrase has been shown in gray. It must be included for the code to compile, but is not relevant to this discussion. It will be discussed later. | + | **NOTE**: |
Now let's test the other operator, the * operator that retrieves the contents stored at an address: | Now let's test the other operator, the * operator that retrieves the contents stored at an address: | ||
C Code Listing 4 | C Code Listing 4 | ||
+ | |||
+ | <code c> | ||
1: #include < | 1: #include < | ||
2: int main() | 2: int main() | ||
Line 107: | Line 146: | ||
8: | 8: | ||
9: } | 9: } | ||
+ | </ | ||
+ | |||
C++ Code Listing 4 | C++ Code Listing 4 | ||
+ | |||
+ | <code c++> | ||
1: #include < | 1: #include < | ||
2: int main() | 2: int main() | ||
Line 117: | Line 160: | ||
8: | 8: | ||
9: } | 9: } | ||
+ | </ | ||
+ | |||
In line (7), step 2 has been performed on a number: | In line (7), step 2 has been performed on a number: | ||
- | 2. The contents stored at that address [addr] are retrieved. | + | * The contents stored at that address [addr] are retrieved. |
- | In order to make line (7) work, a little " | + | In order to make line (7) work, a little " |
OK, But why do we need & and * | OK, But why do we need & and * | ||
- | We have shown that 2 distinct steps occur when accessing a variable, and that we can make those steps occur separately. But why is this useful? | + | We have shown that 2 distinct steps occur when accessing a variable, and that we can make those steps occur separately. |
- | To see why, let's first look at how functions work in C/C++. Try this code: | + | To see why, let's first look at how functions work in C/ |
C Code Listing 5 | C Code Listing 5 | ||
+ | |||
+ | <code c> | ||
1: #include < | 1: #include < | ||
2: void somefunc(float fvar) | 2: void somefunc(float fvar) | ||
Line 141: | Line 188: | ||
11: | 11: | ||
12: } | 12: } | ||
+ | </ | ||
+ | |||
C++ Code Listing 5 | C++ Code Listing 5 | ||
+ | |||
+ | <code c++> | ||
1: #include < | 1: #include < | ||
2: void somefunc(float fvar) | 2: void somefunc(float fvar) | ||
Line 154: | Line 205: | ||
11: | 11: | ||
12: } | 12: } | ||
- | What prints out? 3.14? 99.9? It turns out that 3.14 prints out. The general term used to describe this behavior is pass by value. When somefunc(fl) is called at line 9: | + | </ |
+ | |||
+ | What prints out? 3.14? 99.9? It turns out that 3.14 prints out. The general term used to describe this behavior is pass by value. When somefunc(fl) is called at line 9: | ||
+ | |||
+ | * Execution jumps to line (2) to run the function. | ||
+ | * fvar is created as its own variable and fl's value is copied into fvar. | ||
- | Execution jumps to line (2) to run the function | ||
- | fvar is created as its own variable and fl's value is copied into fvar | ||
fvar stores value passed into function | fvar stores value passed into function | ||
- | On line (4), 99.9 is assigned to fvar | + | |
+ | {{: | ||
+ | |||
+ | |||
+ | * On line (4), 99.9 is assigned to fvar. | ||
99.9 is assigned to fvar | 99.9 is assigned to fvar | ||
- | Now that the function is finished, execution resumes in main where it left off (line 10). The fl variable is unchanged, 3.14 prints out. | + | |
+ | {{: | ||
+ | |||
+ | * Now that the function is finished, execution resumes in main where it left off (line 10). The fl variable is unchanged, 3.14 prints out. | ||
We can circumvent this pass by value behavior and change values passed into functions by using the & and * operators. | We can circumvent this pass by value behavior and change values passed into functions by using the & and * operators. | ||
C Code | C Code | ||
+ | |||
+ | <code c> | ||
1: #include < | 1: #include < | ||
2: void somefunc(unsigned long int fptr) | 2: void somefunc(unsigned long int fptr) | ||
Line 179: | Line 244: | ||
13: | 13: | ||
14: } | 14: } | ||
+ | </ | ||
+ | |||
C++ Code | C++ Code | ||
+ | |||
+ | <code c++> | ||
1: #include < | 1: #include < | ||
2: void somefunc(unsigned long int fptr) | 2: void somefunc(unsigned long int fptr) | ||
Line 194: | Line 263: | ||
13: | 13: | ||
14: } | 14: } | ||
+ | </ | ||
+ | |||
Quite simply, the two steps that normally occur when accessing a variable are being separated to allow us to change the variable' | Quite simply, the two steps that normally occur when accessing a variable are being separated to allow us to change the variable' | ||
- | The floating point variable fl is created at line (9) and given the value 3.14 | + | * The floating point variable fl is created at line (9) and given the value 3.14 |
Variable fl allocated | Variable fl allocated | ||
- | The & operator is used on fl at line (10) (do only step 1, get the address). The address is stored in the integer variable addr. | + | |
+ | {{: | ||
+ | |||
+ | * The & operator is used on fl at line (10) (do only step 1, get the address). The address is stored in the integer variable addr. | ||
The address of fl is stored in addr | The address of fl is stored in addr | ||
- | The function somefunc is called at line (11) and fl's address is passed as an argument. | + | |
- | The function somefunc begins at line (2), fptr is created and fl's address is copied into fptr. | + | {{: |
+ | |||
+ | * The function somefunc is called at line (11) and fl's address is passed as an argument. | ||
+ | | ||
The argument addr is copied to fptr | The argument addr is copied to fptr | ||
- | The * operator is used on fptr at line (4) -- do step 2, the contents stored in an address are retrieved. In this example, the contents at address 924 are retrieved. | + | |
- | The contents at address 924 are assigned the value 99.9. | + | {{: |
+ | |||
+ | * The * operator is used on fptr at line (4) -- do step 2, the contents stored in an address are retrieved. | ||
+ | | ||
99.9 is assigned to fl | 99.9 is assigned to fl | ||
- | The function finishes. Control returns to line (12). | ||
- | The contents of fl are printed to the screen. | ||
- | Pointer Variables | ||
- | Even though we have shown that an address is nothing more than a simple integer, the creators of the language were afraid we might confuse variables in our programs. We might confuse integers we intend to use for program values (e.g. variables storing ages, measurements, | + | {{: |
- | The language creators decided the best way to eliminate confusion was to create a different type of variable for holding addresses. A first attempt at this might have looked something like this: | + | * The function finishes. Control returns |
+ | * The contents | ||
+ | |||
+ | |||
+ | ===== Pointer Variables ===== | ||
+ | |||
+ | Even though we have shown that an address is nothing more than a simple integer, the creators of the language were afraid we might confuse variables in our programs. | ||
+ | |||
+ | The language creators decided the best way to eliminate confusion was to create a different type of variable for holding addresses. | ||
+ | |||
+ | <code c> | ||
1:... | 1:... | ||
2: float fl=3.14; | 2: float fl=3.14; | ||
3: float Ptr addr = &fl; | 3: float Ptr addr = &fl; | ||
4:... | 4:... | ||
- | On line (3), here is how to describe the addr variable: | + | </ |
+ | |||
+ | * On line (3), here is how to describe the addr variable: | ||
addr is a pointer to a float | addr is a pointer to a float | ||
- | (A) addr is an integer. (B) However, it is a special integer designed to hold the address of a (C) float | ||
- | In the code above, line (3) is close to what the creators of the language wanted except for one thing: using Ptr would require introducing another keyword into the language. If there is one thing that all C instructors like to brag about, it is how there are only a very small number of keywords in the language. Well, using line (3) as shown above would mean adding Ptr as another keyword to the language. | + | {{:c: |
- | To avoid this threat to the very fabric of the universe, the creators cast about for something already being used in the language that could do double duty as Ptr shown above. What they came up with was the following: | ||
+ | * (A) addr is an integer. | ||
+ | |||
+ | In the code above, line (3) is close to what the creators of the language wanted except for one thing: using Ptr would require introducing another keyword into the language. | ||
+ | |||
+ | To avoid this threat to the very fabric of the universe, the creators cast about for something already being used in the language that could do double duty as Ptr shown above. | ||
+ | |||
+ | <code c> | ||
1:... | 1:... | ||
2: float fl=3.14; | 2: float fl=3.14; | ||
3: float * addr = & | 3: float * addr = & | ||
4:... | 4:... | ||
- | Even with the * instead of Ptr, addr is described the same way: | + | </ |
+ | |||
+ | * Even with the * instead of Ptr, addr is described the same way: | ||
addr is a pointer to a float | addr is a pointer to a float | ||
- | (A) addr is an integer. (B) However, it is a special integer designed to hold the address of a (C) float | + | |
+ | {{: | ||
+ | |||
+ | * (A) addr is an integer. | ||
These variables are described this way, regardless of the type: | These variables are described this way, regardless of the type: | ||
addr is a pointer to a char | addr is a pointer to a char | ||
- | (A) addr is an integer. (B) However, it is a special integer designed to hold the address of a (C) char | + | |
+ | {{: | ||
+ | |||
+ | * (A) addr is an integer. | ||
addr is a pointer to an int | addr is a pointer to an int | ||
- | (A) addr is an integer. (B) However, it is a special integer designed to hold the address of an (C) int | + | |
+ | {{: | ||
+ | |||
+ | |||
+ | * (A) addr is an integer. (B) However, it is a special integer designed to hold the address of an (C) int. | ||
This " | This " | ||
- | Unfortunately, | + | Unfortunately, |
- | What is all that " | + | |
+ | ===== What is all that " | ||
Let's take one last look at our original code that illustrates the utility of separating out steps 1 & 2. | Let's take one last look at our original code that illustrates the utility of separating out steps 1 & 2. | ||
C Code Listing 7 | C Code Listing 7 | ||
+ | |||
+ | <code c> | ||
1: #include < | 1: #include < | ||
2: void somefunc(unsigned long int fptr) | 2: void somefunc(unsigned long int fptr) | ||
Line 265: | Line 381: | ||
13: | 13: | ||
14: } | 14: } | ||
+ | </ | ||
+ | |||
C++ Code Listing 7 | C++ Code Listing 7 | ||
+ | |||
+ | <code c++> | ||
1: #include < | 1: #include < | ||
2: void somefunc(unsigned long int fptr) | 2: void somefunc(unsigned long int fptr) | ||
Line 280: | Line 400: | ||
13: | 13: | ||
14: } | 14: } | ||
- | In nearly all of the code samples, you have been asked to ignore certain bits of the code. These bits of code have always appeared around those areas where we are either taking the address of a variable or getting the contents at an address (doing step 1 or step 2 on a variable) | + | </code> |
- | Those bits of " | + | In nearly all of the code samples, you have been asked to ignore certain bits of the code. These bits of code have always appeared around those areas where we are either taking |
- | On line (10) we are taking | + | Those bits of " |
- | Why would the compiler complain? Because when we assign | + | On line (10) we are taking |
- | This " | + | Why would the compiler |
- | The other place casting | + | This " |
- | Putting | + | The other place casting occurs is on line (4). On line (4), we are getting the contents at an address ("do step 2 on a number/ |
- | From the previous section, you might be left with the impression that whenever you deal with addresses and pointers, there is a lot of casting. Not so. The only reason our examples up till now have required casting is because we were storing our addresses in unsigned long int variables. The language designers want us to store addresses in the " | + | |
+ | ===== Putting it all together ===== | ||
+ | |||
+ | From the previous section, you might be left with the impression that whenever you deal with addresses and pointers, there is a lot of casting. | ||
Once we replace our unsigned long int variables with these pointer variables, none of the casting is required: | Once we replace our unsigned long int variables with these pointer variables, none of the casting is required: | ||
C Code Listing 8 | C Code Listing 8 | ||
+ | |||
+ | <code c> | ||
1: #include < | 1: #include < | ||
2: void somefunc(float* fptr) | 2: void somefunc(float* fptr) | ||
Line 313: | Line 438: | ||
13: | 13: | ||
14: } | 14: } | ||
+ | </ | ||
+ | |||
C++ Code Listing 8 | C++ Code Listing 8 | ||
+ | |||
+ | <code c++> | ||
1: #include < | 1: #include < | ||
2: void somefunc(float* fptr) | 2: void somefunc(float* fptr) | ||
Line 328: | Line 457: | ||
13: | 13: | ||
14: } | 14: } | ||
- | On line (10), when we take the address of fl the address is assigned to a variable designed to hold it. No casting is required. | + | </ |
- | When addr is passed to the function in line (11), addr is copied to fptr on line (2). | + | |
- | Line (2) shows that fptr is created as a float pointer, that is a variable designed to hold the address of a floating point number. As a result, no casting is needed on line (4) where the contents at the address are retrieved. | + | * On line (10), when we take the address of fl the address is assigned to a variable designed to hold it. No casting is required. |
+ | | ||
+ | | ||
+ |
c/pointers.1470404086.txt.gz · Last modified: 2020/07/15 09:30 (external edit)