深入理解指針(1)(C語言版)

文章目錄

    • 前言
    • 一、內存和地址
      • 1.1 內存
      • 1.2 究竟該如何理解編址
    • 二、指針變量和地址
      • 2.1 取地址操作符&
      • 2.2 指針變量和解引用操作符*
        • 2.2.1 指針變量
        • 2.2.2 如何拆解指針類型
        • 2.2.3 解引用操作符
      • 2.3 指針變量的大小
    • 三、指針變量類型的意義
      • 3.1 指針的解引用
      • 3.2 指針+-整數
      • 3.3 void*指針
    • 四、const修飾指針
      • 4.1 const修飾變量
      • 4.2 const修飾指針變量
        • 4.2.1 指針指向的數據是常量
        • 4.2.2 指針本身是常量
    • 五、指針運算
      • 5.1 指針+-整數
      • 5.2 指針-指針
      • 5.3 指針的關系運算
    • 六、野指針
      • 6.1 野指針的成因
      • 6.2 如何規避野指針
        • 6.2.1 指針初始化
        • 6.2.2 小心指針越界
        • 6.2.3 指針變量不再使用時,及時置NULL,指針使用之前檢查有效性
        • 6.2.4 避免返回局部變量的地址
    • 七、assert斷言
    • 八、指針的使用和傳址調用
      • 8.1 `strlen`的模擬實現
      • 8.2 傳址調用和傳值調用
        • 8.2.1 傳值調用
        • 8.2.2 傳址調用
    • 總結

前言

在C語言中,指針是一個非常重要且強大的概念。它允許程序員直接操作內存,從而實現高效的數據處理和靈活的程序控制。然而,指針也是C語言中較為復雜和容易出錯的部分。深入理解指針的原理和用法,對于每一個C語言開發者來說都至關重要。本篇博客將從內存和地址的基本概念入手,逐步深入探討指針變量、指針類型、指針運算、野指針以及指針在函數傳址調用中的應用等內容。
在這里插入圖片描述

一、內存和地址

1.1 內存

計算機的內存就像一個巨大的倉庫,里面有很多很多的小格子,每個小格子都可以用來存放數據。這些小格子的大小和用途各不相同,有的可以存放整數,有的可以存放字符,還有的可以存放浮點數等等。

假設你有一個超市的貨架,貨架上有很多層,每一層都有很多個格子,每個格子都可以用來存放商品。這些格子的大小和用途各不相同,有的可以存放大型商品,如家電;有的可以存放中型商品,如食品;還有的可以存放小型商品,如化妝品。當你需要存放或者取用某樣商品的時候,你只需要知道對應的格子位置,就可以直接找到那個格子。

在計算機中,內存被劃分成一個個小的存儲單元,每個單元都有一個唯一的編號,這個編號就是內存地址。這些存儲單元可以用來存放各種各樣的數據,比如數字、文字、圖片等等。通過內存地址,程序可以訪問和操作特定存儲單元中的數據。

舉個例子,假設我們有一個變量 num,它的值是10。編譯器會為這個變量分配一個內存地址,比如說 0x7ffee5e0。這個內存地址就像是 num 這個變量在內存倉庫里的格子位置。我們可以用這個格子位置來找到這個變量的值,就像用貨架上的格子位置找到對應的商品一樣。

1.2 究竟該如何理解編址

編址就像是給內存倉庫里的每個格子分配一個唯一的門牌號。通過這個門牌號,我們可以準確地找到每個格子的位置,從而進行數據的存取操作。

在現實生活中,我們經常需要通過地址來找到某個地方。比如,你想要去一個朋友的家里,你需要知道他家的詳細地址,包括城市、街道、門牌號等。只有這樣,你才能準確地找到他的家。同樣地,在計算機中,通過內存地址,程序可以準確地找到對應的存儲單元。

內存地址通常以十六進制形式表示,例如 0x7ffee5e0。每個內存地址對應一個存儲單元,存儲單元的大小由數據類型決定。例如,一個 int 類型的變量通常占用4個字節的內存空間,這意味著它需要連續的4個存儲單元。

