【C語言】—— 動態內存管理

【C語言】——動態內存管理

一、動態內存管理概述

1.1、動態內存的概念

??在了解為什么要有動態內存管理之前,我們得先知道動態內存的定義

??動態內存是指動態的內存空間,意思就是:能動態開辟的內存空間動態就是申請了這塊空間后,可動態的修改這塊空間的大小,根據需要,動態地釋放和分配內存空間
??

1.2、動態內存的必要性

??為什么要有動態內存呢?
??既然有動態內存,那與之相對的就是靜態內存
??什么是靜態內存呢?其實靜態內存我們天天都在用,只是不知道它是靜態內存而已
??
下面兩種內存開辟方式就是靜態內存

int val = 20;//在棧空間上開辟四個字節
char arr[10] = { 0 };//在棧空間上開辟10個字節的連續空間

??

但是靜態內存的開辟有兩個缺點

  • 空間開辟的大小是固定
  • 數組在申明的時候,必須指定數組的長度,數組空間一旦確定了大小不能調整

??但是,在實際需求中,我們往往只有在程序運行時才能知道所需的空間大小,用數組開辟空間,往往容易造成內存溢出(空間開小),或者內存浪費(空間開大),無法滿足實際的需求
??
??因此,C語言引入了動態內存開辟,讓程序員自己可以申請和釋放空間,并根據需要,自己調整開辟后空間的大小。這樣不僅提高了內存的利用率,也極大地增強了程序的靈活性擴展性
??
??

二、 m a l l o c malloc malloc 函數

2.1、函數介紹

??C語言中提供了一個動態內存分配的函數: m a l l o c malloc malloc

在這里插入圖片描述

功能:向內存申請一塊連續可用的空間(可當成數組),并返回指向這塊空間的指針

  • 參數 s i z e size size_ t t t s i z e size size

    • 分配的內存的大小,以字節為單位。即開辟 s i z e size size 字節大小的空間
    • 如果參數為 0 m a l l o c malloc malloc 的行為是標準未定義的,取決于編譯器
      ??
  • 返回值 v o i d void void *

    • 返回指向開辟空間的指針,因為 m a l l o c malloc malloc 函數 事先并不知道使用者開辟空間存放什么類型的數據,因此指針為 v o i d void void* 類型,以便能接受所有類型。
    • 使用者可根據自己的需要,將其強制類型轉換成自己所需要的類型,以便能進行解引用操作。
    • 如果開辟失敗,則返回 空指針,因此 m a l l o c malloc malloc 的返回值一定要做檢查

??

2.2、應用舉例

#include<stdlib.h>int main()
{int* p = NULL;p = (int*)malloc(10 * sizeof(int));if (NULL == p){perror("malloc fail");return 1;}return 0;
}

上述代碼是使用 m a l l o c malloc malloc 函數開辟 10 個整型變量的空間,也即 40 個字節的空間

  • 首先,因為 m a l l o c malloc malloc 函數的返回值是指針,我們需用指針變量 p p p 接收其返回值,創建 p p p 時,并不知道其指向的空間,所以先初始化為 NULL。
  • 接著,使用 m a l l o c malloc malloc 函數開辟空間,因為我們要存放的是整型變量,而 m a l l o c malloc malloc 的返回值類型為 v o i d void void* 我們通過強制類型轉換將其返回類型轉換為 i n t int int* ,并用 p p p 來接收
  • 因為 m a l l o c malloc malloc 函數有可能開辟失敗1,只有當返回值不為空的情況我們才使用它,因此需判斷 p p p 指針是否為空。若為空,則用 p e r r o r perror perror 函數2打印出錯誤信息,并返回 13
  • 若開辟成功,我們就可以愉快地使用這塊空間啦

在這里插入圖片描述

??需要注意的是: m a l l o c malloc malloc 開辟的空間并不會將其初始化
??
??

三、 c a l l o c calloc calloc 函數

??開辟動態內存空間,C語言還提供了一個函數叫 c a l l o c calloc calloc ,原型如下:

在這里插入圖片描述

  • 函數的功能是為 n u m num num 個大小為 s i z e size size 的元素開辟一塊空間,并將這塊空間初始化為 0
  • 與函數 m a l l o c malloc malloc 的區別只在于 c a l l o c calloc calloc 會返回地址之前把申請的空間的每個字節初始化為全 0

舉個例子:

#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)calloc(10, sizeof(int));if (NULL != p){int i = 0;for (i = 0; i < 10; i++){printf(" %d", *(p + i));}printf("\n");}return 0;
}

??
運行結果:

在這里插入圖片描述

??
??

四、 f r e e free free 函數

4.1、函數介紹

??
??上述 m a l l o c malloc malloc 函數、 c a l l o c calloc calloc 函數以及后面講的 r e a l l o c realloc realloc 函數所申請的空間,并不滿足作用域的規則。只有當程序退出時,用他們開辟的動態空間才會歸還給操作系統,換言之,程序不退出,就不會主動歸還空間。這時,我們就需要 f r e e free free函數 來對其主動釋放

?? f r e e free free 函數是專門用于動態開辟的內存空間的釋放回收,聲明如下:

在這里插入圖片描述

??
f r e e free free 函數用來釋放動態開辟的內存

  • 如果參數 p t r ptr ptr 指向的空間不是動態開辟的,那 f r e e free free 函數的行為是未定義
  • 如果參數是 p t r ptr ptr 是NULL指針,則函數什么事都不做
  • 需要注意的是, f r e e free free 函數不會改變指針所指向的值,釋放后它依然指向相同的內存空間。因此我們要手動將釋放后的 p t r ptr ptr 置空,避免出現野指針。

m a l l o c malloc malloc c a l l o c calloc calloc 以及 f r e e free free 函數的聲明都在 < s t d l i b . h > <stdlib.h> <stdlib.h>
??

4.2、應用舉例

??
我們來看個例子:

#include<stdio.h>
#include<stdlib.h>int main()
{int* ptr = NULL;ptr = (int*)malloc(10 * sizeof(int));if (NULL != ptr){int i = 0;for (i = 0; i < 10; i++){*(ptr + i) = 0;}}free(ptr);ptr = NULL;return 0;
}

在這里插入圖片描述

??
??那我們來看看下面這種情況行不行呢?

int main()
{int* ptr = NULL;ptr = (int*)malloc(5 * sizeof(int));if (NULL != ptr){int i = 0;for (i = 0; i < 5; i++){*ptr = 0;ptr++;}}free(ptr);ptr = NULL;return 0;
}

??當然是不行的,為什么呢?
??因為傳遞給 f r e e free free 函數的是要釋放空間的 起始地址
??上面函數的 p t r ptr ptr 以及不再指向要釋放空間的起始地址了,當然是不行的。
??
??

五、 r e a l l o c realloc realloc 函數

5.1、函數介紹

??
??可能有小伙伴問:前面你說動態內存可根據需要,動態調整所開辟空間的大小,但前面介紹 m a l l o c malloc malloc c a l l o c calloc calloc 以及 f r e e free free函數 都只是在將動態空間的開辟和釋放,如何調整空間的大小呢?別急,我們接下來要講的 r e l l o c relloc relloc函數 就是完成調整開辟空間的大小的任務的

?? r e a l l o c realloc realloc 函數的出現讓動態內存管理更加靈活
??
??有時我們會發現之前申請的空間太小了,有時我們又會覺得申請的空間太大了,那為了合理的使用內存,,我們一定會對內存的大小做出靈活的調整。那 r e a l l o c realloc realloc函數 就可以做到對動態開辟內存大小的調整

先來看看 r e l l o c relloc relloc函數 的聲明:

在這里插入圖片描述

  • p t r ptr ptr 是要調整的內存地址
  • s i z e size size 是調整之后的大小(可以變大,也可變小)
  • 返回值為調整之后的內存起始位置

r e a l l o c realloc realloc 調整內存大小分為三種情況:

在這里插入圖片描述

  1. 原有空間之后有足夠大的空間

??如上圖: r e l l o c relloc relloc 已經開辟 20 個字節的空間,現在我想擴容到 40 字節,同時原有空間后方空間足夠擴展新空間
??
??此時 r e a l l o c realloc realloc 函數直接在后方追加空間,原來空間的數據不發生變化

