高效利用內存資源之動態內存管理詳解

目錄

一、為什么存在動態內存分配

二、動態內存函數的介紹

2.1malloc

2.2free

2.3calloc

2.4realloc

三、常見的動態內存錯誤

3.1對NULL指針的解引用操作

3.2對動態開辟空間的越界訪問

3.3對非動態開辟內存使用free釋放

3.4使用free釋放一塊動態開辟內存的一部分

3.5對同一塊動態內存多次釋放

3.6動態開辟內存忘記釋放(內存泄漏)

四、經典筆試題

🌴題目一:?

?🌴題目二:?

?🌴題目三:?

??🌴題目四:?

五、C/C++程序的內存開辟

六、柔性數組

6.1柔性數組的特點

?6.2柔性數組的使用

6.3柔性數組的優勢

結語:


一、為什么存在動態內存分配

截止目前我們已經掌握的開辟空間的方式有以下兩種:

int main()
{//在棧空間上開辟四個字節,存放一個值int a = 10;//在棧空間上開辟10個字節的連續空間,存放一組數int arr[] = { 1,2,3,4,5,6,7,8,9,10 };return 0;
}

但是上述開辟空間的方式有兩個特點:

  1. 空間開辟的大小是固定的。
  2. 數組在聲明的時候,必須指定數組的長度,它所需要的內存在編譯時分配。

但是對于空間的需求,不僅僅是上述的情況。有時候我們需要的空間大小在程序運行的時候才能知道,那數組在編譯時開辟空間的方式就不能滿足了。這個時候C語言給了我們程序員一種權利:能夠動態申請和管理內存空間,即動態內存的開辟。有了這種權力,我們就能很好的解決上述所面臨的問題了。

二、動態內存函數的介紹

?🌴函數頭文件都是:

#include <stdlib.h>

2.1malloc

"malloc"函數用于動態分配指定大小的內存空間,并返回一個指向該內存空間的指針。

🌴函數原型:?

void* malloc (size_t size);
  • 其中,size參數表示需要分配的內存空間的大小,單位為字節。
  • 函數返回一個指向分配的內存空間的指針,如果分配失敗則返回 NULL。

?🌴函數用法示例:

#include <stdlib.h>
#include <stdio.h>int main()
{//申請一塊空間,用來存放10個整型int* ptr = (int*)malloc(10 * sizeof(int));//如果返回NULL,則代表空間申請失敗,并打印失敗原因if (ptr == NULL){perror("malloc");return 1;}int i = 0;//因為這個函數返回一個指向分配好的內存塊開頭的指針,//所以ptr這個指針變量相當于這塊內存空間的首地址for (i = 0; i < 10; i++){*(ptr + i) = i;}for (i = 0; i < 10; i++){printf("%d ", ptr[i]);}return 0;
}

🌴打印結果:

?🌴注意事項:?

  1. 如果開辟成功,則返回一個指向開辟好空間的指針。
  2. 如果開辟失敗,則返回一個NULL指針,因此malloc的返回值一定要做檢查。
  3. 返回值的類型是 void*?,所以malloc函數并不知道開辟空間的類型,具體在使用的時候由使用者自己來決定。
  4. 如果參數 size 為0,malloc的行為是標準是未定義的,取決于編譯器。

malloc函數申請的空間有兩種釋放方式:

  1. free釋放 ---?主動回收。
  2. 程序退出后,malloc申請的空間會被操作系統回收 --- 被動回收。

注:正常情況下,誰申請的空間,誰去釋放,萬一自己不釋放,也要交代給別人記得釋放。

2.2free

動態分配內存允許程序在運行時分配和釋放內存,這對于處理大量數據或者需要靈活管理內存的程序非常重要。但是,如果不及時釋放已經分配的內存,就會導致內存泄漏,最終可能導致程序崩潰。在C語言中,我們可以使用free()函數釋放已經分配的內存。

?🌴函數原型:?

void free (void* ptr);

?free函數非常簡單,它只需要傳入一個指向已經分配的內存塊的指針,就可以將該內存塊釋放回操作系統。

??🌴函數用法示例:

#include <stdlib.h>
#include <stdio.h>int main()
{//申請一塊空間,用來存放10個整型int* ptr = (int*)malloc(10 * sizeof(int));//如果返回NULL,則代表空間申請失敗,并打印失敗原因if (ptr == NULL){perror("malloc");return 1;}*ptr = 10;printf("ptr指向的值為:%d\n", *ptr);free(ptr);ptr = NULL;return 0;
}

🍄解析:

  • ?在上述代碼中,首先使用malloc函數分配一個整型變量的內存空間,并將其賦值給指針變量ptr。然后,將整型變量的值設置為10,并輸出該值。最后,使用free函數釋放了該內存空間。
  • 需要我們清楚的一點是,malloc的作用是申請一塊空間供當前程序使用,而free函數的作用是把申請的這塊空間還給操作系統。然而,free雖然將空間還給了操作系統,但指針變量ptr卻還記得申請的這塊空間的地址,這時候它就變成了一個野指針,這是非常危險的,所以我們要在free釋放完空間后將ptr置為空指針NULL。

🌴注意事項:?

  1. 如果參數 ptr 指向的空間不是動態開辟的,那free函數的行為是未定義的。
  2. 如果參數 ptr 是NULL指針,則函數什么事都不做。

2.3calloc

"calloc"函數和"malloc"函數相似,都是用來分配內存的。不同之處在于"calloc"函數在分配內存時會將內存中的每個字節初始化為0。

?🌴函數原型:

void* calloc (size_t num, size_t size);
  • "calloc"函數接收兩個參數,分別是要分配的元素個數和每個元素的大小。
  • 它會分配總共 num*size 個字節的內存,并將這些內存空間初始化為0。?

???🌴函數用法示例:

#include <stdio.h>
#include <stdlib.h>int main()
{int* ptr = (int*)calloc(10, sizeof(int));if (ptr == NULL){perror("calloc");return 1;}//打印int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(ptr + i));}//釋放free(ptr);ptr = NULL;return 0;
}

🍄解析:

?

在上述代碼中,首先使用calloc函數分配了10個整型變量的內存空間 ,并將其賦值給指針變量ptr。由于calloc函數會將分配的內存空間初始化為0,因此在使用循環輸出ptr指向的內存空間時,會發現所有的值都是0。最后,使用free函數釋放了該內存空間。所以如果我們對申請的內存空間的內容要求初始化,那么可以很方便的使用calloc函數來完成任務。

2.4realloc

有時會我們發現過去申請的空間太小了,有時候我們又會覺得申請的空間過大了,那為了合理的使用內存,我們一定會對內存的大小做靈活的調整,那 realloc 函數就可以做到對動態開辟內存大小的調整,即realloc函數用于重新分配之前通過malloc、calloc或realloc函數分配的內存塊的大小。

??🌴函數原型:

void* realloc (void* ptr, size_t size);
  • ptr:之前分配的內存塊的指針。
  • size:新的內存塊的大小。
  • 返回值為調整之后的內存起始位置。
  • realloc函數會嘗試將之前分配的內存塊的大小改變為size字節,并返回指向新內存塊的指針。如果無法滿足新的大小要求,realloc函數可能會在不同的位置重新分配內存塊,并將原內存塊的內容復制到新的內存塊中。

????🌴函數用法示例:

#include <stdio.h>
#include <stdlib.h>int main()
{//分配10個整型的內存塊int* ptr = (int*)calloc(10, sizeof(int));if (ptr == NULL){perror("calloc");return 1;}//初始化內存塊int i = 0;for (i = 0; i < 10; i++){ptr[i] = i;}//打印for (i = 0; i < 10; i++){printf("%d ", ptr[i]);}//空間不夠,希望調整空間為20個整型的空間int* p = (int*)realloc(ptr, 20 * sizeof(int));if (p != NULL){ptr = p;}//釋放free(ptr);ptr = NULL;return 0;
}

?🌴注意事項:??

1.realloc函數在調整內存空間時存在兩種情況:

🍄情況1:原有空間之后有足夠大的空間:


?