舉個例子,假設我們有一個數組 arr,它包含5個整數。編譯器會為這個數組分配連續的內存空間,每個整數占用4個字節。數組的首地址是 0x7ffee5e0,那么數組中各個元素的地址如下:

  • arr[0] 的地址是 0x7ffee5e0
  • arr[1] 的地址是 0x7ffee5e4
  • arr[2] 的地址是 0x7ffee5e8
  • arr[3] 的地址是 0x7ffee5ec
  • arr[4] 的地址是 0x7ffee5f0

通過這種方式,程序可以按照一定的規則訪問數組中的每個元素。

在程序中,我們經常需要通過指針來操作內存地址。指針變量存儲的是內存地址,通過指針可以間接訪問該地址中的數據。這就像通過朋友家的門牌號找到他的家,然后進行拜訪一樣。

通過這樣的類比,我們可以更直觀地理解內存和編址的概念。內存就像是一個巨大的倉庫,被劃分成一個個小的存儲單元,每個單元都有一個唯一的地址。編址就是給這些單元分配門牌號,方便程序進行數據的存取操作。這種機制使得程序能夠高效地管理和操作數據,為后續的指針操作奠定了基礎。

二、指針變量和地址

2.1 取地址操作符&

在C語言中,& 符號被稱為取地址操作符。它的作用是獲取一個變量在內存中的地址。這就像我們通過地圖應用獲取某個地點的坐標一樣。

舉個例子,假設我們有一個變量 num,它的值是10。我們可以通過 &num 獲取它的內存地址。

int num = 10;
printf("num的地址是:%p", &num);

在這個例子中,&num 獲取了變量 num 的內存地址,并通過 printf 函數輸出。%p 是用于打印內存地址的格式說明符。

2.2 指針變量和解引用操作符*

2.2.1 指針變量

指針變量是一種特殊的變量,它存儲的是內存地址。我們可以把指針變量想象成一個快遞單號,快遞單號本身并不包含商品,但它能告訴你商品存放在哪個倉庫的哪個位置。

int num = 10;
int *p; // 聲明一個指針變量p,它可以存儲int類型的內存地址
p = # // 將num的地址賦值給指針變量p

在這個例子中,p 是一個指針變量,它保存了變量 num 的內存地址。

2.2.2 如何拆解指針類型

指針變量是有類型的,它決定了指針所指向的數據的類型和大小。指針類型需要與所指向的數據類型匹配,這樣編譯器才能正確地進行內存操作。

一個指針類型的聲明可以拆解為以下幾個部分:

  • 指針所指向的數據類型(如 intfloatchar 等)
  • 指針本身的類型(* 表示這是一個指針)

例如,int *p; 表示 p 是一個指向 int 類型數據的指針。

2.2.3 解引用操作符

* 符號除了用于聲明指針變量外,還用于解引用操作。解引用操作符的作用是獲取指針所指向的內存單元中的值。這就像我們通過快遞單號找到商品所在的倉庫位置,然后取出商品一樣。

printf("%d", *p); // 輸出10,即num的值

在這個例子中,*p 表示獲取指針 p 所指向的內存單元中的值,也就是變量 num 的值。

2.3 指針變量的大小

指針變量的大小取決于計算機系統的架構。在32位系統中,指針變量通常占用4個字節;在64位系統中,指針變量通常占用8個字節。這是因為32位系統使用32位(4字節)的內存地址,而64位系統使用64位(8字節)的內存地址。

printf("指針變量的大小是:%zu字節", sizeof(p));

在這個例子中,sizeof(p) 獲取了指針變量 p 的大小,并通過 printf 函數輸出。%zu 是用于打印大小的格式說明符。

通過這樣的類比和解釋,我們可以更直觀地理解指針變量和地址的概念。指針變量就像是快遞單號,它本身并不包含數據,但它能告訴你數據存放在內存的哪個位置。通過取地址操作符 &,我們可以獲取變量的內存地址;通過解引用操作符 *,我們可以訪問指針所指向的內存單元中的值。這種機制使得程序能夠靈活地操作內存中的數據。

三、指針變量類型的意義

3.1 指針的解引用

指針的解引用操作符 * 用于獲取指針所指向的內存單元中的值。這就像我們通過快遞單號找到商品所在的倉庫位置,然后取出商品一樣。

int num = 10;
int *p = # // p是int類型的指針,指向num的地址
printf("%d", *p); // 輸出10,即num的值

