- 1 1. Introduction
- 2 2. Basics of Structures and Pointers
- 3 3. What is a Structure?
- 4 Summary
- 5 4. Basics of Pointers
- 6 Summary
- 7 5. Combining Structures and Pointers
- 8 Summary
- 9 6. Using Structures with Functions
- 10 Summary
- 11 7. Using Pointers Inside Structures
- 12 Summary
- 13 8. Practical Example: Creating a Linked List
- 14 Summary
- 15 9. Common Mistakes and Debugging Methods
- 16 Summary
- 17 10. Conclusion
- 18 Final Thoughts
1. Introduction
The C programming language is widely used in system development and embedded programming. Among its many features, structures and pointers are essential for efficient data management and memory operations. In this article, we will explain these concepts in detail, from the basics to more advanced applications.
By reading this article, you will gain a solid understanding of the role of structures and pointers in C, and you will be able to master their usage through practical code examples. Even beginners will find it easy to follow, as we include concrete examples step by step.
2. Basics of Structures and Pointers
What is a Structure?
A structure is a data structure that allows you to group together multiple data types into a single unit. For example, it is useful when you want to manage a person’s information (such as name, age, and height) as one entity.
The following code shows a basic definition and usage example of a structure.
#include <stdio.h>
// Definition of a structure
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person person1; // Declare a structure variable
// Assign data
strcpy(person1.name, "Taro");
person1.age = 20;
person1.height = 170.5;
// Display data
printf("Name: %sn", person1.name);
printf("Age: %dn", person1.age);
printf("Height: %.1f cmn", person1.height);
return 0;
}
In this example, we define a structure called Person
, which groups three different data types into one structure. This makes it easier to manage related data collectively.
What is a Pointer?
A pointer is a variable that stores the memory address of another variable. It is used to dynamically manipulate memory within a program. Below is a basic example of a pointer:
#include <stdio.h>
int main() {
int a = 10;
int *p; // Declare a pointer variable
p = &a; // Assign the address of variable a to the pointer
printf("Value of a: %dn", a);
printf("Value pointed to by p: %dn", *p);
return 0;
}
In this example, the pointer variable p
is used to access the value of variable a
. Pointers play a powerful role in memory operations, but improper use may lead to bugs or memory leaks, so caution is required.
Relationship Between Structures and Pointers
By combining structures and pointers, you can perform more flexible data manipulation. We will cover this in more detail later, but by mastering the basic concepts, you will be able to move smoothly into advanced applications.

3. What is a Structure?
Basic Definition of a Structure
A structure is a data structure used to group together multiple types of data. In C, it is commonly used to organize related information and make data management more concise.
Here is an example of a structure definition:
struct Person {
char name[50];
int age;
float height;
};
In this example, we define a structure called Person
with the following three members:
name
: stores a string (array) for the nameage
: stores an integer value for ageheight
: stores a floating-point number for height
Defining a structure creates a “type” that you can use to declare actual variables.
Declaring and Using Structure Variables
To use a structure, you first need to declare a variable. Here’s an example:
#include <stdio.h>
#include <string.h>
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person person1; // Declare a structure variable
// Assign data
strcpy(person1.name, "Taro");
person1.age = 20;
person1.height = 170.5;
// Display data
printf("Name: %sn", person1.name);
printf("Age: %dn", person1.age);
printf("Height: %.1f cmn", person1.height);
return 0;
}
In this code, we declare a structure variable named person1
and assign values to its members.
Initializing Structures
You can also initialize a structure variable at the time of declaration:
struct Person person2 = {"Hanako", 25, 160.0};
This approach allows you to write concise code by initializing all members at once.
Arrays of Structures
If you want to manage multiple data items, you can use an array of structures:
struct Person people[2] = {
{"Taro", 20, 170.5},
{"Hanako", 25, 160.0}
};
for (int i = 0; i < 2; i++) {
printf("Name: %s, Age: %d, Height: %.1f cmn", people[i].name, people[i].age, people[i].height);
}
In this example, two sets of data are stored in an array, and processed together using a loop.
Passing Structures to Functions
Structures can also be passed to functions for processing. Here’s an example:
void printPerson(struct Person p) {
printf("Name: %s, Age: %d, Height: %.1f cmn", p.name, p.age, p.height);
}
This function takes a structure as an argument and prints its information.
Summary
Structures are very convenient for managing related data as a single unit. By mastering the basics, you can make your data organization and access more efficient.