??
2. 原有空間之后沒有足夠大的空間

??還是上面那個圖,現在我想將他擴容到 400 字節,很明顯,已開辟空間后方沒有足夠的空間,總不能把別人踢開,自己霸占吧
??這時, r e a l l o c realloc realloc 函數就會堆空間 另外找一個 合適大小的空間
??
具體流程如下:

  • r e a l l o c realloc realloc 函數先在堆空間上找一塊新的空間,并且滿足大小要求
  • 后將舊空間的數據拷貝到新空間中
  • 接著釋放舊空間
  • 最后返回新空間的起始地址

??
3. 空間調整失敗

?? r e a l l o c realloc realloc 可能出現空間調整失敗的情況,此時返回的是空指針

??
??
?? r e a l l o c realloc realloc 不僅僅能將空間的變大,還能將空間變小,只需要第二個參數的值小于原空間的大小就好了,因為縮小空間比較簡單,這里就不再過多介紹,但需要注意的是,縮小空間可能會造成數據丟失,因此需小心使用

??同時 r e a l l o c realloc realloc函數 不僅能調整空間大小,還能完成 m a l l o c malloc malloc函數 的功能:當第一個參數 p t r ptr ptr 傳遞的是 空指針 時, r e a l l o c realloc realloc 函數就不再是調整空間大小了,你都沒空間,我還怎么調。此時 r e a l l o c realloc realloc 函數會 新開辟 s i z e size size 字節大小的空間
??
??

5.2、應用舉例

??看了上面三種情況,大家想一想,應該怎樣接收 r e a l l o c realloc realloc 調整之后的返回值呢?
??可以直接用原來的指針 p p p 接收嗎?

??顯然是不行,如果 r e a l l o c realloc realloc 調整成功,那確實沒問題,但如果失敗了呢?此時返回的是空指針。本來 p p p 還維護著原來的空間,現在直接變空指針,那原來的空間再也找不到了,這就造成了內存泄漏

??正確的方法是創建新的指針 p t r ptr ptr 來接收,當 p t r ptr ptr 不為 NULL,再將 p t r ptr ptr 的值傳給 p p p
??
如下:

#include<stdlib.h>int main()
{int* p = (int*)malloc(5 * sizeof(int));if (NULL == p){perror("malloc fail");return 1;}//1 2 3 4 5for (int i = 0; i < 5; i++){*(p + i) = i + 1;}//希望將空間調整為40個字節int* ptr = NULL;ptr = (int*)realloc(p, 40);if (NULL != ptr){p = ptr;}else{perror("realloc fail");}//調整成功,使用40個字節;調整失敗,繼續使用20個字節/**************業務處理**************/free(p);p = NULL;return 0;
}

??
??

六、常見的動態內存錯誤

6.1、對NULL指針進行解引用

??

#include<stdlib.h>int main(
{int* p = (int*)malloc(INT_MAX);*p = 20;//如果p的值是空指針,就會有問題free(p);p = NULL;return 0;
}

??
??動態開辟的空間,應該先對返回值進行判斷,確保空間開辟成功
??上述代碼所要開辟的空間太大,開辟失敗,返回的是空指針,而下面一句代碼對空指針進行解引用,是錯誤的
??

#include<stdlib.h>int main()
{int* p = (int*)malloc(10 * INT_MAX);if (NULL == p){perror("malloc fail");return 1;}*p = 20;free(p);p = NULL;return 0;
}

在這里插入圖片描述

??

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

??

#include<stdlib.h>int mian()
{int i = 0;int* p = (int*)malloc(10 * sizeof(int));if (NULL == p){exit(EXIT_FAILURE);}for (i = 0; i <= 10; i++){*(p + i) = i;}free(p);p = NULL;return 0;
}

??可以看到,當 i i i = 10 時,就是對 m a l l o c malloc malloc 開辟的空間越界訪問了。
??動態內存的空間與數組是非常相似的,要注意不能對其越界訪問
??