在這個例子中,*p 表示獲取指針 p 所指向的內存單元中的值,也就是變量 num 的值。通過解引用,我們可以訪問和操作指針所指向的數據。

3.2 指針±整數

指針支持與整數進行加法和減法運算。這在遍歷數組或處理連續內存塊時非常有用。指針與整數相加或相減時,會根據指針的類型自動計算偏移量。

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr; // p指向數組的第一個元素for (int i = 0; i < 5; i++) {printf("%d ", *p); // 輸出數組元素的值p++; // 指針自增,指向下一個元素
}

在這個例子中,p 是一個指向 int 類型的指針,初始時指向數組的第一個元素。通過指針自增運算,我們可以遍歷整個數組。每次自增操作都會使指針移動到下一個元素的位置。

3.3 void*指針

void* 是一種通用指針類型,它可以指向任何類型的數據。void* 指針不與任何特定的數據類型關聯,因此在使用時需要進行類型轉換。

int num = 10;
void *p = &num; // p是一個void類型的指針,指向num的地址// 要訪問指針所指向的值,需要進行類型轉換
printf("%d", *(int*)p); // 輸出10,即num的值

在這個例子中,p 是一個 void* 指針,它指向了 num 的地址。由于 void* 指針不與任何特定的數據類型關聯,所以在訪問它所指向的值時,需要將其轉換為具體的指針類型(如 int*),然后進行解引用操作。

通過理解指針變量類型的意義,我們可以更靈活地使用指針進行內存操作。指針的解引用允許我們訪問指針所指向的數據,指針與整數的運算使得遍歷數組等操作更加方便,而 void* 指針則提供了一種通用的指針類型,適用于多種場景。這些特性使得指針在C語言中非常強大和靈活。

四、const修飾指針

4.1 const修飾變量

const 關鍵字用于聲明常量,表示該變量的值在聲明后不能被修改。這就像我們去博物館參觀展品,這些展品是受到保護的,我們只能觀看,不能觸摸或改變它們。

const int num = 10; // 聲明一個常量num,值為10
// num = 20; // 錯誤:不能修改常量的值

在這個例子中,num 被聲明為一個常量,它的值在程序運行過程中不能被修改。

4.2 const修飾指針變量

const 修飾指針變量時,可以有以下兩種情況:

4.2.1 指針指向的數據是常量

const 修飾指針指向的數據,表示不能通過該指針修改所指向的數據。這就像我們拿到了一份只讀的文件,我們可以查看文件內容,但不能修改它。

const int *p; // p是一個指向常量int的指針,不能通過p修改它所指向的int值
int num = 10;
const int *p = &num; // p指向num的地址
// *p = 20; // 錯誤:不能通過const指針修改數據

在這個例子中,p 是一個指向常量 int 的指針,不能通過 p 修改它所指向的 int 值。

4.2.2 指針本身是常量

const 修飾指針本身,表示指針的值(即它所存儲的內存地址)不能被修改。這就像我們拿到了一張電影票,票上的座位號是固定的,我們不能隨意更換座位。

int *const p; // p是一個const指針,即指針本身是常量,不能改變它所指向的地址
int num = 10;
int *const p = &num; // p被初始化為指向num的地址
// p = &another_num; // 錯誤:不能修改const指針的值

在這個例子中,p 是一個 const 指針,一旦被初始化為指向某個地址,就不能再改變它所指向的地址。

通過使用 const 修飾指針,我們可以確保數據的完整性和指針的穩定性,避免不必要的修改和錯誤。這種特性在編寫安全、可靠的代碼時非常有用。

五、指針運算

5.1 指針±整數

指針支持與整數進行加法和減法運算。這就像你在圖書館的書架前,想要找到某本書的位置。假設你站在書架的起點(指針初始位置),然后向前走幾步(加整數)或者向后退幾步(減整數),就能到達目標書籍的位置。

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr; // p指向數組的第一個元素// 指針加法
p = p + 2; // p現在指向數組的第三個元素
printf("%d", *p); // 輸出3// 指針減法
p = p - 1; // p現在指向數組的第二個元素
printf("%d", *p); // 輸出2

在這個例子中,p 是一個指向 int 類型的指針。通過指針與整數的加法和減法運算,我們可以靈活地在數組中移動指針,訪問不同的元素。

5.2 指針-指針