4. Basics of Pointers
What is a Pointer?
A pointer is a powerful C feature that lets you directly work with memory addresses. In this section, we’ll cover the basic concepts of pointers, how to declare and use them, and walk through practical examples.
Declaring and Initializing Pointers
Pointers are declared by placing an *
before the variable name:
int a = 10; // Regular variable
int *p; // Declare a pointer variable
p = &a; // Assign the address of a to p
*p
represents the value stored at the address the pointer refers to (dereferencing).&a
retrieves the address of variablea
(address-of operator).
Manipulating Values with Pointers
Here’s an example of modifying values using pointers:
#include <stdio.h>
int main() {
int a = 10; // Regular variable
int *p = &a; // Declare pointer p and assign a’s address
printf("Value of a: %dn", a); // 10
printf("Address of a: %pn", &a); // Address of a
printf("Value stored in p (address): %pn", p);
printf("Value pointed to by p: %dn", *p); // 10
*p = 20; // Change value through pointer
printf("New value of a: %dn", a); // 20
return 0;
}
In this code, we use pointer p
to indirectly modify the value of variable a
.
Arrays and Pointers
You can also access array elements using pointers:
#include <stdio.h>
int main() {
int arr[3] = {10, 20, 30};
int *p = arr; // Points to the first element of the array
printf("First element: %dn", *p); // 10
printf("Second element: %dn", *(p+1)); // 20
printf("Third element: %dn", *(p+2)); // 30
return 0;
}
In this example, we use pointer p
to access each element of the array.
Summary
Pointers are a fundamental feature of C that enable efficient memory management and flexible program design. In this section, we covered the basics of pointers and how to use them. In the next section, we’ll dive into “5. Combining Structures and Pointers”.
5. Combining Structures and Pointers
Basics of Structure Pointers
By combining structures and pointers, you can achieve more flexible and efficient data management. In this section, we’ll cover the basics of using structure pointers along with practical examples.
Here’s a basic example of a structure pointer:
#include <stdio.h>
#include <string.h>
// Structure definition
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person person1 = {"Taro", 20, 170.5}; // Initialize structure
struct Person *p = &person1; // Declare and initialize a structure pointer
// Access data through the pointer
printf("Name: %sn", p->name);
printf("Age: %dn", p->age);
printf("Height: %.1f cmn", p->height);
// Modify values through the pointer
p->age = 25;
printf("Updated Age: %dn", p->age);
return 0;
}
Working with Dynamic Memory Allocation
Structure pointers work well with dynamic memory allocation, making it easier to handle large amounts of data. Here’s an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Structure definition
struct Person {
char name[50];
int age;
float height;
};
int main() {
// Create a structure using dynamic memory allocation
struct Person *p = (struct Person *)malloc(sizeof(struct Person));
// Assign data
strcpy(p->name, "Hanako");
p->age = 22;
p->height = 160.0;
// Display data
printf("Name: %sn", p->name);
printf("Age: %dn", p->age);
printf("Height: %.1f cmn", p->height);
// Free allocated memory
free(p);
return 0;
}
Arrays and Structure Pointers
You can also combine arrays and structure pointers for efficient management of multiple data items:
#include <stdio.h>
#include <string.h>
// Structure definition
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person people[2] = {{"Taro", 20, 170.5}, {"Hanako", 25, 160.0}};
struct Person *p = people; // Pointer to the first element of the array
for (int i = 0; i < 2; i++) {
printf("Name: %sn", (p + i)->name);
printf("Age: %dn", (p + i)->age);
printf("Height: %.1f cmn", (p + i)->height);
}
return 0;
}
Summary
By combining structures and pointers, you can improve efficiency in data management and gain flexibility in memory operations. This section covered the basics as well as how to use dynamic memory allocation.