6.3、對非動態開辟的內存使用 f r e e free free 釋放

void test()
{int a = 10;int* p = &a;free(p);//ok?
}

??變量 a a a 并不是動態開辟的變量,用 f r e e free free 釋放是錯誤的
??
??

6.4、使用 f r e e free free 釋放一塊動態開辟內存的一部分

??這種情況即是,傳給 f r e e free free 的指針并不是動態開辟內存的起始地址,指針跑后面去了。

void test()
{int* p = (int*)malloc(100);p++;free(p);//p不再指向動態內存的起始位置
}

??注意:動態內存一定是 一同申請,一同釋放。無法做到只釋放一部分空間
??

6.5、對同一塊動態內存多重釋放


void test()
{int* p = (int*)malloc(100);//···free(p);free(p);//重復釋放
}

??這種釋放有辦法可以避免:釋放完后及時 p p p 置為空指針,這樣,即使再次釋放,傳的是空指針, f r e e free free 什么都不會做,不會造成什么影響
??

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

#include<stdlib.h>
void test()
{int* p = (int*)malloc(100);if (NULL != p){*p = 20;}
}int main()
{test();while (1);return 0;
}

??上述代碼,你會發現,一旦出了函數,就再也找不到開辟的那 100 個字節的空間(這代碼寫的比較極端,一直死循環,程序一直不結束) 。找不到開辟的空間更別提將其釋放,空間就一直在那占著,就造成了內存泄漏

??想一想,如果我們一直向內存申請空間,但從來不釋放。要知道,內存的總大小是有限的,這樣就會把內存耗干,機器就掛了。

??
總結: m a l l o c malloc malloc c a l l o c calloc calloc r e a l l o c realloc realloc 申請的空間,盡量做到:

  • 誰(可能是函數)申請的就誰釋放,即 m a l l o c malloc malloc f r e e free free 成對出現
  • 如果不能釋放,要告訴使用的人記得釋放

??
??

七、動態內存經典筆試題分析

7.1、題一

void GetMemory(char* p)
{p = (char*)malloc(100);
}void Test(void)
{char* str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}int main()
{Test();return 0;
}

請問運行 T e s t Test Test 函數會有什么樣的結果?

運行 T e s t Test Test 函數,程序會崩潰
??
為什么呢?我們來分析一下
??
先來看這段代碼想要做什么:

  1. 首先,它定義了一個 G e t M e m o r y GetMemory GetMemory函數,很明顯,這個函數是完成動態開辟空間任務的
  2. 接著 T e s t Test Test函數 中創建了指針 s t r str str,將變量傳給 G e t M e m o r y GetMemory GetMemory,即希望指針 s t r str str 管理動態開辟的空間
  3. 最后往空間中存入 " h e l l o w o r l d " "hello world" "helloworld",并打印

??
??代碼的邏輯沒問題,那就是代碼本身出問題咯

在這里插入圖片描述

??通過調試我們發現, G e t M e m o r y GetMemory GetMemory函數 并沒有改變 s t r str str 的值,它依然是個空指針。

??為什么呢?因為 G e t M e m o r y GetMemory GetMemory傳值傳參,而不是傳址傳參!傳值傳參無法改變主調函數中的值,出了函數 s t r str str 依然是空指針,而后面打印 s t r str str 指向的內容,是要對其解引用的,對空指針解引用自然會出問題。
??同時,函數中 m a l l o c malloc malloc實打實開辟了空間的,只有程序結束才銷毀,而函數中的變量出了函數作用域就銷毀,這樣函數中所開辟的 100 個字節空間出了 G e t M e m o r y GetMemory GetMemory函數 后也無法找到,造成內存泄漏=

??可能有小伙伴會問: G e t M e m o r y GetMemory GetMemory函數 的參數類型就是 c h a r char char* 啊,為什么還是傳值傳參呢?這里我們要指針傳址傳參的本質:傳遞的是變量的地址,因為主調函數中要傳的值本身就是指針 c h a r char char* 類型,要改變指針變量,就要傳遞指針變量的指針,即二級指針。這里可不敢看到 G e t M e m o r y GetMemory GetMemory函數 參數中是 c h a r char char* 就認為他是傳址傳參
??
正確寫法應該是這樣:

void GetMemory(char** p)
{*p = (char*)malloc(100);
}void Test(void)
{char* str = NULL;//傳str的地址GetMemory(&str);strcpy(str, "hello world");printf(str);//釋放動態空間free(str);str = NULL;
}

當然, G e t M e m o r y GetMemory GetMemory函數 我們也可以直接讓他返回 p p p,以實現目的

char* GetMemory()
{char* p = (char*)malloc(100);return p;
}void Test(void)
{char* str = GetMemory();strcpy(str, "hello world");printf(str);free(str);str = NULL;
}

??
??

7.2、題二

char* GetMemory(void)
{char p[] = "hello world";return p;
}void Test(void)
{char* str = NULL;str = GetMemory();printf(str);
}int main()
{Test();return 0;
}

運行結果:

在這里插入圖片描述

??為什么會這樣呢?
??問題還是出在 G e t M e m o r y GetMemory GetMemory函數

?? G e t M e m o r y GetMemory GetMemory函數 中創建的 p p p 數組,在出了函數作用域后就銷毀了,因此函數返回 p p p,用 s t r str str 接收,而實際上 s t r str str 接收的地址是指向一塊已經歸還的空間,此時的 s t r str str野指針。再去訪問 s t r str str 所指向的空間是非法訪問,打印出的值是隨機值。
??
??

7.3、題三

void GetMemory(char** p, int num)
{*p = (char*)malloc(num);
}
void Test(void)
{char* str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);
}
int main()
{Test();return 0;
}

??可能有小伙伴會覺得這段代碼咋一看好像沒什么問題啊

??確實,大家有沒有發現代碼與我們第一題修改后的代碼非常像,但大家仔細想想它還缺少什么?

??這段代碼唯一的問題是:沒有 f r e e free free,動態申請內存空間后他并沒有還回去。

??雖然這里沒有 f r e e free free 程序也沒有問題,因此程序結束后會自動釋放空間,但以后遇到復雜的情況就不好說了,因此我們要 養成主動釋放內存空間的習慣
??
??

7.4、題四

void Test(void)
{char* str = (char*)malloc(100);strcpy(str, "hello");free(str);if (str != NULL){strcpy(str, "world");printf(str);}
}
int main()
{Test();return 0;
}

??這題的問題相信大家都能看得出來:
??
?? T e s t Test Test函數 上來先開辟 100 字節動態空間,并創建 s t r str str 變量維護它,再向空間中放 " h e l l o " "hello" "hello"
??
??但緊接著,釋放 s t r str str卻沒將 s t r str str 置空,此時的 s t r str str野指針。將空間釋放,即將其還給操作系統,我們是沒有使用權限了,但是這塊空間本身還在
??
??下面的 i f if if 語句判斷為真,往 s t r str str 指向的空間放入 " w o r l d " "world" "world",此時 s t r str str 指向的空間我們已經沒有使用權限了,但依然進行修改,為非法內存訪問。
??
??

八、柔性數組

8.1、什么是柔性數組

??
??也許有些小伙伴從來沒有聽過柔性數組這個概念,但是它確實是存在的
??C99 中,結構體的最后一個元素允許是未知大小的數組,這就叫做:柔性數組成員
??

typedef struct st_type
{int i;int a[0];
}type_a;

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

typedef struct st_type
{int i;int a[];
}type_a;

??
??

8.2、柔性數組的特點

  • 結構體中的柔性數組成員前面必須至少一個其他成員
  • s i z e o f sizeof sizeof 返回的這種結構體大小不包括柔性數組的內存
  • 包含柔性數組成員的結構體一般用 m a l l o c malloc malloc函數 進行內存的動態分配,并且分配的內存應該大于結構體的大小,以適應柔性數組的預期大小

例如:

typedef struct st_type
{int i;int a[0];
}type_a;
int main()
{printf("%d\n", sizeof(type_a));return 0;
}

運行結果:

在這里插入圖片描述

??
??

8.2、柔性數組的使用

