成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C/C++面試題:void*通常怎么使用?——快手一面

開發(fā)
void* 是一種特殊的指針類型,可以指向任何數據類型的對象(或函數)的地址,但它本身不包含任何關于它所指向對象類型的信息。

void* 在 C 和 C++ 中被稱為“無類型指針”或“通用指針”(generic pointer)。它是一種特殊的指針類型,可以指向任何數據類型的對象(或函數)的地址,但它本身不包含任何關于它所指向對象類型的信息。

void* 的主要用途和使用方式包括:

1. 通用函數接口(如內存操作函數):

標準庫函數如 malloc, calloc, realloc 返回 void*,因為它們分配的是原始內存塊,并不知道你打算在這塊內存中存儲什么類型的數據。你需要將返回的 void* 顯式轉換(cast)為你需要的具體指針類型才能使用。

memcpy, memmove, memset 等函數接受 void* 參數,因為它們按字節(jié)操作內存,不關心實際的數據類型,只需要知道內存地址和大小。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
    // 1. malloc example
    int *p_int = (int*)malloc(sizeof(int)); 
    if (p_int == NULL) {
        perror("Failed to allocate memory");
        return 1;
    }
    *p_int = 100;
    printf("Value via p_int: %d\n", *p_int);
    free(p_int); 
    // 2. memcpy example
    char src[] = "Hello";
    char dest[10];
    memcpy(dest, src, strlen(src) + 1);                                         
    printf("Copied string: %s\n", dest);
    return 0;
}

2.實現泛型數據結構和算法 (主要在 C 語言中):

在 C 語言中,沒有模板(templates)這樣的泛型編程機制。如果想創(chuàng)建可以存儲任何類型數據的列表、樹、哈希表等,或者編寫可以處理任何類型數組的排序、搜索算法(如標準庫的 qsort),void* 是常用的方法。

數據結構通常會存儲 void* 指向實際數據。

像 qsort 這樣的函數接受一個 void* 指向數組基地址,并需要一個比較函數,該比較函數也接受兩個 const void* 參數,你需要在比較函數內部將 void* 轉換回實際的數據類型指針進行比較。

#include <stdio.h>
#include <stdlib.h>
// Comparison function for qsort (sorting integers)
int compare_ints(const void *a, const void *b) {
    int int_a = *((const int*)a); // Cast void* to const int* and dereference
    int int_b = *((const int*)b); // Cast void* to const int* and dereference
    if (int_a < int_b) return -1;
    if (int_a > int_b) return 1;
    return 0;
}
int main() {
    int numbers[] = {5, 2, 8, 1, 9, 4};
    size_t num_count = sizeof(numbers) / sizeof(numbers[0]);
    printf("Before sorting: ");
    for (size_t i = 0; i < num_count; ++i) printf("%d ", numbers[i]);
    printf("\n");
    // Use qsort with void* base address and comparison function
    qsort(numbers, num_count, sizeof(int), compare_ints);
    printf("After sorting: ");
    for (size_t i = 0; i < num_count; ++i) printf("%d ", numbers[i]);
    printf("\n");
    return 0;
}

3.傳遞不透明數據指針

在庫或 API 設計中,有時會將內部結構的指針作為 void* 返回給用戶,用戶不能(也不應該)直接操作它,只能將其傳遞回庫的其他函數。這隱藏了實現細節(jié)。

4.回調函數的用戶數據(User Data / Context)

許多 API(如圖形庫、線程庫、事件處理系統(tǒng))允許你注冊一個回調函數,并在注冊時提供一個 void* 參數(通常稱為 userData、context 或類似名稱)。當 API 調用你的回調函數時,它會把你當初提供的 void* 再傳回給你的回調函數。這允許你的回調函數訪問特定的上下文信息,而 API 本身無需知道這些信息的具體類型。

假設有一個庫函數 setTimer,它會在指定的毫秒數后調用你提供的回調函數。為了讓你的回調函數知道是哪個計時器觸發(fā)了(或者攜帶任何你想傳遞的信息),setTimer 允許你傳遞一個 void* 用戶數據。