6. Using Structures with Functions
Ways to Pass Structures to Functions
There are two main ways to pass structures to functions:
- Pass by Value
A full copy of the structure is passed to the function. For large data, this may consume more memory. - Pass by Reference (Pointer Passing)
By passing the address of a structure, you improve memory efficiency and can directly modify the original data within the function.
Example: Pass by Value
#include <stdio.h>
#include <string.h>
// Structure definition
struct Person {
char name[50];
int age;
};
// Function: pass by value
void printPerson(struct Person p) {
printf("Name: %sn", p.name);
printf("Age: %dn", p.age);
}
int main() {
struct Person person1 = {"Taro", 20};
printPerson(person1); // Pass by value
return 0;
}
In this example, the printPerson
function takes a structure by value. However, passing large structures this way may not be memory-efficient.
Example: Pass by Reference (Pointer Passing)
#include <stdio.h>
#include <string.h>
// Structure definition
struct Person {
char name[50];
int age;
};
// Function: pass by pointer
void updateAge(struct Person *p) {
p->age += 1; // Increment age
}
void printPerson(const struct Person *p) {
printf("Name: %sn", p->name);
printf("Age: %dn", p->age);
}
int main() {
struct Person person1 = {"Hanako", 25};
printf("Before update:n");
printPerson(&person1);
updateAge(&person1); // Update age via pointer
printf("After update:n");
printPerson(&person1);
return 0;
}
This example shows how to pass a structure by pointer, allowing the function updateAge
to directly modify the original data.
Dynamic Memory and Functions
You can also handle dynamically allocated memory in functions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Structure definition
struct Person {
char name[50];
int age;
};
// Function: initialize memory
struct Person *createPerson(const char *name, int age) {
struct Person *p = (struct Person *)malloc(sizeof(struct Person));
strcpy(p->name, name);
p->age = age;
return p;
}
// Function: display information
void printPerson(const struct Person *p) {
printf("Name: %sn", p->name);
printf("Age: %dn", p->age);
}
// Function: free memory
void deletePerson(struct Person *p) {
free(p);
}
int main() {
struct Person *person1 = createPerson("Taro", 30); // Allocate memory dynamically
printPerson(person1);
deletePerson(person1); // Free memory
return 0;
}
This example shows how to allocate memory dynamically for a structure, manage it with functions, and free it properly to ensure safe programming.
Summary
In this section, we explored how to use functions with structure pointers. Using pointers allows data sharing between functions and more efficient memory management.

7. Using Pointers Inside Structures
Advantages of Using Pointers in Structures
By including pointers inside a structure, you can achieve more flexible and efficient data management and memory operations. In this section, we’ll cover the basics and practical applications of using pointers within structures.
Basic Example: Dynamic String Management
The following example demonstrates how to use a pointer inside a structure to dynamically manage strings:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Structure definition
struct Person {
char *name; // Pointer for name
int age;
};
// Memory allocation and initialization
void setPerson(struct Person *p, const char *name, int age) {
p->name = (char *)malloc(strlen(name) + 1); // Allocate memory dynamically
strcpy(p->name, name);
p->age = age;
}
// Display information
void printPerson(const struct Person *p) {
printf("Name: %sn", p->name);
printf("Age: %dn", p->age);
}
// Free allocated memory
void freePerson(struct Person *p) {
free(p->name); // Free dynamically allocated memory
}
int main() {
struct Person person;
// Set data
setPerson(&person, "Taro", 30);
// Display data
printPerson(&person);
// Free memory
freePerson(&person);
return 0;
}
In this example, dynamic memory allocation allows managing string data without being limited by fixed array sizes. After use, memory is freed with free
.
Combining Arrays and Pointers
When handling multiple data items, pointers allow for flexible and dynamic management:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Structure definition
struct Student {
char *name;
int score;
};
// Memory allocation and initialization
struct Student *createStudent(const char *name, int score) {
struct Student *s = (struct Student *)malloc(sizeof(struct Student));
s->name = (char *)malloc(strlen(name) + 1);
strcpy(s->name, name);
s->score = score;
return s;
}
// Free allocated memory
void freeStudent(struct Student *s) {
free(s->name);
free(s);
}
int main() {
// Array of student information
struct Student *students[2];
students[0] = createStudent("Taro", 85);
students[1] = createStudent("Hanako", 90);
// Display data
for (int i = 0; i < 2; i++) {
printf("Name: %s, Score: %dn", students[i]->name, students[i]->score);
}
// Free memory
for (int i = 0; i < 2; i++) {
freeStudent(students[i]);
}
return 0;
}
This program dynamically manages student data, allowing flexible handling of multiple items.
Summary
By using pointers inside structures, you can design dynamic memory management and complex data structures more easily. This section covered both basic and applied examples.