#include<stdio.h>
#include<stdlib.h>typedef struct st_type
{int i;int a[0];
}type_a;int main()
{int i = 0;type_a* p = (type_a*)malloc(sizeof(type_a) + 10 * sizeof(int));if (NULL == p){perror("malloc fail");return 1;}//業務處理p->i = 10;for (i = 0; i < 10; i++){p->a[i] = i;}//調整空間type_a* ptr = (type_a*)realloc(p, sizeof(type_a) + 20 * sizeof(int));if (ptr != NULL){p = ptr;}free(p);p = NULL;return 0;
}

柔性數組的結構:在這里插入圖片描述

??既然這塊空間是 m a l l o c malloc malloc 出來的,也就是說他可以通過 r e a l l o c realloc realloc 來調整大小,所以這個數組可變長變短,不就是柔性
??
??

8.3、柔性數組的優勢

??
??上述 t y p e type type_ a a a 結構,也可以設計為下面的結構,也能完成同樣的效果

#include<stdio.h>
#include<stdlib.h>typedef struct st_type
{int i;int* p_a;
}st_type;
int main()
{st_type* p = (st_type*)malloc(sizeof(st_type));p->i = 100;p->p_a = (int*)malloc(p->i * sizeof(int));///業務處理for (i = 0; i < 100; i++){p->p_a[i] = i;}//釋放空間free(p->p_a);p->p_a = NULL;free(p);p = NULL;return 0;
}

圖示:

在這里插入圖片描述

??上述兩個方法都可以達到類似的效果

??但是使用柔性數組有兩個好處
??

  • 方便內存釋放
    ??如果我們的代碼是在一個給別人用的函數中,你在里面做了二次內存分配,并把結構體返回給用戶。用戶調用 f r e e free free 可以釋放結構體,但是用戶并不知道結構體內的成員也需要 f r e e free free,所以你不能指望用戶來發現這個事
    ??所以,如果我們把結構體的內存以及其成員要的內存一次性分配好了,并返回給用戶一個結構體指針,用戶做一次 f r e e free free 就可以把所有的內存釋放掉
    ??
  • 有利于訪問速度
    ??連續的內存有益于提高訪問速度,也有益于減少內存碎片4

??
??

九、C/C++中內存區域劃分

在這里插入圖片描述

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

  • 內核空間操作系統核心(內核)運行的地方,在這個區域,操作系統可以直接訪問硬件,并執行特權指令。我們用戶是無權訪問這塊空間的
  • 棧區:在執行函數時,函數內局部變量的存儲單元都是在棧上創建,函數執行結束時這些存儲單元自動釋放。棧內存分配運算內置于處理器的指令中,效率很高,但是分配的內存容量有限。棧區只要存放運行函數而分配的局部變量、函數參數、返回數據、返回地址等。
  • 堆區:堆區一般是用來存儲程序運行期間動態分配內存的地方。堆區的內存分配是在程序運行時動態進行的,程序員可以通過調用標準庫函數(如 m a l l o c malloc malloc c a l l o c calloc calloc r e a l l o c realloc realloc等)來在堆區中分配內存,并在不需要時手動釋放這些內存(使用 f r e e free free函數)。使用堆區需要注意內存泄漏 m e m o r y l e a k memory leak memoryleak)的問題,即程序在不再需要某塊內存時沒有釋放它,導致程序占用的內存越來越多。
  • 數據段:數據段也叫做靜態區,主要用來存放全局變量、靜態數據、全局變量。程序結束后由系統釋放
  • 代碼段:存放函數體(類成員函數和全局函數)的二進制代碼、只讀常量(字符串常量)

  1. 內存開辟失敗:動態內存開辟失敗的原因一般都是所空間太大,沒有足夠的空間 ??

  2. p e r r o r perror perror函數:有關該函數的具體介紹請看:《【C語言】——字符串函數的使用與模擬實現(下)》 ??

  3. 返回值為 1: m a i n main main 函數程序正常退出,返回值為 0;異常退出,返回值為 1 ??

  4. 我們開辟內存時,不會緊接著上一塊內存開辟,而會留下一點空隙,開辟次數越多,留下的空隙也就也多,這些空隙稱為內存碎片。 ??

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

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