兩個指針相減可以得到它們之間的元素個數。這就像你在一條街道上,想知道兩個房子之間相隔多少戶。通過計算兩個房子的門牌號之差,再除以每戶的平均間距,就能得到它們之間的戶數。

int arr[5] = {1, 2, 3, 4, 5};
int *p1 = arr; // p1指向數組的第一個元素
int *p2 = arr + 4; // p2指向數組的第五個元素int distance = p2 - p1; // 計算兩個指針之間的元素個數
printf("%d", distance); // 輸出4

在這個例子中,p2 - p1 計算了兩個指針之間的元素個數,結果是4,表示從 p1p2 之間有4個元素。

5.3 指針的關系運算

指針支持關系運算,如大于(>)、小于(<)、大于等于(>=)、小于等于(<=)等。這些運算用于比較兩個指針所指向的內存地址的大小。這就像你在比較兩個建筑物的高度,看哪個更高,哪個更矮。

int arr[5] = {1, 2, 3, 4, 5};
int *p1 = arr; // p1指向數組的第一個元素
int *p2 = arr + 2; // p2指向數組的第三個元素if (p2 > p1) {printf("p2指向的地址比p1大");
} else {printf("p1指向的地址比p2大");
}

在這個例子中,p2 > p1 判斷 p2 是否指向的內存地址比 p1 大。由于 p2 指向數組的第三個元素,而 p1 指向第一個元素,所以條件成立,輸出 “p2指向的地址比p1大”。

通過指針運算,我們可以靈活地操作內存中的數據,實現數組遍歷、內存塊操作等功能。指針與整數的運算、指針之間的減法以及指針的關系運算,都是C語言中非常實用的特性,能夠幫助我們編寫高效、靈活的代碼。

六、野指針

6.1 野指針的成因

野指針是指指向不確定內存地址的指針。野指針可能是未初始化的指針,或者是已經釋放了內存但仍然指向該內存地址的指針。這就像你拿到了一張沒有明確地址的快遞單,或者快遞員已經送完快遞但你還在等待。

int *p; // 未初始化的指針,是一個野指針
printf("%d", *p); // 錯誤:訪問野指針可能導致程序崩潰

在這個例子中,p 是一個未初始化的指針,它指向的內存地址是隨機的,訪問這樣的指針可能會導致程序崩潰或出現不可預測的行為。

6.2 如何規避野指針

6.2.1 指針初始化

在聲明指針時,最好對其進行初始化,使其指向一個有效的內存地址或 NULL。這就像在拿到快遞單時,先確認收貨地址是否正確,或者先將快遞單標記為“待發貨”。

int num = 10;
int *p = &num; // 初始化指針,使其指向有效的內存地址

或者

int *p = NULL; // 初始化指針為NULL,表示它目前不指向任何有效的內存地址
6.2.2 小心指針越界

指針越界是指指針超出了其合法的內存范圍。這就像你在圖書館找書時,超出了書架的范圍,可能會撞到墻壁或其他書架。

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr; // p指向數組的第一個元素p = p + 5; // 錯誤:指針越界,數組只有5個元素,索引從0到4
printf("%d", *p); // 錯誤:訪問越界的指針

在這個例子中,p + 5 超出了數組的范圍,訪問這樣的指針是不安全的。

6.2.3 指針變量不再使用時,及時置NULL,指針使用之前檢查有效性

當指針變量不再使用時,將其置為 NULL,以避免懸掛指針(dangling pointer)。在使用指針之前,檢查它是否為 NULL 或指向有效的內存地址。這就像在快遞送達后,將快遞單標記為“已收貨”,避免再次使用無效的快遞單。

int num = 10;
int *p = &num; // p指向num的地址// 在某個操作后,num不再需要被訪問
p = NULL; // 將指針置為NULLif (p != NULL) {printf("%d", *p); // 安全地使用指針
} else {printf("指針無效");
}
6.2.4 避免返回局部變量的地址

函數中的局部變量在函數返回后會被銷毀,因此不要返回局部變量的地址。這就像快遞員送完快遞后離開,但收件人還在等待,導致無法取到快遞。

int* get_pointer() {int num = 10;int *p = &num;return p; // 錯誤:返回局部變量的地址,num的生命周期已經結束
}int main() {int *p = get_pointer();printf("%d", *p); // 錯誤:p是一個野指針,因為num的生命周期已經結束return 0;
}