8. Practical Example: Creating a Linked List
Basic Structure of a Linked List
A linked list is a data structure that manages data in nodes, allowing dynamic insertion and deletion of elements. In C, you can implement it using structures and pointers.
Its structure looks like this:
[Data | Pointer to next node] → [Data | Pointer to next node] → NULL
Each node holds data and a pointer to the next node. The last node’s pointer is NULL
, marking the end of the list.
Defining a Node
Here’s the definition of a node for a linked list:
#include <stdio.h>
#include <stdlib.h>
// Node definition
struct Node {
int data; // Data
struct Node *next; // Pointer to next node
};
Appending a Node
The following code appends a new node at the end of the linked list:
void append(struct Node **head, int newData) {
// Create new node
struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
struct Node *last = *head; // Pointer to traverse to the end
newNode->data = newData; // Assign data
newNode->next = NULL; // New node points to NULL (end of list)
// If the list is empty
if (*head == NULL) {
*head = newNode;
return;
}
// Traverse to the end of the list
while (last->next != NULL) {
last = last->next;
}
// Add new node at the end
last->next = newNode;
}
Displaying Nodes
Here’s a function to print all nodes in the list:
void printList(struct Node *node) {
while (node != NULL) {
printf("%d -> ", node->data);
node = node->next;
}
printf("NULLn");
}
Deleting a Node
Here’s a function to delete a node with a specific value:
void deleteNode(struct Node **head, int key) {
struct Node *temp = *head, *prev;
// If the head node itself holds the key
if (temp != NULL && temp->data == key) {
*head = temp->next;
free(temp);
return;
}
// Search for the node to be deleted
while (temp != NULL && temp->data != key) {
prev = temp;
temp = temp->next;
}
// Key not found
if (temp == NULL) return;
// Unlink the node
prev->next = temp->next;
free(temp);
}
Full Example: Linked List Operations
Here’s a complete program combining the above functions:
#include <stdio.h>
#include <stdlib.h>
// Node definition
struct Node {
int data;
struct Node *next;
};
// Append node
void append(struct Node **head, int newData) {
struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
struct Node *last = *head;
newNode->data = newData;
newNode->next = NULL;
if (*head == NULL) {
*head = newNode;
return;
}
while (last->next != NULL) {
last = last->next;
}
last->next = newNode;
}
// Print list contents
void printList(struct Node *node) {
while (node != NULL) {
printf("%d -> ", node->data);
node = node->next;
}
printf("NULLn");
}
// Delete node
void deleteNode(struct Node **head, int key) {
struct Node *temp = *head, *prev;
if (temp != NULL && temp->data == key) {
*head = temp->next;
free(temp);
return;
}
while (temp != NULL && temp->data != key) {
prev = temp;
temp = temp->next;
}
if (temp == NULL) return;
prev->next = temp->next;
free(temp);
}
int main() {
struct Node *head = NULL;
// Add nodes
append(&head, 10);
append(&head, 20);
append(&head, 30);
printf("Linked list:n");
printList(head);
// Delete node
deleteNode(&head, 20);
printf("After deleting 20:n");
printList(head);
return 0;
}
Summary
In this section, we explained how to implement a linked list using structures and pointers.
Linked lists are widely used in algorithms and data management systems because they allow easy resizing and efficient insertion and deletion of elements.