相關文章

無列名注入

在進行sql注入時&#xff0c;一般都是使用 information_schema 庫來獲取表名與列名&#xff0c;因此有一種場景是傳入參數時會將 information_schema 過濾 在這種情況下&#xff0c;由于 information_schema 無法使用&#xff0c;我們無法獲取表名與列名。 表名獲取方式 Inn…

Redis——Redis集群腦裂問題

Redis集群的腦裂問題&#xff08;Split-Brain&#xff09;是一個在分布式系統中可能發生的嚴重問題&#xff0c;特別是在基于主從復制和哨兵&#xff08;Sentinel&#xff09;機制的Redis集群環境中。以下是對Redis集群腦裂問題的詳細闡述&#xff1a; 定義 Redis集群腦裂問題…

FullCalendar日歷組件集成實戰(3)

背景 有一些應用系統或應用功能&#xff0c;如日程管理、任務管理需要使用到日歷組件。雖然Element Plus也提供了日歷組件&#xff0c;但功能比較簡單&#xff0c;用來做數據展現勉強可用。但如果需要進行復雜的數據展示&#xff0c;以及互動操作如通過點擊添加事件&#xff0…

SwiftUI中的常用圖形(Shapes)

概述 在SwiftUI中&#xff0c;常用的圖形&#xff08;Shape&#xff09;主要有&#xff1a; Circle&#xff1a;圓形 Ellipse&#xff1a;橢圓形 Capsule&#xff1a;膠囊形 Rectangle&#xff1a;矩形 RoundedRectangle&#xff1a;圓角矩形 上面的這些圖形都繼承了Shape協議…

DFA算法 敏感詞過濾方案匯總以及高效工具sensitive-word

敏感詞過濾方案匯總以及高效工具sensitive-word 導入pom文件 <dependency><groupId>com.github.houbb</groupId><artifactId>sensitive-word</artifactId><version>0.12.0</version> </dependency>接下來我們編寫相關測試類…

解四層負載和七層負載:Nginx 的應用示范

在網絡架構中&#xff0c;負載均衡是分配網絡或應用程序流量到多個服務器的技術&#xff0c;以優化資源使用、最大化吞吐量、最小化響應時間和避免任何單一資源的過載。Nginx&#xff0c;作為一款強大的HTTP和反向代理服務器&#xff0c;能夠處理七層&#xff08;應用層&#x…

深入剖析JVM、JDK和JRE的區別與聯系

在Java開發和運行過程中&#xff0c;JVM、JRE和JDK是三個核心組件。理解它們的區別和聯系是每個Java開發者的基礎技能。本文將深入探討這三個組件的作用、組成及其在實際應用中的重要性。 一、Java虛擬機&#xff08;JVM&#xff09; **JVM&#xff08;Java Virtual Machine&…

Hive讀寫文件機制

Hive讀寫文件機制 1.SerDe是什么&#xff1f; SerDe是Hive中的一個概念&#xff0c;代表著“序列化/反序列化” &#xff08;Serializer/Deserializer&#xff09;。 SerDe在Hive中是用來處理數據如何在Hive與底層存儲系統&#xff08;例如HDFS&#xff09;之間進行轉換的機制…

ceph糾刪碼精簡配置ec4+2:1與ec4+2的切換

概述 近期遇到項目&#xff0c;由于靈活配置&#xff0c;前期只有部分機器&#xff0c;后續擴容&#xff0c;想用ec42的糾刪碼&#xff0c;但前期只有3臺機器&#xff0c;需要做精簡ec。 erasure-code-profile 首先按照ceph創建糾刪碼池步驟進行操作。 創建ec42的rule cep…

2024國考行測、申論資料大全,做好備考真的很重要!

1. 國考是什么? 國考,全稱國家公務員考試,是選拔國家公務員的重要途徑。通過國考,你將有機會進入政府部門,為國家建設貢獻力量。 2. 國考難在哪里? 國考之所以難,主要體現在以下幾個方面: (1) 競爭激烈 每年國考報名人數都在百萬以上,而錄取率卻不足2%。千軍萬馬過獨木橋…

