Hello fellow programmers,

This is a tutorial about using pointers in the C environment. Please, don’t hit the back button; pointers aren’t as hard as you think. In fact without pointers, most of us would be lost in our latter programming years.

Even though pointers are for the experienced, as they say, I’m here to help programmers from consisting of all levels to help greater understand pointers, and why they are pertinent to your everyday programming needs.

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 usually lead to more compact and efficient code. If you view the following example [1.1], it may confuse you or if not, you’ll see the incompleteness of it:

int main() {
	char c;
	char ch[2];
	char *pch;

	c = ‘a’;
	ch[0] = ‘a’
	*pch = ch[0];

	return 0;
}

Example 1.1: An incomplete look at pointers

Pointers and addresses need 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 an empty or 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() {
	int n = 3;
	int *ptr;

	ptr = &n;

	printf("%p\n", (void *)ptr);	// memory address
	printf("%d\n", *ptr);		// data

	return 0;
}

Example 1.2: A closer look into pointers and addresses

If you have tried to compile this piece of code, you may see that it did not result in a crash. As you might ask “why? this is because we sent our memory address of the variable n to ptr which is results to giving ptr its memory block. Here, ptr does not receive its own block of memory, yet it points to an existing variable n. The same implementation applies for multiple situations, as arrays:

int main() {
	int n[5];
	int *ptr;

	ptr = &n[0];
	*ptr = 3;

	return 0;
}

Example 1.3: Sending a memory address to a pointer

As you are probably wondering how the same applies if you 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:

int main() {
	int n[5];
	int *ptr;

	ptr = &n[0];	// points to n[0]
	*(ptr+1);	// points to n[1]
	++*ptr;		// points to n[2]
	(*ptr)++;	// points to n[3]

	return 0;
}

Example 1.4: Pointer arithmetic

Pointer arithmetic may seem confusing, but it’s just like adding and subtracting. *ptr is the location of your pointer, not actually the value when working with arrays. As you may have already learned, “++ is an operator that remedies the choice of “+= 1, or in other terms, “increments the variable by 1. To move multiple positions at once, the recommended arithmetic would be “*(ptr+x) as x represents your incrementing position.

Pointers are used in real programs. For example, take the following question and convert it to the C syntax:

There are 3 people in room A, and 5 in room B. If they were reversed, how many people would be in room A, and room B?

Note: This seems extremely easy and it would be best served if we used pointers in this situation. Let me explain, here, as logically explained above, we are to swap A and 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() {
	int A = 3, B = 5; // represent room A and B

	reverse(&A, &B);

	printf(“Room A: %d\nRoom B: %d\n, A, B);

	return 0;
}

void reverse(int *x, int *y) {
	int temp;	// temporary variable

	temp = *x;	// hold temporary variable that wont change
	*x = *y;	// set x to y
	*y = temp;	// set y to what x was temporarily before
}

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 for us easily. The reason a temporary variable was needed, is because 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 [[b]x[/b]] = 2 [[b]y[/b]], then “2 [[b]y[/b]] = 2 [[b]x[/b]]. Using a temporary variable should become clear since keeping the previous state of *x is very crucial at this point.

In order for this code to have worked so clearly, we would need to send 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 steps.


Pointers in the char data type realm
Above we discussed pointers in the realm of integers, and one-dimensional figures. As we may know, there are multiple dimensions in a programming environment, and 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 line:

int main() {
	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

	return 0;
}

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. Pointers our pointers, so that rule applies always.

Pointing a character pointer to a valid memory address isn’t as easy as seen before in the integer arena. The following can be utilized, but is not recommended by most:

int main() {
	char text[6] = “Hello;
	char *ptr;

	ptr = &text[0];	// not recommended

	return 0;
}

Example 2.2: Pointing a pointer to, though not recommended

As seen above, we initialized text to “Hello which is 5 letters long resulting {‘H’, ‘e’, ‘l’, ‘l’ ‘o’, ‘\0’} 4 in the array world. Arrays always start at 0, and ‘\0’ is at location [5] in this case.

Next, I will display a more efficient way of receiving the memory address of a local variable. Even though it’s not recommended, it ensures more linkage between the two:

void pointTo(char **src, char *dst);

int main() {
	char text[3];
	char *ptr;

	pointTo(&ptr, text);

	ptr[0] = ‘A’;
	ptr[1] = ‘\0’;

	return 0;
}

void pointTo(char **src, char *dst) {
	*src = dst;
}

Example 2.3: Linking a pointer to a local variable

