Con trỏ void

Giả sử khi ta cần sử dụng 3 biến con trỏ kiểu: int, float, char, thì ta cần phải khai báo 3 con trỏ kiểu int, float, char. Nhưng trong ngôn ngữ lập trình C, có 1 dạng con trỏ đặc biệt (gọi là void pointer).
Khai báo:

void *p;

Đặc điểm của con trỏ void:
– Nó có thể lưu trữ địa chỉ của mọi kiểu biến dữ liệu

int a;
float b;
char c;
void *p;
p = &a; // address of a
p = &b; // address of b
p = &c; // address of c

Hạn chế:
– Ta không thể sử dụng trực tiếp dữ liệu mà con trỏ void trỏ tới bằng toán tử (*), mà cần biến đổi con trỏ (void*) sang thành kiểu dữ liệu tương ứng.

Ví dụ 1:

#include<stdio.h>
#include<conio.h>
int main()
{
    int a = 10;
    void *p = &a;
    int *ptr = p; // error
    printf("%u\n",*ptr);
    getch();
}

Kết quả:
Trong đoạn code trên khai báo con trỏ p kiểu void trỏ đến địa chỉ biến a (câu lệnh này OK). Câu lệnh tiếp theo, trình biên dịch sẽ không thể biết biến p có kiểu dữ liệu là gì -> Complier Error.

Con trỏ void
Con trỏ void

Ví dụ 2:

#include <stdio.h>
#include <conio.h>
int main()
{
    int a = 10;
    void *p = &a;
    int *ptr = (int*)p; // OK
    printf("%u\n", *ptr); // 10
    getch();
}

Ở ví dụ này, ta đã fix lỗi ở ví dụ 1 bằng cách ép kiểu con trỏ (void*) thành (int*). Lúc này complier sẽ hiểu là con trỏ p trỏ tới kiểu int.

Ví dụ 3: minh họa con trỏ void có thể trỏ tới các kiểu dữ liệu khác như struct, class

#include <conio.h>
#include <stdio.h>

typedef struct  
{
    int date;
    int month;
    int year;
}DATE;

typedef struct  
{
    int hour;
    int minute;
    int second;
}TIME;

void showTime(void *p, char type);

void main()
{
    DATE d = {16, 9, 1989};
    TIME t = {14, 30, 0};
    showTime((void*)&d, 'd');
    showTime((void*)&t, 't');
    getch();
}

void showTime(void *p, char type)
{
    DATE *pDate;
    TIME *pTime;
    switch(type)
    {
    case 'd':
        pDate = (DATE*)p;
        printf("date = %.02d/%.02d/%.04d\n", pDate->date, pDate->month, pDate->year);
        break;
    case 't':
        pTime = (TIME*)p;
        printf("time = %.02d:%.02d:%.02d\n", pTime->hour, pTime->minute, pTime->second);
        break;
    default:
        printf("Default case");
    }
}

Giải thích:
Đoạn code trên hiển thị thông tin của struct DATETIME. Thông thường, chúng ta sẽ phải viết 2 hàm hiển thị cho 2 struct. Tuy nhiên, chúng ta có thể sử dụng tham số kiểu void* để ép kiểu khi truyền đối số là kiểu DATE và TIME.
Khi vào hàm showTime(), dựa vào biến type để ép từ kiểu void* về kiểu dữ liệu tương ứng. Điều này làm giảm thiểu việc viết nhiều function cùng chức năng nhưng khác kiểu dữ liệu đầu vào.

Kết quả:

Kiểu void* trỏ tới struct
Kiểu void* trỏ tới struct

3 Comments on Con trỏ void

  1. Vậy tác dụng của con trỏ void là gì hả a? Khi nó có thể nhận được tất cả các địa chỉ của mọi biến dữ liệu. Nhưng khi sử dụng lại phải ép về kiểu mình cần dùng, vậy tại sao ko dùng luôn con trỏ của kiểu mình cần dùng luôn?

Leave a Reply to TienLuongJS Cancel reply