在這個例子中,get_pointer 函數返回了一個局部變量的地址,當函數返回后,局部變量的生命周期已經結束,p 成為了一個野指針。正確的做法是使用動態分配的內存或靜態變量。

通過以上方法,我們可以有效規避野指針的出現,確保程序的穩定性和安全性。野指針是C語言中常見的錯誤來源,但通過良好的編程習慣和細心的操作,我們可以避免這些問題,編寫出高效、可靠的代碼。

七、assert斷言

assert 是一個宏,用于在調試階段檢查程序的狀態是否符合預期。如果斷言的條件為假,程序將終止并輸出錯誤信息。

#include <assert.h>int *get_pointer() {int num = 10;int *p = &num;return p; // 返回局部變量的地址,返回后num的生命周期已經結束
}int main() {int *p = get_pointer();assert(p != NULL); // 檢查p是否為NULL指針printf("%d", *p); // 錯誤:p是一個野指針,因為num的生命周期已經結束return 0;
}

在這個例子中,get_pointer 函數返回了一個局部變量的地址,當函數返回后,局部變量的生命周期已經結束,p 成為了一個野指針。使用 assert 檢查 p 是否為 NULL 指針,但實際上 p 并不是 NULL,而是指向了一個無效的內存地址,因此程序可能會崩潰。

八、指針的使用和傳址調用

8.1 strlen的模擬實現

strlen 是C標準庫中的一個函數,用于計算字符串的長度。通過指針,我們可以模擬實現 strlen 的功能。這就像你想要知道一本書有多少頁,你需要從第一頁開始,一頁一頁地數,直到看到最后一頁的頁碼。

#include <stdio.h>// 模擬實現strlen函數
int my_strlen(const char *str) {int length = 0;while (*str != '\0') { // 遍歷字符串,直到遇到空字符'\0'length++;str++;}return length;
}int main() {const char *str = "Hello, World!";printf("字符串長度是:%d", my_strlen(str)); // 輸出13return 0;
}

在這個例子中,我們通過指針 str 遍歷字符串,逐個檢查每個字符,直到遇到空字符 \0 為止。每檢查一個字符,長度計數器 length 就增加1。最終返回字符串的長度。

8.2 傳址調用和傳值調用

在函數調用中,C語言支持兩種參數傳遞方式:傳值調用和傳址調用。傳值調用是將實際參數的值傳遞給形式參數,函數內部對形式參數的修改不會影響實際參數。傳址調用是將實際參數的地址傳遞給形式參數,函數內部通過指針可以修改實際參數的值。

8.2.1 傳值調用

傳值調用就像你給朋友寫信,你把信的內容抄寫一份寄給他。他在回信中修改了信的內容,但你的原始信件內容不會改變。

#include <stdio.h>void swap(int a, int b) {int temp = a;a = b;b = temp;
}int main() {int x = 10, y = 20;swap(x, y);printf("x = %d, y = %d", x, y); // 輸出x = 10, y = 20return 0;
}

在這個例子中,swap 函數的參數 ab 是通過傳值調用傳遞的。函數內部對 ab 的修改不會影響主函數中的 xy

8.2.2 傳址調用

傳址調用就像你把一份重要文件的地址告訴給朋友,他可以直接到那個地址去修改文件內容。這樣,文件的原始內容就會被改變。

#include <stdio.h>void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}int main() {int x = 10, y = 20;swap(&x, &y); // 傳址調用printf("x = %d, y = %d", x, y); // 輸出x = 20, y = 10return 0;
}

在這個例子中,swap 函數的參數 ab 是通過傳址調用傳遞的。函數內部通過指針修改了 xy 的值,因此主函數中的 xy 的值發生了變化。

通過指針的使用和傳址調用,我們可以實現函數對變量的直接修改,這在很多場景下非常有用,比如交換變量值、修改結構體內容等。傳址調用提高了函數的靈活性和效率,避免了大量數據拷貝帶來的性能損失。

總結

指針是C語言中一個強大而靈活的概念,它允許程序員直接操作內存,實現高效的數據處理和靈活的程序控制。然而,指針也是C語言中較為復雜和容易出錯的部分。通過深入理解內存和地址、指針變量、指針類型、指針運算、野指針以及指針在函數傳址調用中的應用等內容,我們可以更好地掌握指針的使用方法,避免常見的錯誤和陷阱,編寫出高效、可靠的C語言程序。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/73470.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/73470.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/73470.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【視頻】m3u8相關操作