Not exactly a two-dimensional pointer yet, 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. The first explanation is in C.

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 out how much is asked for or called. That’s why the ANSI standard incorporated a pre-made function for us called void *malloc(unsigned int);. This function works in a unique way, sending the pointer a memory address of empty/unused memory to the size you request. This function can fail if insufficient memory is provided. Here is an example of how this function is used in programming:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int main() {
	char *ptr;

	ptr = (char *)malloc(6);
	if (!ptr)
		return 0;

	strcpy(ptr, "Hello");

	printf(ptr);

	free(ptr);

	return 0;
}

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 program before a fatal crash, else, copy 5 letters to our 5 bytes leaving enough room for the NULL terminator ‘\0’. Let’s print our pointer to the screen, and last of all, and never forget, free the memory. void free(void *); works like malloc(), though it frees the memory of the memory address sent in the first and only argument. 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;
}

Example 3.1: 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 2	Column 3
Row 0		myValue[0][0]	myValue[0][1]	myValue[0][2]	myValue[0][3]
Row 1		myValue[1][0]	myValue[1][1]	myValue[1][2]	myValue[1][3]
Row 2		myValue[2][0]	myValue[2][1]	myValue[2][2]	myValue[2][3]

That should make a lot of sense. If its to confusing, lets break it down:

int myValue[2][3] = { {5, -3, 0}, {10, 17, -25} };

Could be looked at as:

Rows/Columns	Column 0	Column 1	Column 2
Row 0		5		-3		0
Row 1		10		17		-25

This 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 2
Row 0		A		‘\0’		‘\0’
Row 1		D		E		‘\0’

As 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:

· Know your Row count first.
· Know your Column count next.
· Know your Column length

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() {
	int i, j, p;
	int rows = 6;
	char word[6][12] = {"Hello", "Good-Bye!", "Greetings",
						"Pointers", "Arrays", "Programming"};
	char **ptr;

	ptr = (char **)malloc(rows * (sizeof *ptr)); // allocate room for rows
	// If allocation succeeded
	if (ptr) {
		// Loop through all columns
		for (i = 0; i < rows; i++) {
			// Allocate
			ptr[i] = (char *)malloc(strlen(word[i]) + 1 * (sizeof **ptr));
			// If allocation succeeded
			if (ptr[i])
				// Copy data to our pointers memory	
				strcpy(ptr[i], word[i]);
		}
	}

	// 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);

	return 0;
}

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 tutorial has been helpful to you. Before I’m done, I’d like to explain and explore three-dimensional pointers. This too has a background of difficulty, but in the right perspective is as easy as everything else.

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];

Think of it as:

Book – Page[0]:
Rows/Columns	Column 0	Column 1	Column 2
Row 0		Book[0][0][0]	Book[0][0][1]	Book[0][0][2]
Row 1		Book[0][1][0]	Book[0][1][1]	Book[0][1][2]

Book – Page[1]:
Rows/Columns	Column 0	Column 1	Column 2
Row 0		Book[1][0][0]	Book[1][0][1]	Book[1][0][2]
Row 1		Book[1][1][0]	Book[1][1][1]	Book[1][1][2]

Or better yet:

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
};

Or in other terms it would look like:

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

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>
#include <stdio.h>
#include <string.h>

int main() {
	int i, j, p;				// For loops
	int pNum;				// Page number
	int pGraphs;				// Paragraphs per page
	char paragraph[4][256];			// Our paragraphs
	char ***Book;				// Our book

	strcpy(paragraph[0], "Pointers are awesome! Now that I have learned 3-dimensional arrays, I can use this knowledge to write my own programs!");
	strcpy(paragraph[1], "Through learning one-dimensional to multi-dimensional, I now know that pointers aren't as bad as they may seem.");
	strcpy(paragraph[2], "It may be hard to write your own book typing all the text in a 3-dimensional array, but it works for an example!");
	strcpy(paragraph[3], "Good luck with using 3-dimensional pointers, I hope this has helped you alot in understanding how they work.");

	j = p = 0;				// Initialize loop variables
	pNum = 2;				// 2 pages
	pGraphs = 4;				// 2 paragraphs per page

	// Allocate memory
	Book = (char ***)malloc(pNum * (sizeof *Book));
	if (Book) {
		for (i = 0; i < pNum; i++) {
			Book[i] = (char **)malloc(pGraphs * (sizeof **Book));
			if (Book[i]) {
				for (j = 0; j < pGraphs; j++) {
					Book[i][j] = (char *)malloc(strlen(paragraph[j]) + 1 * (sizeof ***Book));
					if (Book[i][j])
						strcpy(Book[i][j], paragraph[j]);
				}
			}
		}
	}

	// 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]);
		free(Book[i]);
	}
	free(Book);

	return 0;
}

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.