?🍄情況2:原有空間之后沒有足夠大的空間:

2.如果ptr為NULL,則realloc的行為類似于free,即它將分配一個新的內存塊。?

int main()
{int* p = (int*)realloc(NULL, 10 * sizeof(int));if (p == NULL){perror("realloc");return 1;}free(p);p = NULL;return 0;
}

三、常見的動態內存錯誤

3.1對NULL指針的解引用操作

int main()
{int* p = (int*)malloc(40);//不做返回值判斷,就可能使用NULL指針解引用,就會報錯*p = 20;return 0;
}

🍂這時候鼠標點上去編譯器就會提示你有錯誤:?

🌴正確寫法:

int main()
{int* p = (int*)malloc(40);if (p == NULL){perror("malloc");}//不做返回值判斷,就可能使用NULL指針解引用,就會報錯*p = 20;free(p);p = NULL;return 0;
}

3.2對動態開辟空間的越界訪問

int main()
{int* ptr = (int*)calloc(10, sizeof(int));if (ptr == NULL){perror("calloc");return 1;}//初始化內存塊int i = 0;for (i = 0; i <= 10; i++){ptr[i] = i;//當i是10的時候越界訪問}for (i = 0; i <= 10; i++){printf("%d ", ptr[i]);//當i是10的時候越界訪問}free(ptr);ptr = NULL;return 0;
}

3.3對非動態開辟內存使用free釋放

int main()
{int a = 10;int* p = &a;free(p);p = NULL;return 0;
}

上述代碼中的變量a是我們在棧上面開辟的空間,而free只能釋放malloc、calloc、realloc開辟的空間,它們都是在堆區上面開辟空間。

3.4使用free釋放一塊動態開辟內存的一部分

int main()
{int* ptr = (int*)calloc(10, sizeof(int));if (ptr == NULL){perror("calloc");return 1;}//初始化內存塊int i = 0;for (i = 0; i < 5; i++){*ptr = i;ptr++;}// 0 1 2 3 4 0 0 0 0 0free(ptr);ptr = NULL;return 0;
}

在上述代碼中,我們初始化內存塊的時候,剛開始*ptr指向所開辟的這塊空間的第一個元素,將它初始化為0,然后ptr++,指向第二個元素,初始化為1,直到循環結束,所開辟的這塊空間前5個元素就會被初始化為0 1 2 3 4,而因為它是calloc開辟的空間,所以剩下的5個元素就會被初始化為0 0 0 0 0。而現在當這個循環結束的時候ptr++,它會指向第6個元素,緊接著直接釋放內存,這個時候程序就會出現問題。所以我們要釋放也是全部釋放。
?

3.5對同一塊動態內存多次釋放