【視頻】郭老二博文之:圖像視頻匯總 1、視頻文件轉m3u8 1.1 常用命令 1)默認只保留 5 個ts文件 ffmpeg -i input.mp4 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls stream1.m3u82)去掉音頻 -an,保留全部ts文件 ffmpeg -i input.mp4 -vf scale=640:480 -an -…

AWS CloudWatch 實戰:構建智能監控與自動化運維體系

摘要&#xff1a;本文通過實際案例&#xff0c;詳細講解如何利用AWS CloudWatch實現云端資源的實時監控、日志分析與自動化運維&#xff0c;助力企業提升系統穩定性與運維效率 一、場景痛點分析 某電商平臺遷移至AWS后面臨三大挑戰&#xff1a; 故障響應滯后&#xff1a;服務器…

第一天學爬蟲

閱讀提示&#xff1a;我今天才開始嘗試爬蟲&#xff0c;寫的不好請見諒。 一、準備工具 requests庫&#xff1a;發送HTTP請求并獲取網頁內容。BeautifulSoup庫&#xff1a;解析HTML頁面并提取數據。pandas庫&#xff1a;保存抓取到的數據到CSV文件中。 二、爬取步驟 發送請求…

網絡編程和計算機網絡五層模型的關系

計算機網絡的五層模型&#xff08;應用層、傳輸層、網絡層、鏈路層和物理層&#xff09;為網絡編程提供了基礎框架和通信機制。網絡編程就是在這些層次上實現應用程序之間的通信。 計算機網絡五層模型 &#xff08;1&#xff09;應用層&#xff1a; 作用&#xff1a;應用層是…

知識篇 | Oracle的 TEMP表空間管理和優化

Oracle臨時表空間&#xff08;TEMP&#xff09;是數據庫中用于存儲會話級臨時數據的核心組件&#xff0c;主要用于支持需要中間結果集的操作&#xff08;如排序、哈希連接&#xff09;。其數據在事務結束或會話終止后自動釋放&#xff0c;不持久化存儲。 核心特點&#xff1a;…

重學Java基礎篇—線程池參數優化指南

一、核心參數解析 線程池&#xff08;ThreadPoolExecutor&#xff09;的性能取決于以下關鍵參數&#xff1a; 參數說明corePoolSize核心線程數&#xff0c;即使空閑也不會被回收maximumPoolSize最大線程數&#xff0c;當隊列滿且核心線程忙時創建新線程workQueue任務隊列&…

記一次線上環境JAR沖突導致程序報錯org.springframework.web.util.NestedServletException

一、問題描述 有個文件導入功能&#xff0c;用到了Hutool 的加密解密功能&#xff0c;本地運行完全可以&#xff0c;但是線上報錯&#xff1a;“org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFou…

怎么快速部署Sock5代理到ubuntu云服務器

使用 Dante (推薦) 1. 安裝 Dante bash Copy sudo apt update sudo apt install dante-server -y 2. 配置 Dante 編輯配置文件 /etc/danted.conf&#xff1a; bash Copy sudo nano /etc/danted.conf 替換為以下內容&#xff08;按需修改端口和認證&#xff09;&#…

華為OD機試2025A卷 - 游戲分組/王者榮耀(Java Python JS C++ C )

最新華為OD機試 真題目錄:點擊查看目錄 華為OD面試真題精選:點擊立即查看 題目描述 2020年題: 英雄聯盟是一款十分火熱的對戰類游戲。每一場對戰有10位玩家參與,分為兩組,每組5人。每位玩家都有一個戰斗力,代表著這位玩家的厲害程度。為了對戰盡可能精彩,我們需要…

OpenRAND可重復的隨機數生成庫

OpenRAND 是一個 C++ 庫,旨在通過提供強大且可復制的隨機數生成解決方案來促進可重復的科學研究。它是一個簡單的僅頭文件庫,性能可移植,統計穩健,并且易于集成到任何 HPC 計算項目中。 特征 跨平臺支持:OpenRAND 旨在跨各種平臺無縫工作,包括 CPU 和 GPU。其僅標題庫設計…