#include <stdio.h>  // 包含標準輸入輸出頭文件
#include <stdlib.h> // 包含標準庫頭文件 (用于 NULL)
// --- 假設這是外部庫的一部分 ---
typedef void (*TimerCallback)(int timerId, void* userData);
// 模擬設置一個定時器。
void setTimer(int milliseconds, TimerCallback callback, void* userData) {
    printf("定時器庫:正在設置 %d 毫秒的定時器。\n", milliseconds);
    // --- 想象等待 'milliseconds' 毫秒 ---
    printf("定時器庫:定時器到期!調用回調函數。\n");
    // 庫函數不知道也不關心 userData 指向什么,
    // 它只是將其原樣傳遞回給回調函數。
    int assignedTimerId = 1;
    callback(assignedTimerId, userData); // 調用回調,傳入ID和用戶數據
    printf("定時器庫:回調完成。\n");
}
// --- 應用程序代碼 ---
// 1. 定義傳遞給回調函數的數據結構
typedef struct {
    const char* message; // 消息字符串
    int retryCount;      // 重試次數計數器
} MyTimerInfo;
// 2. 實現匹配 TimerCallback 簽名的回調函數
void handleTimerExpiration(int timerId, void* userData) {
    printf("我的應用程序:收到定時器 ID %d 的回調。\n", timerId);
    // 重要:將 void* 指針強制轉換回正確的指針類型 (MyTimerInfo*)
    MyTimerInfo* info = (MyTimerInfo*)userData;
    printf("消息: %s, 重試次數: %d\n", info->message, info->retryCount);
    info->retryCount++; // 修改數據
}
// 3. 主邏輯中,創(chuàng)建數據并注冊定時器
int main() {
    MyTimerInfo myInfo;
    myInfo.message = "任務 A 需要處理";
    myInfo.retryCount = 0;
    printf("我的應用程序:正在注冊定時器...\n");
    setTimer(1000, handleTimerExpiration, &myInfo); // 傳遞 myInfo 的地址
    printf("我的應用程序:定時器注冊調用完成。\n");
    // 打印修改后的重試次數,驗證回調函數確實修改了它
    printf("我的應用程序:當前重試次數 (回調之后): %d\n", myInfo.retryCount);
    return 0; // 程序正常退出
}

5.重要注意事項

  • 不能直接解引用 : 你不能直接對 void* 使用 * 運算符,因為編譯器不知道它指向的數據類型有多大,以及如何解釋這些字節(jié)。
  • 必須顯式轉換: 在使用 void* 指向的數據之前,必須將其顯式轉換(cast)為正確的具體數據類型指針。
  • 類型安全: void* 的使用會繞過編譯器的類型檢查。如果你將 void* 轉換回了錯誤的類型,會導致未定義行為(Undefined Behavior),通常是程序崩潰或數據損壞。這是 void* 的主要缺點。
  • 指針運算: 不能對 void* 進行指針算術運算(如 ptr++ 或 ptr + 1),因為編譯器不知道每個元素的大小。 (GCC 等編譯器可能有擴展允許,但不標準且危險)。
  • C++ 中的替代方案: 在 C++ 中,雖然 void* 仍然可用且在與 C 庫交互時必不可少,但對于泛型編程,通常推薦使用模板(templates),它們提供了類型安全。對于類型轉換,C++ 提供了更安全的轉換運算符,如 static_cast, dynamic_cast, 和 reinterpret_cast。reinterpret_cast<T*>(void_ptr) 常用于 void* 和其他指針類型之間的轉換,但同樣需要開發(fā)者保證類型轉換的正確性。

void* 是一個強大的工具,用于實現通用性,但犧牲了類型安全。使用它時,必須非常小心,確保在解引用或操作指針之前,總是將其轉換回正確的原始類型。

責任編輯:趙寧寧 來源: CppPlayer
相關推薦

2025-05-20 10:00:00

C++命名空間別名代碼

2021-10-27 11:00:30

C++語言面試

2025-05-23 08:15:00

C++constexpr字面類型

2010-02-06 09:59:54

C++ void使用規(guī)

2025-03-24 07:35:00

開發(fā)注解Spring

2025-05-26 03:20:00

2011-03-29 14:31:41

CC++

2025-04-30 10:10:00

在 C++C++11Lambda

2025-05-06 08:20:00

互斥鎖C++編程

2010-02-06 09:53:26

C++ void

2009-08-11 14:59:57

一道面試題C#算法

2025-05-20 08:10:00

函數函數類型函數指針類型

2025-03-13 10:01:47

2009-08-11 10:12:07

C#算法

2025-06-05 08:05:00

vectorC++對象存儲

2022-04-12 11:38:06

C語言全局變量

2009-08-28 09:29:02

2025-06-09 07:55:00

C++引用語言

2011-05-18 17:56:38

C#C++

2025-05-29 10:30:00

C++編程recv
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品日韩欧美一区二区三区 | 一区二区三区视频 | 久久精品在线 | 亚洲国产视频一区二区 | www.五月天婷婷 | av国产精品 | 久久性 | 国产不卡一区 | 羞羞的视频免费观看 | 久久99精品久久 | 日韩精品一区二区三区中文在线 | 日韩国产中文字幕 | 国产视频久 | 久草视频在线播放 | 精品国产青草久久久久福利 | 免费在线观看一区二区 | 亚洲成人国产综合 | 亚洲一区二区三区免费在线 | 成人网视频 | 欧美日韩亚洲国产 | a国产一区二区免费入口 | 中文字幕av一区二区三区 | 日韩在线国产 | 天堂av资源 | 日韩超碰| 九九热这里| 日本 欧美 国产 | 成人在线免费视频 | 一区二区三区视频在线 | 国产精品亚洲精品 | 欧美一卡二卡在线观看 | 亚洲一区二区视频在线播放 | 麻豆精品久久久 | 成人欧美一区二区三区黑人孕妇 | 亚洲 欧美 日韩 精品 | www日日日| 精品免费国产一区二区三区四区 | 中文在线一区二区 | 爱爱无遮挡 | 日本久草 | 在线一区视频 |