int main()
{int* p = (int*)malloc(40);if (p == NULL){//...return 1;}free(p);//...free(p);return 0;
}

解決辦法是第一次釋放完空間后將p置為NULL指針,因為當free函數的參數為NULL指針是它什么事也不做。

3.6動態開辟內存忘記釋放(內存泄漏)

void test()
{int* p = (int*)malloc(100);if (NULL != p){*p = 20;}
}
int main()
{test();while (1);
}

忘記釋放不在使用的動態開辟的空間會造成內存泄漏,切記:動態開辟的空間一定要釋放,并且正確釋放。

四、經典筆試題

🌴題目一:?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>void GetMemory(char* p)
{p = (char*)malloc(100);
}
void Test(void)
{char* str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}//請問運行Test 函數會有什么樣的結果?
int main()
{Test();return 0;
}

🍂解析:

上述這段代碼運行起來后最終會崩潰。首先程序運行起來后先進入main函數,然后調用Test函數,進入Test函數后,創建指針變量str并將它置為NULL指針。緊接著再調用GetMemory函數,將實參str傳給形參p,并將str的值也一并傳給了形參,然后malloc開辟100個字節的空間并將它的起始地址返回給p,即p指向此時開辟的這100個字節的空間。當它返回被調用的GetMemory函數時,因為它是形參,一旦函數執行完畢,形參的值和狀態將不再保留,所以p所占用的內存空間將會被釋放,但malloc開辟的這塊空間還存在,此時因為p不見了,所以沒人能找到這塊空間。函數繼續往下執行,要將"hello world"拷貝到str指向的空間,但因為str是空指針,這兒必然會對空指針進行解引用操作,所以會出現程序崩潰的情況。而且程序運行結束時,malloc開辟的空間也沒有釋放,所以還會發生內存泄漏的情況。

🌻改正后的代碼:?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>void GetMemory(char** p)
{*p = (char*)malloc(100);
}
void Test(void)
{char* str = NULL;GetMemory(&str);strcpy(str, "hello world");printf(str);free(str);str = NULL;
}int main()
{Test();return 0;
}

因為形參是實參的一份臨時拷貝,所以改變形參并不會影響到實參。在上面改進后的代碼中,我們將str的地址傳給形參,并用二級指針變量來接收,然后解引用p,找到str讓他指向malloc函數開辟的空間,就可以將"hello world"拷貝過去了。

?🌴題目二:?

char* GetMemory(void)
{char p[] = "hello world";return p;
}void Test(void)
{char* str = NULL;str = GetMemory();printf(str);
}
//請問運行Test 函數會有什么樣的結果?
int main()
{Test();return 0;
}

🍂解析:

在上述代碼中,我們還是先進入主函數,然后調用Test函數,進入Test函數內部首先創建str指針變量并將它置為NULL指針,然后調用GetMemory函數并將它的返回值賦給str,進入GetMemory函數內部,創建一個數組,里邊存放的是"hello world",這兒我們應該清楚這個p數組它是在棧上邊創建的,進入這個函數創建,出這個函數銷毀。然后返回p(此時p是數組名,代表的是數組首元素的地址),str接收返回的p,此時,str里邊存放的就是p的地址值,但是,雖然將地址值帶回來了,創建的那塊空間卻不屬于我了(因為出了函數后,創建的空間就會還給操作系統,它的使用權限就不屬于我了)。所以,當我們再去使用str指針的時候,它就會變成野指針,這種問題屬于返回棧空間地址的問題。??

要想解決這個問題也很簡單,第一種方法可以在局部變量char p[ ]前面加關鍵字static修飾,這樣它就變成了靜態局部變量,它會一直存在于內存中,直到程序結束。第二種方法是用malloc函數來開辟空間,只要程序不退出或主動回收,這塊空間就一直存在。

?🌴題目三:?

void GetMemory(char** p, int num)
{*p = (char*)malloc(num);
}void Test(void)
{char* str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);
}
//請問運行Test 函數會有什么樣的結果?
int main()
{Test();return 0;
}

?🍂解析:

上面這段代碼雖然能打印出結果來,但它在使用完malloc開辟的空間后沒有將它釋放,所以說存在內存泄漏的問題。

??🌴題目四:?

void Test(void)
{char* str = (char*)malloc(100);strcpy(str, "hello");free(str);if (str != NULL){strcpy(str, "world");printf(str);}
}//請問運行Test 函數會有什么樣的結果?
int main()
{Test();return 0;
}

?🍂解析:

上面這段程序將"hello"拷貝到malloc函數開辟的空間后,直接將這塊空間釋放掉了,但str還是存著這塊空間的地址,所以在if語句中判斷時,它依然為真,那就進入函數內部,將"world"拷貝到str指向的這塊空間的地址,此時的str已經變成了野指針,對野指針進行操作,就是非法訪問內存。

其實這段代碼考察的點在free釋放完空間后有沒有將str置為NULL指針。

五、C/C++程序的內存開辟


?

🌴C/C++程序內存分配的幾個區域:

  1. ?棧區(stack):在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置于處理器的指令集中,效率很高,但是分配的內存容量有限。 棧區主要存放運行函數而分配的局部變量、函數參數、返回數據、返回地址等。
  2. 堆區(heap):一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 ,分配方式類似于鏈表。
  3. 數據段(靜態區):(static)存放全局變量、靜態數據。程序結束后由系統釋放。
  4. 代碼段:存放函數體(類成員函數和全局函數)的二進制代碼。