I hope this tutorial shown the simplicity of pointers. Feedback is greatly appreciated, and good luck with your future programming.


- Stack Overflow

Dave Sinkula commented: You should still fix 1.4, though. --Dave +1

Recommended Answers

All 11 Replies

In example 1.4 it is said that

++*ptr points to n[2].

That is wrong.

++*ptr will increment the value of the content of the location pointed by ptr.

in the code 1.1 which is used for reversing a A=3 and B=5 i am not quite sure why u have used

void reverse(int *x, int *y);

this is there in the first line.....

even if u do not write this line there program shud work ... well as such here u r basically calling a function in the beginning

and then again u r calling the function reverse inside the main block also ...

dunn think this will work...

making call 2 times when one would work...

how i can use it in c++ please

and what adefintion of apointer?

++*ptr will increment the value of the content of the location pointed by ptr.

» Ah, yes. Thank you for pointing that out.

making call 2 times when one would work...

» The only reason I did this was because the first call on top is a declaration of my function, so my whole code is familiar with it. Some compilers compile source code from top to bottom, so if you write a function and call on one beneath it, it may not know what it is just yet. I only do it for good practice.

and what adefintion of apointer?

» The difference between C and C++ pointers aren't much different. In fact check out this link, it covers most of the same syntax.

could you help me in some questions

I have a homework to show which of these codes are wrong if i is an integer and p, q are pointers to integers
p*&i;
p=&*i;
i=*&*p;
i=*&p;

if my fundamentals about c are not clear then i can understand pointer

if my fundamentals about c are not clear then i can understand pointer

There have been general misconception that one has to learn c to have better understanding on C++. This is not at all true. And this is also true for the pointers also. Its unnecessary to go to C to learn C++.

Good tutorial .

Thanks for the person who made it available this for us .... :D

>>*pch = ch[0];
Example 1-1

Above line is incorrect because pointer pch is uninitialized.

>>ptr = &n[0];
Example 1-3.

This can also be simplified like below: The & operator is not necessary.
ptr = n;

>>ca[3] = '\0';
Figure 2-1
The above is wrong because array ca only has 3 elements, not 4.

>>ptr = &text[0]; // not recommen
Example 2-2

Why is this not recommended? You did not explain that statement.

Example 2-3: I disagree -- it seems to add a lot more complexity to such a simple and elementry operation. The example in Example 2-2 works just find and is the one most frequently used.

>>ptr = (char *)malloc(6);]
Code 2-1
malloc() should not be typecase in C, but is required in C++

Example 3-1 is a very good example of why not to use strcpy() -- because it can easily cause buffer overrun and scribble all over the program's memory.

>> ptr = (char **)malloc(rows * (sizeof *ptr)); // allocate room for rows
Code 3-1
sizeof(*ptr) will result most likely always return 1 becuase sizeof(char) is always 1. This is clearly not what you are attempting to do. The program needs to allocate room for rows number of pointers, like this:

ptr = malloc(rows * sizeof (char*)) // allocate room for rows

>> ptr = (char *)malloc(strlen(word) + 1 * (sizeof **ptr));

Same problem as above. Should be this:

ptr[i] = malloc(strlen(word[i]) + 1 * sizeof(char **)));

Figure 4-1 needs some rework to fix up the sizeof() errors, as identified above. sizeof(char*) is not the same as sizeof(char) on most operating systems. And the sizeof(*Book) is the same thing as sizeof(char) -- guarenteed by C standards to always be 1.


Overall, give you B+ for good tutorial. Correct the mistakes and it can be a great tutorial.

ptr[i] = malloc(strlen(word[i]) + 1 * sizeof(char **)));

Overall, give you B+ for good tutorial. Correct the mistakes and it can be a great tutorial.

nah, this was wrong anyway.

SO BE CAREFUL FOLKS! it has to be:

ptr[i] = malloc((strlen(word[i])+1) * sizeof(char **)));

instead of

ptr[i] = malloc(strlen(word[i]) + 1 * sizeof(char **)));

you know * binds stronger than + ... good old math :-P

damn someone should change this in the tutorial... I took me some nerves to find out why my app was crashing :-P

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.