前端環境準備的一些注意事項

1. 安裝 node-sass4.x 需要python 2 和visual studio 2017&#xff0c;visual 2019版本不行。 2. python版本更新問題 python重新配置環境變量時&#xff0c;不會立馬生效&#xff0c;重啟可生效。 3. node版本問題 接觸一個新的項目&#xff0c;搞清楚node版本再開始準備…

node和npm版本太高導致項目無法正常安裝依賴以及正常運行的解決辦法:如何使用nvm對node和npm版本進行切換和管理

1&#xff0c;點擊下載 nvm 并且安裝 進入nvm的github&#xff1a; GitHub - coreybutler/nvm-windows: A node.js version management utility for Windows. Ironically written in Go. 這里下載發行版&#xff0c;Releases coreybutler/nvm-windows GitHub 找到 這個 nv…

洗地機哪款好用?希亦、追覓、順造、米家等高品質洗地機推薦

家用洗地機已經成為家庭清潔的重要利器&#xff0c;其多功能性能幫助您輕松應對各種清潔任務&#xff0c;從而保持家居環境的清潔整潔。然而&#xff0c;市場上品牌繁多、功能各異的洗地機讓人眼花繚亂。為了幫助大家做出明智的選擇&#xff0c;我們將在本文中提供全面的選購指…

4.3 將AX寄存器中的16位數分成4組,每組4位,然后把這四組數分別放在AL,BL,CL和DL中

思路&#xff1a; 主要是通過SHR指令對AX寄存器進行移位&#xff0c;有個容易出錯的地方就是&#xff0c;當移位數超過1時&#xff0c;不能直接用指令SHR&#xff0c;而應該先將移位數存入CL&#xff0c;再使用指令SHR AH,CL。舉個例子&#xff1a; SHR AX,1 ;是可以的 SHR A…

選擇法(數值排序)(C語言)

一、運行結果&#xff1b; 二、源代碼&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//聲明排序函數sort; void sort(int a[], int n);int main() {//初始化變量值&#xff1b;int i, a[10];//填充數組&#xff1b;printf("請輸入10個整數\n&…

win的開發環境配置(Java開發必備)

文章目錄 日常app工具類app開發類app環境類app 由于每次換新工作、用一臺臨時或者新的電腦時總是要想著要下載什么軟件&#xff0c;這次就一次性全部記錄下來&#xff0c;將必須下載的內容做個記錄。 日常app 百度網盤、微信、網易云、搜狗 工具類app office、bandizip&…

現代 c++ 一:c++11 ~ c++23 新特性匯總

所謂現代 c&#xff0c;指的是從 c11 開始的 c&#xff0c;從 c11 開始&#xff0c;加入一些比較現代的語言特性和改進了的庫實現&#xff0c;使得用 c 開發少了很多心智負擔&#xff0c;程序也更加健壯&#xff0c;“看起來像一門新語言”。 從 c11 開始&#xff0c;每 3 年發…

藍橋杯備戰22.k倍區間——前綴和

目錄 題目 分析 暴力求解 優化思路 AC代碼 題目鏈接&#xff1a; P8649 [藍橋杯 2017 省 B] k 倍區間 - 洛谷 | 計算機科學教育新生態 (luogu.com.cn) 題目 分析 很明顯這題是一道前綴和的題 暴力求解 只得了28分 #include<iostream> using namespace std; co…

企業在實施RPA技術時,應如何確保其ROI評估的準確性和全面性?

企業在實施RPA&#xff08;Robotic Process Automation&#xff09;技術時&#xff0c;確保ROI&#xff08;投資回報率&#xff09;評估的準確性和全面性是至關重要的。以下是確保ROI評估準確性和全面性的一些關鍵步驟&#xff1a; ### 1. 明確業務目標 首先&#xff0c;企業需…

1、工廠模式

一、C常用設計模式 &#xff1a;工廠模式 1、why2、when3、what4、how 1、why #include <iostream>class Phone { };class XiaoMi : public Phone { };class Apple : public Phone { };class Huawei : public Phone { };class Oppo : public Phone { };class Vivo : pub…