有了這幅圖,我們就可以更好的理解static關鍵字修飾局部變量的例子了。實際上普通的局部變量是在棧區分配空間的,棧區的特點是在上面創建的變量出了作用域就銷毀。但是被static修飾的變量存放在數據段(靜態區),數據段的特點是在上面創建的變量,直到程序結束才銷毀所以生命周期變長。

六、柔性數組

C99 中,結構中的最后一個元素允許是未知大小的數組,這就叫做『柔性數組』成員。

🎈例如:?

struct s
{char c;int i;int arr[0];//未知大小的數組--柔性數組成員
};

有些編譯器會報錯無法編譯可以改成:?

struct s
{char c;int i;int arr[];//未知大小的數組--柔性數組成員
};

6.1柔性數組的特點

1、結構中的柔性數組成員前面必須至少一個其他成員。

2、sizeof 返回的這種結構大小不包括柔性數組的內存。

struct s
{char c;//1int i;//4int arr[0];//未知大小的數組--柔性數組成員
};int main()
{printf("%d\n", sizeof(struct s));return 0;
}

?

3、包含柔性數組成員的結構用malloc ()函數進行內存的動態分配,并且分配的內存應該大于結構的大小,以適應柔性數組的預期大小。

struct s
{char c;int i;int arr[0];//未知大小的數組--柔性數組成員
};int main()
{struct s* pc = (struct s*)malloc(sizeof(struct s) + 20);if (pc == NULL){perror("malloc");return 1;}//釋放free(pc);pc = NULL;return 0;
}

?6.2柔性數組的使用

//代碼1
struct s
{char c;int i;int arr[];
};int main()
{struct s* pc = (struct s*)malloc(sizeof(struct s) + 20);if (pc == NULL){peror("malloc");return 1;}pc->c = 'w';pc->i = 100;for (int i = 0; i < 5; i++){pc->arr[i] = i;}for (int i = 0; i < 5; i++){printf("%d ", pc->arr[i]);}//空間不夠了,增容struct s* ptr = (struct s*)realloc(pc, sizeof(struct s) + 40);if (ptr != NULL){pc = ptr;}else{perror("realloc");return 1;}//增容成功后,繼續使用// ......//釋放free(pc);pc = NULL;return 0;
}

6.3柔性數組的優勢

🌵上述的代碼也可寫成下面這樣:?

//代碼2
struct s
{char c;int i;int* data;
};int main()
{struct s* pc = (struct s*)malloc(sizeof(struct s) + 20);if (pc == NULL){peror("malloc1");return 1;}pc->c = 'w';pc->i = 100;pc->data = (int*)malloc(20);if (pc->data == NULL){perror("malloc2");return 1;}for (int i = 0; i < 5; i++){pc->data[i] = i;}for (int i = 0; i < 5; i++){printf("%d ", pc->data[i]);}//空間不夠了,增容int* ptr = (int*)realloc(pc->data, 40);if (ptr != NULL){pc->data = ptr;return 1;}//釋放free(pc->data);pc->data = NULL;free(pc);pc = NULL;return 0;
}
上述代碼1 和 代碼2 可以完成同樣的功能,但是 方法1 的實現有兩個好處:

🍂第一個好處是:方便內存釋放

如果我們的代碼是在一個給別人用的函數中,你在里面做了二次內存分配,并把整個結構體返回給用戶。用戶調用free可以釋放結構體,但是用戶并不知道這個結構體內的成員也需要free,所以你不能指望用戶來發現這個事。所以,如果我們把結構體的內存以及其成員要的內存一次性分配好了,并返回給用戶一個結構體指針,用戶做一次free就可以把所有的內存也給釋放掉。

🍂第二個好處是:有利于訪問速度

連續的內存有益于提高訪問速度,也有益于減少內存碎片。

結語:

動態內存分配是一項強大而靈活的功能,它允許程序再運行時動態的分配和釋放內存。然而,與之相伴而來的是一些潛在的問題和風險。在使用動態內存時,我們需要特別注意內存泄漏、野指針、內存碎片等問題,以及合理的管理內存的生命周期。?

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

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

