- 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 Applications
- 7 7. Common Errors and Their Solutions
- 8 8. Summary
1. Introduction
When learning the C language, understanding “pointer variables” is something you can’t avoid. For beginners, concepts like “addresses” or “indirect referencing” might seem difficult, but pointers are a fundamental and important element of the C language, and mastering them enables more advanced programming.
This article will explain step by step, from the basics of “What is a pointer variable?” to practical code examples, as well as relationships with arrays and functions, and advanced usage. To help you easily grasp the meaning of technical terms and the imagery of operations, we’ll include diagrams and sample code along the way, so even those not yet familiar with C can read on with confidence.
Pointers, once you get used to them, are extremely powerful and convenient features. They greatly expand the scope of your programs, such as through dynamic memory operations or passing values to functions. Through this article, I hope you deepen your understanding of pointer variables and elevate your C language development skills to the next level.
2. What is a Pointer Variable?
Basic Concepts of Pointer Variables
A pointer variable in C is a “variable that stores a memory address“. Unlike regular variables that store the data itself, pointers store the address of where another variable is located.
For example, consider the following code.
int a = 10;
int *p = &aIn this case, the variable a stores the value 10, and p stores the address of a. By writing *p, you can indirectly reference the value at the address pointed to by p (in this case, 10).
The Relationship Between Addresses and Memory
All data is stored in the computer’s memory, which has addresses assigned to each byte. Pointers use this address information to specify which memory location to manipulate.
By using pointers, the following becomes possible.
- Directly modify the contents of variables between functions
- Flexibly manipulate array elements
- Dynamic memory management using heap memory
In other words, pointers are an important mechanism that supports the flexibility and low-level control of C.
Declaration and Initialization of Pointer Variables
Pointer variables are declared by attaching an asterisk (*) to the target data type.
int *p; // Pointer to an int variable
char *c; // Pointer to a char variableAnd usually, the address of another variable is assigned using the & operator.
int a = 5;
int *p = &a // Store a's address in pWhat’s important here is that the “type of the pointer” and the “type of the value it points to” need to match. Storing a char-type address in a pointer for an int type may result in undefined behavior.
3. Basic Pointer Operations
Once you understand the basics of pointer variables, let’s take a concrete look at “how to use them.” Here, we introduce basic operation methods that are indispensable for pointer operations, such as operators, reading and writing values, and arithmetic 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 = &aIn this example, the address of the variable a is stored in p. p stores the “location where a is stored.”
Indirection Operator (*)
* is called the “indirection operator” or “dereference operator” and is used when referencing or modifying the contents of the address pointed to by the pointer.
int a = 10;
int *p = &a
printf("%d\n", *p); // Result: 10In this way, by writing *p, you can indirectly obtain the value (contents) of a. Conversely, you can also change the value by writing as follows.
*p = 20;
printf("%d\n", a); // Result: 20Obtaining and Modifying Values: Pointer Usage Examples
By using pointers, you can directly modify the value of a variable from another function. The following is a basic example.
void updateValue(int *p) {
*p = 100;
}
int main() {
int num = 50;
updateValue(#);
printf("%d\n", num); // Result: 100
return 0;
}In this way, pointers are also useful when updating values inside functions. In C language, when passing values to functions, it is basically by copy (pass by value), but by using pointers, it becomes possible to manipulate the original value itself.
Pointer Addition and Subtraction
Pointers can be added and subtracted. This is very convenient when handling arrays or contiguous memory areas.
int arr[3] = {10, 20, 30};
int *p = arr;
printf("%d\n", *p); // 10
p++;
printf("%d\n", *p); // 20The important point here is that when you do “p++“, it moves to the address of the next int-type variable. If the int type is 4 bytes, p++ adds “4” to the address.
In this way, understanding the basic operations of pointers is the first step in building the foundation for memory operations in C language. In the next chapter, let’s look in more detail at the relationship between pointers and arrays.
4. Relationship Between Arrays and Pointers
In C language, arrays and pointers have a very close relationship. This is a point that can be confusing for beginners, but understanding this relationship allows for more flexible and efficient array operations.
Array Names Can Be Treated Like Pointers
In C language, the array name is treated as a pointer to the address of the first element. For example, let’s look at code like the following.
int arr[3] = {10, 20, 30};
printf("%d\n", *arr); // Result: 10At this time, arr points to the same address as &arr[0], and *arr means the first element of the array (arr[0]).
Accessing Arrays Using Pointers
Arrays can be accessed using indices, but the same operations are possible using pointers.
int arr[3] = {10, 20, 30};
int *p = arr;
printf("%d\n", p[1]); // Result: 20Here, p[1] has the same meaning as *(p + 1) . In other words, using a pointer, you can also write it like this.
printf("%d\n", *(arr + 2)); // Result: 30In this way, index notation and pointer arithmetic are essentially doing the same thing.
Differences Between Pointer Arithmetic and Array Indices
Arrays and pointers are similar, but it is also important to note that they are not exactly the same.
1. Obtaining Size
When using an array name, you can obtain its size with sizeof, but once assigned to a pointer, the size is lost.
int arr[5];
int *p = arr;
printf("%zu\n", sizeof(arr)); // Result: 20 (5×4 bytes)
printf("%zu\n", sizeof(p)); // Result: 8 (on 64-bit environments, pointers are 8 bytes)2. Assignability
The array name is like a constant pointer and 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 flexibly manipulate memory space
- Array processing becomes faster and more efficient (pointer arithmetic can be slightly faster than indices in some cases)
- When passing arrays to functions, only the starting address is passed, not the actual array, so knowledge of pointers is essential
5. Functions and Pointers
In C, when passing variables to functions, pass by value is the basic method. Therefore, even if the argument is modified inside the function, it does not affect the original variable. However, by using pointers, it becomes possible to directly manipulate the value of the original variable from the function.
This chapter explains the relationship between functions and pointers, how to modify values, the basics of function pointers, and other ways to use pointers in functions.
Modifying Values Using Pointers
First, if you want to change the value of a variable from inside a function, you need to use a pointer.
Example: Without a Pointer
void update(int x) {
x = 100;
}
int main() {
int a = 10;
update(a);
printf("%d\n", 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 a Pointer
void update(int *x) {
*x = 100;
}
int main() {
int a = 10;
update(&a);
printf("%d\n", a); // Result: 100 (changed)
return 0;
}In this way, by passing the address of the variable to the function, you can modify the original value. This is widely used as a technique for “pass by reference.”
The Relationship Between Arrays and Functions
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, so the contents can 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\n", nums[1]); // Result: 10
return 0;
}As in this example, you can modify the contents from inside the function just by passing the array name as is.
Basics of Function Pointers
In C, you can store the address of a function in a variable and call it. This is a function pointer.
Declaration and Usage Example:
int add(int a, int b) {
return a + b;
}
int main() {
int (*funcPtr)(int, int); // Function pointer that returns int and takes two int arguments
funcPtr = add;
int result = funcPtr(3, 4);
printf("%d\n", result); // Result: 7
return 0;
}Function pointers are used for cases where you want to dynamically select and execute functions, or for implementing callback functions. Since you can obtain the function’s address just by using the function name, flexible programming is possible.
Practical Usage Scenarios
- Array sorting, passing comparison functions via pointers
- Menu selection programs, managing functions to execute for each option with function pointers
- Event-driven processing or callback functions (GUI, embedded systems, game development, etc.)
6. Pointer Applications
Once you understand the basic usage of pointers, let’s learn about advanced usage methods next. Pointers in the C language are essential for dynamic memory operations and implementing advanced data structures. In this chapter, we introduce three advanced techniques that are frequently used in practical work.
Dynamic Memory Allocation (malloc and free)
In the C language, you can dynamically allocate the memory needed at runtime. The malloc function from the standard library makes this possible. The allocated memory is referenced by a pointer, and it must be freed with free when you’re done using it.
Example: Dynamically Allocating an Integer
#include
#include
int main() {
int *p = (int *)malloc(sizeof(int)); // Allocate memory for one int
if (p == NULL) {
printf("Failed to allocate memory\n");
return 1;
}
*p = 123;
printf("%d\n", *p); // Output: 123
free(p); // Free the memory
return 0;
}Notes:
mallocreturns the starting address of the allocated memory- Always check the return value for NULL
- After using the memory, always free it with
free
In this way, the appeal of dynamic memory management using pointers is that you can allocate only the memory you need at the right time.
Pointer to Pointer (Double Pointer)
A pointer that holds the address of another pointer, or a “pointer to a pointer,” is also commonly used in the C language. It is particularly useful when you want to modify a pointer inside a function or when operating on 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); // Output: 42
free(p);
return 0;
}Common Use Cases:
- Array of Arrays (Two-Dimensional Arrays)
- When a Structure Contains a Variable-Length Array
- Handling Multiple Strings (e.g., char *argv)
Combining Function Pointers and Arrays
Storing function pointers in an array and dynamically switching and calling functions based on the situation is also a common advanced technique in the C language.
Example: Simple Menu Selection
#include
void hello() { printf("Hello"); }
void bye() { printf("Goodbye"); }
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;
}This kind of design is also useful for state management and event-driven programs.
Advanced techniques using pointers require not just coding ability, but also a strong awareness of memory and execution control in design. However, once you master them, you can fully unleash the power of the C language.