接口/UI自動化面試題

一、UI自動化 1.1、接口和UI自動化有多少用例&#xff1f; 回答策略&#xff1a;根據接口設定用例&#xff0c;100個接口&#xff0c;自動化case在1500-2000左右。結合自身的項目&#xff0c;回答覆蓋的主功能流程。 示例&#xff1a; 接口自動化的測試case一般需要根據接口數…

使用Docker部署RabbitMQ

第一步&#xff1a;安裝 RabbitMQ # 1. 拉取鏡像 docker pull rabbitmq:3.12.0-management# 2. 啟動容器&#xff08;開放端口 數據持久化&#xff09; docker run -d \--nameshare_rabbitmq \-p 5672:5672 \ # AMQP 協議端口-p 15672:15672 \ # 管理界面端口…

2.基于多線程的TCP服務器實現

目錄 1. 簡單分析之前的代碼 2. 多線程服務器設計 2.1 C11線程的基本使用 2.2 服務器主體邏輯 3. 錯誤處理的封裝 4. 完整的代碼實現 客戶端代碼&#xff08;client.cpp&#xff09; 服務器代碼&#xff08;server.cpp&#xff09; 5. 運行方式 在我們預想中&#xff…

Python Web 框架 Django、Flask 和 FastAPI 對比

在探索 Python Web 框架時&#xff0c;Django、Flask 和 FastAPI 無疑是最常被提及的名字。根據我們最新的 Python 開發者調查&#xff0c;這三大框架繼續穩坐后端 Web 開發的熱門寶座。它們均為開源項目&#xff0c;并且與 Python 的最新版本無縫兼容。然而&#xff0c;面對不…

SQL Server數據庫表刪除分區

在 SQL Server 中刪除分區并將表恢復到非分區狀態&#xff0c;需按以下步驟操作&#xff1a; 一、合并所有分區 1. 檢查現有分區結構 首先確認表的分區方案和分區函數&#xff1a; -- 查看分區方案 SELECT * FROM sys.partition_schemes;-- 查看分區函數 SELECT * FROM sys…

信息安全和病毒防護——安全協議關于SSL和TLS協議的補充說明

文章目錄 SSL與TLS的關系SSL與TLS的核心區別SSL/TLS的典型應用安全建議總結SSL與TLS的關系 SSL(Secure Sockets Layer,安全套接層)和TLS(Transport Layer Security,傳輸層安全)是同一技術體系的演進版本,而非完全獨立的協議。其發展歷程如下: SSL 1.0(1994):未公開…

[原創](Modern C++)現代C++的關鍵性概念: 多維數組的下標引用.

[作者] 常用網名: 豬頭三 出生日期: 1981.XX.XX 企鵝交流: 643439947 個人網站: 80x86匯編小站 編程生涯: 2001年~至今[共24年] 職業生涯: 22年 開發語言: C/C、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 開發工具: Visual Studio、Delphi、XCode、C …

從零構建大語言模型全棧開發指南:第二部分:模型架構設計與實現-2.2.3實戰案例:在筆記本電腦上運行輕量級LLM

?? 點擊關注不迷路 ?? 點擊關注不迷路 ?? 點擊關注不迷路 文章大綱 實戰案例:在筆記本電腦上運行輕量級LLM2.2.3 模型架構設計與實現1. 環境與工具準備1.1 硬件要求1.2 軟件棧選擇2. 輕量級模型架構設計2.1 模型參數配置2.2 關鍵技術優化3. 實戰流程3.1 數據準備流程3.2…

工業軟件的破局與重構:從技術依賴到自主創新的未來路徑

工業軟件作為現代工業的“神經與大腦”&#xff0c;不僅是制造業數字化轉型的核心工具&#xff0c;更是國家工業競爭力的戰略制高點。近年來&#xff0c;中國工業軟件市場在政策驅動與技術迭代中迅猛發展&#xff0c;但核心技術受制于人的困境仍待突破。如何實現從“跟跑”到“…

歌曲緩存相關功能

1. 核心組件 MusicCacheManager (音樂緩存管理器) 單例模式&#xff1a;確保全局只有一個實例&#xff0c;方便管理。 private static var instance: MusicCacheManager?static func shared() -> MusicCacheManager {if instance nil {instance MusicCacheManager()}ret…