相關文章

Spring Boot 3 集成 Druid 連接池詳解

在現代的Java應用中&#xff0c;使用一個高效可靠的數據源是至關重要的。Druid連接池作為一款強大的數據庫連接池&#xff0c;提供了豐富的監控和管理功能&#xff0c;成為很多Java項目的首選。本文將詳細介紹如何在Spring Boot 3項目中配置數據源&#xff0c;集成Druid連接池&…

【ACM獨立出版、確定的ISBN號】第三屆密碼學、網絡安全和通信技術國際會議(CNSCT 2024)

第三屆密碼學、網絡安全和通信技術國際會議&#xff08;CNSCT 2024&#xff09; 2024 3rd International Conference on Cryptography, Network Security and Communication Technology 隨著互聯網和網絡應用的不斷發展&#xff0c;網絡安全在計算機科學中的地位越來越重要&…

Android Kotlin 泛型:強大的類型抽象和重用利器

一、什么是泛型&#xff1f; 泛型是一種參數化類型的機制&#xff0c;它允許我們在定義類、接口和方法時使用類型參數&#xff0c;從而實現代碼的重用和類型安全。通過使用泛型&#xff0c;我們可以將類型作為參數傳遞給類或方法&#xff0c;在不同的場景中實現靈活的類型適配…

精選:免費且高效的郵件營銷軟件推薦

好用的郵件營銷軟件可以幫助企業獲取客戶、維系客戶關系。對于有想做郵件營銷想法&#xff0c;但是想先試試的企業來講&#xff0c;免費版郵件營銷軟件就是個不錯的選擇。當然&#xff0c;免費的郵件郵件營銷軟件雖然在價格上有極大的優勢&#xff0c;但是功能上會有各種限制。…

Java生態系統最受歡迎的工具類使用指南 ?

???? 博主貓頭虎(????)帶您 Go to New World??? ?? 博客首頁——????貓頭虎的博客?? ?? 《面試題大全專欄》 ?? 文章圖文并茂??生動形象??簡單易學!歡迎大家來踩踩~?? ?? 《IDEA開發秘籍專欄》 ?? 學會IDEA常用操作,工作效率翻倍~?? ?…

【小白專用】MySQL查詢數據庫所有表名及表結構其注釋

一、先了解下INFORMATION_SCHEMA 1、在MySQL中&#xff0c;把INFORMATION_SCHEMA看作是一個數據庫&#xff0c;確切說是信息數據庫。其中保存著關于MySQL服務器所維護的所有其他數據庫的信息。如數據庫名&#xff0c;數據庫的表&#xff0c;表欄的數據類型與訪問權 限等。在INF…

網絡安全——SSH密碼攻擊實驗

一、實驗目的要求&#xff1a; 二、實驗設備與環境&#xff1a; 三、實驗原理&#xff1a; 四、實驗步驟&#xff1a;? 五、實驗現象、結果記錄及整理&#xff1a; 六、分析討論與思考題解答&#xff1a; 一、實驗目的要求&#xff1a; 1、了解SSH密碼攻擊、FTP密碼攻擊…

【BEV感知 EA-LSS 方案】Edge-aware Lift-splat-shot

前言 本文分享LSS方案的改進方案——EA-LSS,它解決了“深度跳變”問題,提出了一個新框架Edge-aware Lift-splat-shot 。 適用于“多視圖轉BEV”,可以代替原來的LSS模塊,并有效地提高了檢測精度,而推理時間的增加很少。 在nuScenes測試集上驗證,純相機模型或多模態模型…

Jmeter 請求簽名api接口-BeanShell

Jmeter 請求簽名api接口-BeanShell 項目簽名說明編譯擴展jar包jmeter 使用 BeanShell 調用jar包中的簽名方法 項目簽名說明 有簽名算法的api接口本地不好測試&#xff0c;使用BeanShell 擴展jar 包對參數進行簽名&#xff0c;接口簽名算法使用 sha512Hex 算法。簽名的說明如下…

Mybatis是如何進行分頁的?