9. Common Mistakes and Debugging Methods
Using structures and pointers in C is very powerful, but incorrect usage can cause crashes or unexpected behavior. In this section, we’ll cover common mistakes and how to fix them.
1. Uninitialized Pointers
Problem Example:
struct Node *p; // Pointer not initialized
p->data = 10; // Causes error
Cause:
Pointer p
is not initialized and points to an undefined memory address, leading to invalid memory access.
Solution:
Always initialize pointers to valid memory:
struct Node *p = (struct Node *)malloc(sizeof(struct Node)); // Allocate memory
p->data = 10; // Works correctly
2. Memory Leaks
Problem Example:
struct Node *p = (struct Node *)malloc(sizeof(struct Node));
// Memory not freed after use
Cause:
If memory allocated with malloc
is not freed, it remains occupied until the program terminates.
Solution:
Always free memory when no longer needed:
free(p);
For linked lists and other dynamic structures, free all nodes properly:
struct Node *current = head;
struct Node *next;
while (current != NULL) {
next = current->next; // Store next node
free(current); // Free current node
current = next; // Move to next node
}
3. Dangling Pointers
Problem Example:
struct Node *p = (struct Node *)malloc(sizeof(struct Node));
free(p); // Free memory
p->data = 10; // Access after free → undefined behavior
Cause:
After freeing memory, the pointer still refers to that location. Using it becomes unsafe.
Solution:
Set pointers to NULL
after freeing:
free(p);
p = NULL;
4. Dereferencing NULL Pointers
Problem Example:
struct Node *p = NULL;
p->data = 10; // Accessing NULL pointer → error
Cause:
Dereferencing a NULL
pointer results in a segmentation fault.
Solution:
Check if a pointer is NULL
before using it:
if (p != NULL) {
p->data = 10;
} else {
printf("Pointer is NULLn");
}
Debugging Methods
1. Using a Debugger
Tools like GDB allow you to check variable values and program flow at runtime:
gcc -g program.c -o program // Compile with debug info
gdb ./program
2. Debugging with printf
Print addresses and values to verify behavior:
printf("Address: %p, Value: %dn", (void *)p, *p);
3. Detecting Memory Leaks
Use valgrind
to detect leaks and invalid memory access:
valgrind --leak-check=full ./program
Summary
In this section, we explained common mistakes when using structures and pointers in C, and how to debug them.
- Uninitialized pointers
- Memory leaks
- Dangling pointers
- Dereferencing NULL pointers
These issues can cause serious program errors. Always implement safeguards and test thoroughly.

10. Conclusion
Key Points Recap
In the previous sections, we covered structures and pointers in C from basics to practical applications. Let’s recap the main points:
- Structures Basics
- Useful for grouping multiple data types into one unit.
- Helps organize related data more efficiently.
- Pointers Basics
- Powerful feature to directly manipulate memory addresses.
- Essential for dynamic memory allocation and data referencing.
- Combining Structures and Pointers
- Improves efficiency in data management.
- Enables flexible handling with dynamic memory allocation.
- Functions and Structure Pointers
- Allows direct modification of data across functions.
- Supports memory-efficient program design.
- Using Pointers Inside Structures
- Enables dynamic memory management and handling of complex data structures.
- Efficiently manages linked lists, matrices, and more.
- Implementing Linked Lists
- Learned how to build dynamic data structures using structures and pointers.
- Supports easy addition and deletion of elements.
- Common Mistakes & Debugging
- Learned how to prevent and fix pointer-related errors like memory leaks.
- Introduced debugging tools for safer programming.
Practical Applications
With these concepts, you can now challenge yourself with:
- File Management Systems
- Use structures and pointers to manage file metadata.
- Dynamic Data Structures
- Extend linked lists into stacks and queues.
- Game Development & Simulations
- Manage characters and states using structures efficiently.
- Database Management Systems
- Use structures and pointers for record creation, deletion, and search operations.
Next Steps
- Customize Sample Code
- Modify provided examples to suit your own projects.
- Learn Advanced Data Structures
- Study doubly linked lists, trees, and graphs.
- Combine with Algorithms
- Implement sorting and searching algorithms using structures and pointers.
- Improve Debugging & Optimization
- Use memory analysis tools to optimize performance and stability.
Final Thoughts
Structures and pointers in C are essential concepts that enable efficient and flexible program design. In this article, we’ve covered them in detail, from basics to advanced use cases, with practical code examples.
By applying these techniques in real projects, you’ll be better prepared for advanced system development and algorithm design. Keep practicing and refining your skills to take your C programming to the next level!