7. Common Errors and Their Solutions
Pointers are a very powerful feature, but misusing them can cause bugs and security vulnerabilities. This chapter explains common errors that occur when using pointers in C and measures to prevent them.
Using Uninitialized Pointers
The most basic yet dangerous case is using an uninitialized pointer. Simply declaring a pointer does not make it point to a valid address.
Bad Example:
int *p;
*p = 10; // Undefined behavior! p doesn't point anywhereSolution:
- Always initialize pointers before using them
- Perform a
NULLcheck before using them
int *p = NULL;
// Allocate memory or assign a valid address before usingDereferencing a NULL Pointer
Dereferencing NULL with *p when the pointer points to NULL will cause the program to 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
NULLbefore using it
if (p != NULL) {
printf("%d
", *p);
}Memory Leaks
Forgetting to free dynamically allocated memory causes a memory leak where memory accumulates without being released. This is fatal in long-running programs or embedded systems.
Example:
int *p = (int *)malloc(sizeof(int));
// Forgetting to free after processing → Memory leakSolution:
- Always
freeafter use mallocandfreeshould correspond to each other- Use memory leak detection tools (e.g., Valgrind) during development
Dangling Pointers
A pointer that points to memory after it has been freed is called a “dangling pointer” and can cause undefined behavior if reused.
Example:
int *p = (int *)malloc(sizeof(int));
free(p);
*p = 123; // Error! Accessing already freed memorySolution:
freeAfterfree, always assign NULL to invalidate it
free(p);
p = NULL;Out-of-Bounds Array AccessIndex operations using pointers can
accidentally exceed array bounds
. This is also very dangerous and can cause bugs or vulnerabilities.Example:
int arr[3] = {1, 2, 3};
printf("%d
", *(arr + 3)); // Undefined behavior (arr[3] does not exist)Solution:
- Always
confirm access is within valid bounds
- Thoroughly perform “bounds checking” in loop processing
Double Freeing the Same PointerPerforming free on the same memory address twice can cause the program to crash.
Solution:
freeBy setting the pointer to NULL afterfree,
prevent double free
free(p);
p = NULL;These errors can be prevented by following the basics and coding carefully
. Especially for beginners, adhering to rules like “initialization,” “NULL checks,” and “thorough freeing” leads to bug-free code.基本を守って丁寧にコーディングすることで防止可能です。特に初心者のうちは、「初期化」「NULLチェック」「freeの徹底」をルールとして守ることが、バグのないコードにつながります。
8. Summary
In C language, pointer variables are the most basic yet profoundly deep and important elements. This article has explained step by step from the basics of “What is a pointer?” to advanced examples such as arrays, functions, memory management, and function pointers.
Review of Key Points Learned
- Pointer variables are variables that store the address of data, and are manipulated by
*(indirection operator) and&(address operator) - Arrays and pointers are closely related, and array names can be treated as pointers indicating the starting address
- By combining functions and pointers, “pass by reference” that directly manipulates variables within functions becomes possible, and flexible function calls can also be achieved using function pointers
- Techniques such as dynamic memory management (malloc/free) and double pointers support more practical and flexible program design
- On the other hand, uninitialized pointers, NULL references, memory leaks, and dangling pointers are common pointer-specific errors, requiring careful handling
Advice for Beginners
Pointers often give the impression of being “difficult” or “scary,” but that’s because they are used as black boxes. By thoroughly understanding the meaning of addresses and the mechanics of memory, that anxiety will turn into confidence.
It would be good to solidify your learning with the following steps:
- Trace sample code by hand on paper with diagrams
printfto visualize and verify addresses and valuesValgrindand other memory check tools- Write multiple small pointer operation practice programs
Next Steps
The content introduced in this article covers C language pointers from beginner to intermediate levels. To deepen your understanding further, it would be good to move on to the following topics.
- Structures and pointers
- String manipulation using pointers
- File input/output and pointers
- Manipulating multidimensional arrays
- Callback design using function pointers
By understanding pointers, you will be able to experience the true fun and power of C language. You may feel confused at first, but let’s build your understanding steadily step by step. I hope this article serves as a helpful guide.