程序員的公眾號&#xff1a;源1024&#xff0c;獲取更多資料&#xff0c;無加密無套路&#xff01; 最近整理了一份大廠面試資料《史上最全大廠面試題》&#xff0c;Springboot、微服務、算法、數據結構、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、數據庫等等 …

Django系列之Celery異步框架+RabbitMQ使用

在Django項目中&#xff0c;如何集成使用Celery框架來完成一些異步任務以及定時任務呢&#xff1f; 1. 安裝 pip install celery # celery框架 pip install django-celery-beat # celery定時任務使用 pip install django-celery-results # celery存儲結果使用2. Django集成…

gin投票系統3

對應視頻v1版本 1.優化登陸接口 將同步改為異步 原login前端代碼&#xff1a; <!doctype html> <html lang"en"> <head><meta charset"utf-8"><title>香香編程-投票項目</title> </head> <body> <m…

開關量防抖濾波器(梯形圖和SCL源代碼)

模擬量防抖超限報警功能塊請查看下面文章鏈接: https://rxxw-control.blog.csdn.net/article/details/133969425https://rxxw-control.blog.csdn.net/article/details/133969425 1、開關量防抖濾波器 2、防抖濾波 3、梯形圖代碼

useMemo和useCallback

useMemo和useCallback是React中的兩個優化性能的鉤子&#xff08;Hooks&#xff09;。它們都可以用來緩存計算結果&#xff0c;避免在每次渲染時都重新執行耗時的操作。然而&#xff0c;它們的主要區別在于緩存的內容和使用場景。 useMemo useMemo用于緩存那些計算成本較高的值…

2.Feign使用、上下文隔離及源碼閱讀

目錄 概述使用配置pom.xmlfeign 接口編寫controller 測試降級處理pom.xmlapplication.yml代碼 Feign如何初始化及調用源碼閱讀初始化調用 feign的上下文隔離機制源碼 結束 概述 閱讀此文&#xff0c;可以知曉 feign 使用、上下文隔離及源碼閱讀。源碼涉及兩方面&#xff1a;fe…

課后作業7.3.1:構造一個自己的小操作系統

構造一個自己的 mini 操作系統 任務描述 請實現如下功能&#xff1a; 1.寫一個命令解釋器程序 mysh.c &#xff0c;其功能是接收用戶輸入的命令并給出反饋。要求該程序既支持內部命令 cd、sync、exit &#xff1b;也支持外部命令&#xff0c;即可以接收 cat、ls 等命令&#x…

數據結構與算法-Rust 版讀書筆記-2線性數據結構-雙端隊列

數據結構與算法-Rust 版讀書筆記-2線性數據結構-雙端隊列 1、雙端隊列 deque又稱為雙端隊列&#xff0c;雙端隊列是與隊列類似的項的有序集合。deque有兩個端部&#xff1a;首端和尾端。deque不同于隊列的地方就在于項的添加和刪除是不受限制的&#xff0c;既可以從首尾兩端添…

vue3封裝接口

在src下面創建一個文件夾任意名稱 我拿這個名字舉例子了apiService 相當于創建一個新的文件 // 封裝接口 // apiService.js import axios from axios;// 接口前綴 const API_BASE_URL 前綴;接口后綴export const registerUser async (fileData) > {try {const response …

數據分析 | 頻率編碼和標簽編碼 | Python代碼

數據集見GitHub鏈接&#xff1a;https://github.com/ChuanTaoLai/Frequency-Encoding-And-Label-Encoding 標簽編碼&#xff1a; import pandas as pd from sklearn.preprocessing import LabelEncoderdata1 pd.read_excel(rD:\0文獻整理\網絡入侵檢測\KDD99\KDDTrain.xlsx) …

透析跳躍游戲

關卡名 理解與貪心有關的高頻問題 我會了?? 內容 1.理解跳躍游戲問題如何判斷是否能到達終點 ?? 2.如果能到終點&#xff0c;如何確定最少跳躍次數 ?? 1. 跳躍游戲 leetCode 55 給定一個非負整數數組&#xff0c;你最初位于數組的第一個位置。數組中的每個元素代表…