目次
- 1 1. Introduction
- 2 2. What Is a Pointer Variable?
- 3 3. Basic Pointer Operations
- 4 4. Relationship Between Arrays and Pointers
- 5 5. Functions and Pointers
- 6 6. Pointer Application Examples
- 7 7. Common Errors and Their Solutions
- 8 8. Summary
1. Introduction
Understanding pointer variables is when learning C. Beginners may find concepts like “address” and “indirect reference” confusing, but pointers are a fundamental element of C, and mastering them enables more advanced programming. In this article, we will start from the basics of “what is a pointer variable?” and gradually and carefully explain practical code examples, as well as the relationship with arrays and functions and advanced usage. To make the meaning of technical terms and the mental model of how they work easy to grasp, we will include diagrams and sample code, so even readers who are not yet comfortable with C can read with confidence. Pointers become a very powerful and convenient feature once you get used to them. They expand the scope of programs through dynamic memory manipulation and passing values to functions. Through this article, we hope you deepen your understanding of pointer variables and take your C development skills to the next level.2. What Is a Pointer Variable?
Basic Concept of Pointer Variables
In C, a pointer variable is a variable that stores a memory address. Whereas regular variables store the data itself, a pointer stores the location (address) where another variable is stored. For example, consider the following code.int a = 10;
int *p = &a;
In this case, variable a
holds the value 10, and p
holds the address of a
. By writing *p
, you can indirectly refer to the value at the address pointed to by p
(which is 10 in this case).Relationship Between Addresses and Memory
All data is stored in a computer’s memory. Memory is addressed byte by byte. A pointer uses this address information as a means to specify which memory location to operate on. Using pointers enables the following:- Directly modify variable contents across functions
- Flexibly manipulate array elements
- Dynamic memory management using heap memory
Declaration and Initialization of Pointer Variables
Pointer variables are declared by appending an asterisk (*
) to the target data type.int *p; // pointer to an int variable
char *c; // pointer to a char variable
Typically, you assign the address of another variable using the &
operator.int a = 5;
int *p = &a; // store the address of a in p
The important point here is that the “type of the pointer” and the “type of the value the pointer points to” must match. Storing the address of a char
in a pointer that expects an int
may lead to undefined behavior.3. Basic Pointer Operations
Once you understand the basics of pointer variables, let’s look at exactly how to use them. Here we introduce the essential operators for pointer manipulation, reading and writing values, and basic operations between pointers.Address Operator (&) and Indirection Operator (*)
Address Operator (&)
&
is called the “address operator” and is used to obtain the memory address of a variable.int a = 10;
int *p = &a;
In this example, the address of variable a
is stored in p
. Thus, p
holds the location where a
is stored.Indirection Operator (*)
*
is called the “indirection operator” or “dereference operator” and is used when a pointer references or modifies the contents at the address it points to.int a = 10;
int *p = &a;
printf("%d
", *p); // Result: 10
In this way, writing *p
allows you to indirectly obtain the value (contents) of a
. Conversely, writing as shown below lets you modify the value.*p = 20;
printf("%d
", a); // Result: 20
Getting and Modifying Values: Pointer Usage Example
By using pointers, you can directly change a variable’s value from another function. Below is a basic example. pre>void updateValue(int *p) {
*p = 100;
}
int main() {
int num = 50;
updateValue(&num);
printf(“%d
“, num); // Result: 100
return 0;
} As shown, pointers are also useful when updating values inside functions. In C, passing a value to a function typically creates a copy (pass‑by‑value), but using a pointer allows you to operate directly on the original value.Pointer Addition and Subtraction
Pointers support addition and subtraction, which is extremely handy when working with arrays or contiguous memory regions.int arr[3] = {10, 20, 30};
int *p = arr;
printf("%d
", *p); // 10
p++;
printf("%d
", *p); // 20
The important point here is that p++
moves the pointer to the address of the next int variable. If an int is 4 bytes, p++
effectively adds 4 to the address. Understanding these basic pointer operations is the first step in building a foundation for memory manipulation in C. In the next chapter, we’ll explore the relationship between pointers and arrays in more detail.4. Relationship Between Arrays and Pointers
In the C language, arrays and pointers have a very close relationship. It can be a confusing point for beginners, but understanding this relationship enables more flexible and efficient array manipulation.Array Names Can Be Treated Like Pointers
In C, an array name is treated as a pointer that points to the address of the first element. For example, see the following code.int arr[3] = {10, 20, 30};
printf("%d
", *arr); // Result: 10
At this point, arr
points to the same address as &arr[0]
, and *arr
refers to the first element of the array (arr[0]
).Accessing Arrays Using Pointers
Arrays can be accessed by index, but the same operations are possible using pointers.int arr[3] = {10, 20, 30};
int *p = arr;
printf("%d
", p[1]); // Result: 20
Here, p[1]
has the same meaning as *(p + 1)
. In other words, using a pointer you can also write it as follows.printf("%d
", *(arr + 2)); // Result: 30
Thus, index notation and pointer arithmetic essentially do the same thing.Differences Between Pointer Arithmetic and Array Indexing
Arrays and pointers are similar, but it is important to note that they are not exactly the same.1. Obtaining Size
When you use an array name, you can obtain its size withsizeof
, but once it is assigned to a pointer, the size information is lost.int arr[5];
int *p = arr;
printf("%zu
", sizeof(arr)); // Result: 20 (5×4 bytes)
printf("%zu
", sizeof(p)); // Result: 8 (in a 64‑bit environment, a pointer is 8 bytes)
2. Ability to Reassign
An array name behaves like a constant pointer, and it cannot be changed by assignment.int arr[3];
int *p = arr;
p = p + 1; // OK
arr = arr + 1; // Error (array name cannot be reassigned)
Benefits of Mastering Pointers and Arrays
- Using pointers allows you to manipulate memory space flexibly
- Array processing becomes faster and more efficient (pointer arithmetic can be slightly faster than indexing in some cases)
- When passing an array to a function, only the address of the first element is passed, not the actual array, so knowledge of pointers is essential
5. Functions and Pointers
In C, passing variables to functions uses pass-by-value (call by value) by default. Therefore, modifying an argument inside a function does not affect the original variable. However, using pointers allows a function to directly manipulate the original variable’s value. This chapter explains the relationship between functions and pointers, how to rewrite values, the basics of function pointers, and how to use pointers in functions.Rewriting Values Using Pointers
First, if you want to change a variable’s value from within a function, you need to use a pointer.Example: Without Pointers
void update(int x) {
x = 100;
}
int main() {
int a = 10;
update(a);
printf("%d
", a); // Result: 10 (unchanged)
return 0;
}
In this case, a copy of a
is passed to the function, so a
itself is not changed.Example: Using Pointers
void update(int *x) {
*x = 100;
}
int main() {
int a = 10;
update(&a);
printf("%d
", a); // Result: 100 (changed)
return 0;
}
Thus, by passing a variable’s address to a function, you can modify the original value. This technique, known as “pass-by-reference (call by reference)”, is widely used.Arrays and Functions Relationship
In C, when an array is passed to a function it is automatically treated as a pointer. In other words, the address of the first element of the array is passed to the function, allowing its contents to be modified inside the function.void setValues(int *arr, int size) {
for (int i = 0; i < size; i++) {
arr[i] = i * 10;
}
}
int main() {
int nums[3];
setValues(nums, 3);
printf("%d
", nums[1]); // Result: 10
return 0;
}
As shown in this example, you can modify the contents from within a function simply by passing the array name.Basics of Function Pointers
In C, you can also store a function’s address in a variable and call it. This is a function pointer.Declaration and Example:
int add(int a, int b) {
return a + b;
}
int main() {
int (*funcPtr)(int, int); // function pointer that returns an int and takes two int arguments
funcPtr = add;
int result = funcPtr(3, 4);
printf("%d
", result); // Result: 7
return 0;
}
Function pointers are used when you want to dynamically select and execute a function, or implement callback functions. Since you can obtain a function’s address simply by using its name, they enable flexible programming.Practical Use Cases
- Array sorting by passing a comparison function as a pointer
- Menu-driven programs where each option’s function is managed with a function pointer
- Event-driven processing and callback functions implementation (GUI, embedded, game development, etc.)
6. Pointer Application Examples
Once you understand the basic usage of pointers, let’s learn advanced usage methods. Pointers in C are essential for dynamic memory manipulation and implementing sophisticated data structures. In this chapter, we introduce three advanced techniques that are frequently used in practice.Dynamic Memory Allocation (malloc
and free
)
In C, you can dynamically allocate memory as needed at runtime. This is made possible by the standard library function malloc
. The allocated memory is accessed via a pointer, and you must release it with free
when done.Example: Dynamically Allocating an Integer
#include <stdio.h>
#include <stdlib.h>
int main() {
int *p = (int *)malloc(sizeof(int)); // allocate memory for one int
if (p == NULL) {
printf("Memory allocation failed\n");
return 1;
}
*p = 123;
printf("%d\n", *p); // result: 123
free(p); // free the memory
return 0;
}
Notes:
malloc
returns the starting address of the allocated memory- Always check the return value for NULL
- When finished using memory, always release it with
free
Pointer to Pointer (Double Pointer)
A pointer that holds the address of another pointer, i.e., a pointer to a pointer, is also commonly used in C. It is especially useful when you need to modify a pointer inside a function or work with two-dimensional arrays.Example: Initializing a Pointer Inside a Function
void allocate(int **pp) {
*pp = (int *)malloc(sizeof(int));
if (*pp != NULL) {
**pp = 42;
}
}
int main() {
int *p = NULL;
allocate(&p);
printf("%d\n", *p); // result: 42
free(p);
return 0;
}
Common Use Cases:
- Array of arrays (2D arrays)
- When a struct contains a variable-length array
- Handling multiple strings (e.g., char *argv)
Combining Function Pointers with Arrays
Storing function pointers in an array and dynamically selecting and invoking a function based on the situation is also a common advanced technique in C.Example: Simple Menu Selection
#include <stdio.h>
void hello() { printf("Hello\n"); }
void bye() { printf("Goodbye\n"); }
int main() {
void (*funcs[2])() = {hello, bye};
int choice = 0;
printf("0: hello, 1: bye > ");
scanf("%d", &choice);
if (choice >= 0 && choice < 2) {
funcs[choice](); // function call
}
return 0;
}
Such a design is also useful for state management and event-driven programming. Advanced pointer techniques require more than just coding ability; they demand design skills that consider memory and execution control. However, once mastered, they enable you to fully leverage the power of C.
7. Common Errors and Their Solutions
Pointers are a very powerful feature, but misusing them can cause bugs and security holes. This chapter explains the errors that frequently occur when using pointers in C and the measures to prevent them.Using Uninitialized Pointers
The most basic yet dangerous case is using an uninitialized pointer. A pointer does not point to a valid address merely by being declared.Bad Example:
int *p;
*p = 10; // Undefined behavior! p does not point anywhere
Solution:
- Always initialize pointers before using them
- Perform a
NULL
check before use
int *p = NULL;
// Allocate memory or assign a valid address before use
Dereferencing a NULL Pointer
If a pointer points toNULL
and you dereference it with *p
, the program will crash. This is a very common bug.Example:
int *p = NULL;
printf("%d
", *p); // Runtime error (segmentation fault, etc.)
Solution:
- Check that the pointer is not
NULL
before using it
if (p != NULL) {
printf("%d
", *p);
}
Memory Leak
If you forget tofree
dynamically allocated memory, a “memory leak” occurs where memory is not released and accumulates. This is fatal for long-running programs or embedded systems.Example:
int *p = (int *)malloc(sizeof(int));
// Not freeing after processing → memory leak
Solution:
- Always
free
after use - Be aware of matching
malloc
andfree
- Use memory leak detection tools (e.g., Valgrind) during development
Dangling Pointer
A pointer that points to memory after it has beenfree
d is called a “dangling pointer”, and reusing it causes undefined behavior.Example:
int *p = (int *)malloc(sizeof(int));
free(p);
*p = 123; // Error! Accessing memory that has already been freed
Solution:
- After
free
, always assignNULL
to invalidate it
free(p);
p = NULL;
Out-of-Bounds Array Access
When performing index arithmetic with pointers, you may unintentionally exceed the array bounds, which is also very dangerous and can cause bugs and vulnerabilities.Example:
int arr[3] = {1, 2, 3};
printf("%d
", *(arr + 3)); // Undefined behavior (arr[3] does not exist)
Solution:
- Always verify that you are accessing within a valid range
- Enforce “boundary checks” in loops
Double-Freeing the Same Pointer
If you callfree
on the same memory address twice, the program may crash.Solution:
- By setting the pointer to NULL after
free
, you can prevent double free
free(p);
p = NULL;
These errors can be prevented by following the basics and coding carefully. Especially for beginners, adhering to the rules of “initialization”, “NULL checks”, and “consistent use of free” leads to bug‑free code.8. Summary
In C, pointer variables are a fundamental yet deeply important element. This article has progressively covered everything from the basics of “What is a pointer?” to applications such as arrays, functions, memory management, and function pointers.Recap of Learned Points
- Pointer variables are variables that store the address of data and are manipulated using
*
(indirection operator) and&
(address operator). - Arrays and pointers are closely related, and an array name can be treated as a pointer to its first element.
- Functions and pointers combined enable “pass-by-reference” style direct manipulation of variables within functions, and using function pointers allows flexible function calls.
- Techniques such as dynamic memory management (malloc/free) and double pointers support more practical and flexible program design.
- On the other hand, pointer-specific errors such as uninitialized pointers, NULL dereferences, memory leaks, and dangling pointers are common, requiring careful handling.
Advice for Beginners
Pointers often get a reputation for being “hard” or “scary,” but that’s because they’re used as a black box. By thoroughly understanding what addresses mean and how memory works, anxiety turns into confidence. Following these steps can help solidify your learning:- Trace sample code by hand on paper and diagrams
- Use
printf
to visualize and verify addresses and values - Leverage
Valgrind
and other memory-checking tools - Write several small pointer manipulation practice programs
Next Steps
The content covered in this article spans from basic to intermediate topics on C pointers. To deepen your understanding further, consider moving on to the following topics.- Structures and pointers
- String manipulation using pointers
- File I/O and pointers
- Multidimensional array operations
- Callback design using function pointers