![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 |
|
Newbie
|
Pointers in C (Part I)
Hello,
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. All tutorial examples are compliant to the Standard C library, and should build successfully on any C compiler. All examples are optimized for the -Wall, -pedantic, -ansi, and -std=c89 GCC flags. 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() {
/* local variables */
char c;
char ch[2];
char *pch;
c = 'a';
ch[0] = 'a'
*pch = ch[0];
/* end program */
return 0;
}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>
int main() {
/* local variables */
int n = 3;
int *ptr;
/* point ptr to n */
ptr = &n;
/* memory address */
printf("%p\n", (void *)ptr);
/* data */
printf("%d\n", *ptr);
/* end program */
return 0;
}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() {
/* local variables */
int n[5];
int *ptr;
/* point ptr to n */
ptr = &n[0];
*ptr = 3;
/* end program */
return 0;
}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>
int main() {
/* local variables */
int n[5] = {10,20,30,40,50};
int *ptr;
/* points to n[0]*/
ptr = &n[0];
printf("ptr now points to n[%d] whose value is %d\n", (int)(ptr - n), *ptr);
/* points to n[1] */
ptr++;
printf("ptr now points to n[%d] whose value is %d\n", (int)(ptr - n), *ptr);
/* this expression references n[2], but ptr remains the same */
*(ptr+1);
printf("ptr now points to n[%d] whose value is %d\n", (int)(ptr - n), *ptr);
/* this decrements the value of the content of the location pointed by ptr */
(*ptr)--;
printf("ptr now points to n[%d] whose value is %d\n", (int)(ptr - n), *ptr);
/* this increments the value of the content of the location pointed by ptr */
++*ptr;
printf("ptr now points to n[%d] whose value is %d\n", (int)(ptr - n), *ptr);
/* end program */
return 0;
}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>
void reverse(int *x, int *y);
int main() {
/* Represent room A and B */
int A = 3, B = 5;
/* send local variable addresses to function */
reverse(&A, &B);
/* print result */
printf("Room A: %d\nRoom B: %d\n", A, B);
/* end program */
return 0;
}
void reverse(int *x, int *y) {
/* temporary variable */
int temp;
/* hold temporary variable that wont change */
temp = *x;
/* set x to y */
*x = *y;
/* set y to what x was temporarily before */
*y = temp;
}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() {
/* local variables */
int iCh;
char ch; /* signed */
char ca[3];
ch = 'a'; /* or 97 in ASCII */
iCh = 98; /* 98 is 'b' in ASCII */
ca[0] = ch; /* first index is 'a' */
ca[1] = (char)iCh; /* second index is 'b' [type cast the integer to char] */
ca[2] = 'c'; /* third index is 'c' */
ca[3] = '\0'; /* fourth ends here */
/* end program */
return 0;
}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() {
/* local variables */
char text[6] = "Hello";
char *ptr;
/* not recommended */
ptr = &text[0];
/* end program */
return 0;
}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);
int main() {
/* local variables */
char text[3];
char *ptr;
/* point our pointer to our local variable */
pointTo(&ptr, text);
/* modify pointer data; affects local data due to pointer linkage */
ptr[0] = 'A';
ptr[1] = '\0';
/* end program */
return 0;
}
void pointTo(char **src, char *dst) {
*src = dst;
}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>
#include <string.h>
#include <stdio.h>
int main() {
/* local variables */
char *ptr;
/* dynamically allocate memory */
ptr = malloc(6);
/* if allocation failed */
if (!ptr)
/* end application */
return 0;
/* copy data to pointer */
strcpy(ptr, "Hello");
/* print data */
printf("%s\n", ptr);
/* free data */
free(ptr);
/* end program */
return 0;
}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) {
char *s = dest;
while (*src)
*s++ = *src++;
*s = 0;
return dest;
}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]; Rows/Columns Column 0 Column 1 Column 2 Row 0 myValue[0][0] myValue[0][1] myValue[0][2] Row 1 myValue[1][0] myValue[1][1] myValue[1][2] int myValue[2][3] = { {5, -3, 0}, {10, 17, -25} };Rows/Columns Column 0 Column 1 Column 2 Row 0 5 -3 0 Row 1 10 17 -25 Look at this example: char letters[2][3] = { {'A'}, {'D', 'E'} };Rows/Columns Column 0 Column 1 Column 2 Row 0 A ‘\0’ ‘\0’ Row 1 D E ‘\0’
In this order, everything should come together smoothly. Lets take a look at an example: #include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main() {
/* Local variables */
int i, j;
int rows = 6;
char word[6][12] = {"Hello", "Good-Bye!", "Greetings",
"Pointers", "Arrays", "Programming"};
char **ptr = NULL;
/* Allocate room for rows */
ptr = malloc(rows * sizeof *ptr);
/* If allocation succeeded */
if (ptr) {
/* Loop through all columns */
for (i = 0; i < rows; i++) {
/* Allocate */
ptr[i] = malloc(strlen(word[i]) + 1);
/* If allocation succeeded */
if (ptr[i])
/* Copy data to our pointers memory */
strcpy(ptr[i], word[i]);
}
}else {
/* Allocation failed */
return 0;
}
/* Print data */
for (i = 0; i < rows; i++)
printf("%s\n", ptr[i]);
/* Free memory */
for (j = 0; j < rows; j++)
free(ptr[j]);
free(ptr);
/* End program */
return 0;
}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]: Rows/Columns Column 0 Column 1 Column 2 Column 3 Row 0 Book[0][0][0] Book[0][0][1] Book[0][0][2] Book[0][0][3] Row 1 Book[0][1][0] Book[0][1][1] Book[0][1][2] Book[0][1][3] Row 2 Book[0][2][0] Book[0][2][1] Book[0][2][2] Book[0][2][3] Book – Page[1]: Rows/Columns Column 0 Column 1 Column 2 Column 3 Row 0 Book[1][0][0] Book[1][0][1] Book[1][0][2] Book[1][0][3] Row 1 Book[1][1][0] Book[1][1][1] Book[1][1][2] Book[1][1][3] Row 2 Book[1][2][0] Book[1][2][1] Book[1][2][2] Book[1][2][3] int Book[2][3][4] = {
{ {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} } /* Page 0 */
{ {12, 13, 14, 15}, {16, 17, 18, 19}, {20, 21, 22, 23} } /* Page 1 */
};Book – Page[0]: Rows/Columns Column 0 Column 1 Column 2 Column 3 Row 0 0 1 2 3 Row 1 4 5 6 7 Row 2 8 9 10 11 Book – Page[1]: Rows/Columns Column 0 Column 1 Column 2 Column 3 Row 0 12 13 14 15 Row 1 16 17 18 19 Row 2 20 21 22 23 #include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main() {
int i, j, k, p; /* For loops */
int pNum; /* Page number */
int pGraphs; /* Paragraphs per page */
char paragraph[4][256]; /* Our paragraphs */
char ***Book = NULL; /* Our book */
/* Copy data to string */
strcpy(paragraph[0], "Pointers are awesome!");
strcpy(paragraph[1], "Now that I have learned 3-dimensional arrays,");
strcpy(paragraph[2], "I can use this knowledge");
strcpy(paragraph[3], "to write my own programs!");
/* Initialize loop variables */
j = p = 0;
pNum = 2; /* 2 pages */
pGraphs = 4; /* 2 paragraphs per page */
/* Allocate memory */
Book = malloc(pNum * sizeof *Book);
if (Book) {
for (i = 0; i < pNum; i++) {
/* Allocate memory */
Book[i] = malloc(pGraphs * sizeof *Book);
/* If allocation failed */
if (Book[i] == NULL) {
/* Free any memory that was previously used */
for (k = i; k >= 0; k--) {
if (Book[k] != NULL) {
free(Book[k]);
Book[k] = NULL;
}
}
/* Free any memory that was previously used from beginning */
if (Book != NULL) {
free(Book);
Book = NULL;
}
/* Terminate program */
return 0;
}
for (j = 0; j < pGraphs; j++) {
/* Allocate memory */
Book[i][j] = malloc(strlen(paragraph[j]) + 1);
/* If allocation failed */
if (Book[i][j] == NULL) {
/* Free any memory that was previously used */
for (k = j; k >= 0; k--) {
if (Book[i][k] != NULL) {
free(Book[i][k]);
Book[i][k] = NULL;
}
}
/* Free any memory that was previously used in previous loop */
for (k = i; k >= 0; k--) {
if (Book[k] != NULL) {
free(Book[k]);
Book[k] = NULL;
}
}
/* Free any memory that was previously used from beginning */
if (Book != NULL) {
free(Book);
Book = NULL;
}
/* Terminate program */
return 0;
}
/* Copy data to pointer */
strcpy(Book[i][j], paragraph[j]);
}
}
}else {
return 0;
}
/* Print data */
p = 0;
printf("My two page book\n");
for (i = 0; i < pNum; i++) {
printf("\nPage: %i\n", i);
for (j = p; j < (p + 2); j++) {
printf("%s\n", Book[i][j]);
}
p = j;
}
/* Free Memory */
for (i = 0; i < pNum; i++) {
for (j = 0; j < pGraphs; j++) {
free(Book[i][j]);
Book[i][j] = NULL;
}
free(Book[i]);
Book[i] = NULL;
}
free(Book);
Book = NULL;
/* End program */
return 0;
}I’ll let you decipher that one on your own. Always remember; think of this code as a book. Depth, row, and column. Conclusion That concludes this tutorial. In the next tutorial we will discuss Pointers in Application, tips on improving allocation techniques, and briefly explore dynamic allocation of 4-dimensional pointers. - Stack Overflow
__________________
Following the rules will ensure you get a prompt answer to your question. Here are a few guidelines you should know when posting. Your question may have been asked before, try the search facility. Tutorials Pointers In C (Part I) Pointers In C (Part II) |
|
|
|
|
|
#2 |
|
I eat cake for breakfast.
![]() ![]() ![]() ![]() Join Date: Jul 2004
Location: In my box.
Posts: 4,434
Rep Power: 9
![]() |
I only skimmed through it, but it looks purty damn good.
|
|
|
|
|
|
#3 |
|
Newbie
|
Hi
Nice tutorial. Thanks for your time ![]() |
|
|
|
|
|
#4 |
|
Expert Programmer
Join Date: Sep 2004
Location: Ontario, Canada
Posts: 579
Rep Power: 5
![]() |
Excellent tutorial
![]()
__________________
Johnny was a chemist's son but Johnny is no more, for what Johnny thought was H2O was H2SO4 |
|
|
|
|
|
#5 |
|
Newbie
|
Hello,
Thanks for the kind comments. Part II of the tutorial should be posted today. ![]() Regards, - Stack Overflow
__________________
Following the rules will ensure you get a prompt answer to your question. Here are a few guidelines you should know when posting. Your question may have been asked before, try the search facility. Tutorials Pointers In C (Part I) Pointers In C (Part II) |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|