![]() |
| ||
| Pointers Hello, Brief Tutorial Revision: All examples can be compiled successfully in your compiler. Also, each example is compatable using the -Wall, -pedantic, -ansi, and -std=c89 GCC flags. Also, a few paragraphs have been modified, and code examples improved. Previous tutorial, Pointers #2, has been combined in this revision. Introduction Pointers are facile, yet confusing. Thinking in the programming world isn’t easy, and comprehending everything read, intricate. Even though pointers are for the experienced, as they say, I’m here to guide programmers consisting of all levels to greaten their understanding of pointers, and why they are pertinent to your everyday programming. Pointer Fundamentals Let me start off by stating, a pointer is a variable that contains the address of another variable. Pointers and arrays are closely related, though pointers are sometimes the only way to express a computation. Some also say pointers lead to more compact and efficient code. If you view the following example [1.1], it may be confusing and you’ll see the incompleteness of it: int main() {Example 1.1: An incomplete look at pointers Pointers and addresses require allocation to store its data. Unlike the char and char[] data types, which use locally stacked memory, pointers pass though existing memory stacks. The unary operator “&� gives the memory address of an existing object. This assigns the address of one variable and “points to� another. Remember, pointers use existing memory, so we can either send a freed block of memory to a pointer, or assign it another variables’ address. Let me lead this with an example: #include <stdio.h>Example 1.2: A closer look into pointers and addresses If you have tried to compile this short example, you may see that it did not result in a crash. This is because we sent our memory address of the variable n to ptr. Here, ptr does not receive its own block of memory, yet it points to an existing variable, n. The same implementation applies in other situations, such as arrays: int main() {Example 1.3: Sending a memory address to a pointer Or, you might want to consistently move the pointers position to correspond with all 5 slots of the array {0, 1, 2, 3, 4}. This is called pointer arithmetic, and is very possible to do with ease. An example: #include <stdio.h>Example 1.4: Pointer arithmetic Pointer arithmetic may seem confusing, but it’s just like adding and subtracting. *ptr is the data of your pointer, while ptr is the location. The “++� is an operator that remedies the choice of “+= 1�, or in other terms, “increments the variable by 1�. To reference extended positions, the recommended arithmetic would be “*(ptr+x)� as x represents your incrementing position. Pointers are used in real day-to-day programs. For example, take the following question and convert it to C syntax accordingly: There are 3 people in room A, and 5 people in room B. If the people in each room switched rooms, how many people would be in room A and room B? Note: This seems extremely easy and would best serve if we used pointers in this situation. Let me explain. As logically explained above, we are to swap the people within Room A and Room B, and produce an answer. With our current knowledge of pointers, this can be done feasibly: #include <stdio.h>Code 1.1: Reversing two numbers using pointer knowledge As stated in code, void reverse(int *x, int *y) did a simple calculation and reversed A and B. The reason we used a temporary variable was to store the data of x. If we had set “*x = *y� and “*y = *x� it would have caused a problem no matter which we would call first. To break it down, we would literally state “1 [x] = 2 [y]�, then “2 [y] = 2 [x]�. Keeping the previous state of *x was very crucial. Simply, We sent our function void reverse(int *x, int *y) the memory addresses of A and B. That’s where the unary operator comes in handy. Send the addresses of A and B to *x and *y, swap out the two and we’re done. If we had not worked with pointers, we would have to create another set of variables, say, A0 and B0, then send A to B0, and B to A0 yet implementing a swap with unnecessary code congestion. » Pointers in the char data type realm We just discussed pointers from the integer perspective, and one-dimensional figures. As we may know, there are multiple dimensions in a programming environment. In which we must take the appropriate steps to accommodate all surrounding aspects. The character array realm is different from the integer, as we must deal with multiple instances in one variable. They both dwindle down to the fact of digits, as the ASCII Table defines. Standard ASCII, and signed char’s represent 0 thru 127. With those numbers, the char reads them as letters, or in the ASCII environment. To explain a character array is in the same mindset: int main() {Example 2.1: Character arrays in the integer environment The example shown is still within the “one-dimensional� environment. Character pointers also need a valid memory address to write to, like integers. Pointing a “character pointer� to a valid memory address isn’t as simple as seen before from the integer perspective. The following can be utilized, but is not recommended by most: int main() {Example 2.2: Pointing a pointer to, though not recommended As seen in this example, we initialized text to “Hello� which is 5 letters long resulting {‘H’, ‘e’, ‘l’, ‘l’ ‘o’, ‘\0’} 4 indices in the array system. Arrays always start at 0 and ‘\0’ is at the fifth location, [5]. Next, is a more efficient way of receiving the memory address of a local variable. Even though it’s not recommended, it ensures linkage between the two variables: void pointTo(char **src, char *dst);Example 2.3: Linking a pointer to a local variable Not exactly a two-dimensional pointer. We just need to send a pointer’s address to a function resulting in the pointer’s “*� pointer “*�. In void pointTo(char **, char *); we point dst to the pointed pointer *src. To ensure a pointer has a memory block without risking the chance of our local variable failing, we would take an opposite approach and allocate memory right from your machine's core. » Memory allocation in C We previously learned how to link memory addresses to pointers, but now its time to move to a more stable and serious approach: Handling memory from the core. This is no time at all to write a function or algorithm to space partition memory and issue it accordingly. That’s why the ANSI standard incorporated a function within the Standard C Library called void *malloc(unsigned int);. This function works in a unique way, sending the pointer memory of an empty/unused memory blcok of your requested size. This function will fail if there is insufficient memory from the system. Here is an example: #include <stdlib.h>Code 2.1: Allocating memory the right way Let’s ask for 6 bytes of memory to work with. If it can’t be found, end the program before a fatal crash occurs. Else, copy 5 letters to our 5 bytes leaving enough room for the NULL terminator ‘\0’. Once we are finished with out memory, we will free it. void free(void *); deallocates any dynamically allocated memory if previously allocated by a call to malloc(). This function is also provided by the standard library stdlib.h. char *strcpy(char *, const char *); is also within the included function(s) written in the standard header files, though this one is declared in string.h. This function, strcpy(), isn’t hard to re-implement. In fact, it just takes a few pointer skills: char* strcpy(char *dest, const char *src) {Example 2.4: Copy one string to another Note: Remember, if you have <string.h> included, don’t add these functions to our code example. Library’s and functions will conflict, yet leading to errors. I won’t get into great detail on this function. The main functioning of this is, that we increment *src and *s while copying the data from *src to *s while *src still exists. Once done, set the null terminator, and return dest as *s points to it. » Multi-dimensional pointers As tricky as it may sound, multi-dimensional pointers are just as easy as one-dimensional pointers, so don’t give up! As opposed to pointers, arrays can also work in a multi-dimensional realm. For example: Lets take: int myValue[2][3];Or for a more detailed look would be as the following: Rows/Columns Column 0 Column 1 Column 2That should make a lot of sense. If its to confusing, lets break it down: int myValue[2][3] = { {5, -3, 0}, {10, 17, -25} }; Rows/Columns Column 0 Column 1 Column 2This is beginning to look simpler by the minute. As we previously discussed, the character environment is somewhat different, but not always. Look at this example: char letters[2][3] = { {'A'}, {'D', 'E'} }; Rows/Columns Column 0 Column 1 Column 2As seen above, two-dimensional arrays consist of “row� and “column�, as one-dimensional consists of “column�. Allocating memory to two-dimensional arrays can be tricky, so here are some good steps to remember:
#include <stdlib.h>Code 3.1: Using two-dimensional arrays The comments in the code help guide you through each step. The sizeof function comes in handy during this process. We need to multiply our allocation size with the size of our variable to assure we have enough space to allocate anything else. Without that, our program may terminate unexpectedly. Pointers may seem difficult at this point, but its making perfect sense. There comes a time when it begins to advance. I do hope this short tutorial has been helpful to you. Before I’m done, I’d like to explore three-dimensional pointers. This too has a background of difficulty, but in the right perspective it too can be made easy. » Three-Dimensional Pointers This is an easy subject I like to think. It’s as easy as 1, 2, 3. Think of this as a Book. A book is three dimensions; depth, row, and column. For example: int Book[2][3][4]; Book – Page[0]:Or, in initialization: int Book[2][3][4] = { Book – Page[0]:I hope this is all coming together. Of course taking special measures for memory allocation is always needed. I’ll show an example: #include <stdlib.h>Code 4.1: Using three-dimensional pointers I’ll let you decipher that one on your own. Always remember; think of this code, as a book, and it will make complete sense. Pointers in application You have learned most, if not all, of the basics pertaining pointers in the previous tutorial. Here, we’ll discuss the fact-finding situations of pointers and their importance in the programming world. This tutorial is to help you understand pointers in application, how to dissect them, and how to use them properly. Pointer arithmetic is also a crucial segment of learning pointers in their entirety. I briefly covered this subject in the previous tutorial, which will indeed lead to a more successful approach in pointer utilization in the near future. Fully understanding pointers will further help you when you run into a problem, or become confused in your current program or project. For our first approach, lets further explain the pointer usage: #include <string.h>Example 5.1: Utilizing pointers in a new view That may seem weird, though all functions that retrieve a pointer point to where you send. Normally when you send a pointer, you don’t send its address. Since the function prototype asks for a single pointer, you send it the pointer. If we were to dissect the memcpy function, we may notice the first parameter looks different; at least while normal variable names were sent. Functions like memcpy() take a one-dimensional character array in one or more of their arguments. We are aware that the & operator only applies to objects in memory. Also previously learned is that p points to ch; no matter which is changed, they both correspond. Also, we are aware of the fact that “p[4]� is a single character from our array. In the cataclysmic event, we are complying with the one-dimensional array as to this extent: We are sending the object p at position 4. Any changes to this variable will proceed with and after position 4. If we were to take a more in-depth look, this is how the compiler perceives this: The & operator takes a one-dimensional array and then deals with the memory address; causing a “char *� to be perceived as a “char **�. Likewise with our object “p�. p[4] is a character. The & operator will then make our “char� look like a “char *�. Since we defined which location to start at “[4]�, our new “char *� will start at position 4 when converted. Another Example: int myFunc(int *);Example 5.2: When to send a memory address It is pertinent to know when and when not to send a pointer address to a function. For example, as we just saw above, consider the following: #include <stdio.h>Example 5.3: Pointers address information not always needed. Same applies for non-pointers in this case. The character array/pointer already contains an address, and when sending to a function, don’t send the address of unless you send the location. Many don’t understand why it isn’t appropriate to send the address of a character array to scanf(). It is simple actually. The reason we don’t send it is because we want to write to its data, not its address. The reason we do send it when dealing with an integer, float, double, or other is because scanf() takes pointers to objects. If you want to store the result on a standard variable, it is imperative to precede it with the reference operator. Another Example: #include <stdio.h>Example 5.4: Send pointer address including where to point to This way, scanf() can write to p, not the address. The address is good when you need to directly gain access to a variable, though here we don’t need to. Integer variables see otherwise. When sending information to a function that needs access, it usually means it wants the address too, like scanf(). Remember, sending address information is completely different when dealing with an array or not. The difference is very obvious: int main() {Example 5.5: Integers, and the difference between array’s and non-array’s There is a large difference between integers and character arrays. Expounding on this seems nagging, though it is what most programmers need to understand. The integer array is controlled by indices. My array[0] is a number, then my array[1] is another number. They are handled separately, and require more hand-holding. The character array is different, you have an array, and it controls the whole block. No need to set one array index at a time. » Pointer Techniques Pointers can be used in many programs, varying from the instance. You can use them to allocate memory, point to other variables, change data from a specified address, and so on and so forth. It really depends on where you use them, and what they are being used for. For example, if you wanted to send a two-dimensional array to a function and allocate it there; it would be somewhat impossible to send the 2-D pointer and memory address and allocate it there. There are ways around this though, for instance we would send our 2-D pointer to a function. Then we would create a temporary 2-D pointer inside our separate function and allocate it there. Tell our sent object to equal the temporary variable, and we are on our way. Here is an example: #include <stdlib.h>Code 5.1: Allocating a 2-dimensional array by passing pointers. Conclusion In conclusion of this segment, there are many ways pointers can be utilized in programs. This tutorial is just here to provide information on pointers, and how they work. With the fundamentals, it should not be difficult to debug your own programs and figure out why they may be performing the way it is. - Stack Overflow |
| All times are GMT -4. The time now is 6:47 am. |
Forum system based on vBulletin Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
©2003 - 2009 DaniWeb® LLC