前端學習C語言 - 函數和關鍵字

来源:https://www.cnblogs.com/pengjiali/archive/2023/06/19/17492014.html
-Advertisement-
Play Games

## 函數和關鍵字 本篇主要介紹:`自定義函數`、`巨集函數`、`字元串處理函數`和`關鍵字`。 ### 自定義函數 #### 基本用法 實現一個 add() 函數。請看示例: ```c #include // 自定義函數,用於計算兩個整數的和 int add(int a, int b) { // a ...


函數和關鍵字

本篇主要介紹:自定義函數巨集函數字元串處理函數關鍵字

自定義函數

基本用法

實現一個 add() 函數。請看示例:

#include <stdio.h>

// 自定義函數,用於計算兩個整數的和
int add(int a, int b) { // a, b 叫形參
    int sum = a + b;
    return sum;
}

int main() {
    int num1 = 3;
    int num2 = 5;
    
    // 調用自定義函數計算兩個整數的和
    int result = add(num1, num2); // num1, num2 叫實參
    
    printf("兩個整數的和為:%d\n", result);
    
    return 0;
}

其中a, b 叫形參,num1, num2 叫實參

Tip:形參和實參的個數不同,筆者編譯器報錯如下(一個說給函數的參數少,一個說給函數的參數多了):

// 3個形參,2個實參
int add(int a, int b, int c) {}

//  error: too few arguments to function call, expected 3, have 2
int result = add(num1, num2);
// 2個形參,3個實參
int add(int a, int b) {}

// error: too many arguments to function call, expected 2, have 3
int result = add(num1, num2, num1);

函數調用過程

函數調用過程:

  1. 通過函數名找到函數的入口地址
  2. 給形參分配記憶體空間
  3. 傳參。包含值傳遞地址傳遞(比如js中的對象)
  4. 執行函數體
  5. 返回數據
  6. 釋放空間。例如棧空間

請看示例:

#include <stdio.h>

// 2. 給形參分配記憶體空間
// 3. 傳參:值傳遞和地址傳遞(比如js中的對象)
// 4. 執行函數體
// 5. 返回數據
// 6. 釋放空間。例如棧空間:局部變數 a,b,sum
int add(int a, int b) {
    int sum = a + b;
    return sum;
}

int main() {
    int num1 = 3;
    int num2 = 5;
    
    // 1. 通過函數名找到函數的入口地址
    int result = add(num1, num2); 
    
    printf("add() 的地址:%p\n", add);
    printf("%d\n", result);
    
    return 0;
}

輸出:

add() 的地址:0x401130
8

練習-sizeof

題目:以下兩次 sizeof 輸出的值相同嗎?

#include <stdio.h>

void printSize(int arr[]) {
    printf("Size of arr: %zu\n", sizeof(arr));
}

int main() {
    int nums[] = {1, 2, 3, 4, 5};
    
    printf("Size of nums: %zu\n", sizeof(nums));
    printSize(nums);
    
    return 0;
}

運行:

開始運行...
// sizeof(arr) 獲取的是指針類型 int * 的大小(在此例中是8位元組)
/workspace/CProject-test/main.c:4:40: warning: sizeof on array function parameter will return size of 'int *' instead of 'int[]' [-Wsizeof-array-argument]
    printf("Size of arr: %zu\n", sizeof(arr));
                                       ^
/workspace/CProject-test/main.c:3:20: note: declared here
void printSize(int arr[]) {
                   ^
1 warning generated.
Size of nums: 20
Size of arr: 8

運行結束。

結果:輸出不相同,一個是數組的大小,一個卻是指針類型的大小。

結果分析:將一個數組作為函數的參數傳遞時,它會被隱式地轉換為指向數組首元素的指針,然後在函數中使用 sizeof 運算符獲取數組大小時,實際上返回的是指針類型的大小((通常為4或8位元組,取決於系統架構)),而不是整個數組的大小。

巨集函數

巨集函數是C語言中的一種預處理指令,用於在編譯之前將代碼片段進行替換

之前我們用 #define 定義了常量:#define MAX_NUM 100。定義巨集函數就是將常量改為函數。就像這樣

#include <stdio.h>
// 無參
#define PRINT printf("hello\n")

// 有參
#define PRINT2(n) printf("%d\n", n)

int main() {

    // 無參調用
    PRINT;
    // 有參調用
    PRINT2(10);    
    return 0;
}

輸出:hello 10

編譯流程

巨集函數發生在編譯的第一步。

編譯可以分為以下幾個步驟:

  • 預處理(Preprocessing):在這一步中,預處理器將對源代碼進行處理。它會展開巨集定義、處理條件編譯指令(如 #if、#ifdef 等)、包含頭文件等操作。處理後的代碼會生成一個被稱為預處理文件(通常以 .i 或 .ii 為擴展名)。
  • 編譯(Compilation):在這一步中,編譯器將預處理後的代碼翻譯成彙編語言。它會進行詞法分析、語法分析、語義分析和優化等操作,將高級語言的代碼轉化為低級機器可以理解的形式。輸出的文件通常以 .s 為擴展名,是一個彙編語言文件。
  • 彙編(Assembly):彙編器將彙編語言代碼轉換為機器語言指令。它將每條彙編語句映射到對應的機器語言指令,並生成一個目標文件(通常以 .o 或 .obj 為擴展名),其中包含已彙編的機器指令和符號表信息。
  • 鏈接(Linking):如果程式涉及多個源文件,以及使用了外部庫函數或共用的代碼模塊,鏈接器將合併和解析這些文件和模塊。它會將目標文件與庫文件進行鏈接,解析符號引用、處理重定位等。最終生成可執行文件(或共用庫),其中包含了完整的機器指令。

這些步驟並非一成不變,具體的編譯過程可能因為編譯器工具鏈和目標平臺的不同而有所差異。但是大致上,這是一個常見的編譯流程。

巨集函數 vs 普通函數

用普通函數和巨集函數實現平方的功能,代碼分別如下:

int square(int x) {
    return x * x;
}
#define SQUARE(x) ((x)*(x))

巨集函數在編譯過程中被簡單地替換為相應的代碼片段。它沒有函數調用的開銷,可以直接插入到調用的位置,這樣可以提高代碼執行效率

這發生在預處理階段,不會進行類型檢查錯誤檢查,可能導致意外的行為或結果。例如:巨集函數中需列印字元串,而參數傳遞數字1:

#include <stdio.h>

#define PRINT2(n) printf("%s\n", n)

int main() {

    PRINT2(1);    
    return 0;
}

編譯有告警,執行文件還是生成了:

pjl@pjl-pc:~/ph$ gcc demo-3.c -o demo-3
demo-3.c: In function ‘main’:
demo-3.c:3:26: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
    3 | #define PRINT2(n) printf("%s\n", n)
      |                          ^~~~~~
......
    7 |     PRINT2(1);
      |            ~
      |            |
      |            int
demo-3.c:7:5: note: in expansion of macro ‘PRINT2’
    7 |     PRINT2(1);
      |     ^~~~~~
demo-3.c:3:28: note: format string is defined here
    3 | #define PRINT2(n) printf("%s\n", n)
      |                           ~^
      |                            |
      |                            char *
      |                           %d

但運行還是報錯:

pjl@pjl-pc:~/ph$ ./demo-3
段錯誤 (核心已轉儲)

普通函數具備了類型檢查作用域錯誤檢查等功能,可以更加安全可靠地使用。但是函數調用需要一定的開銷,涉及保存現場、跳轉等操作。例如:

#define ADD(a, b) (a + b)

int result = ADD(3, 5);

編譯器會將巨集函數展開為 (3 + 5),並直接插入到 ADD(3, 5) 的位置,避免了函數調用的開銷。

練習

題目:請問以下輸出什麼?

#include <stdio.h>

#define SQUARE(x) x * x

int main() {
    int result = SQUARE(1 + 2); 
    printf("%d\n", result);

    return 0;
}

輸出:5。

分析:

// 1 + 2 * 1 + 2
#define SQUARE(x) x * x

如果希望輸出 9 可以用括弧,就像這樣:

//(1 + 2) * (1 + 2)
#define SQUARE(x) (x) * (x)

字元串處理函數

以下幾個字元串處理函數都來自 <string.h> 庫函數。

strlen()

strlen() - 用於獲取字元串的長度,即字元串中字元的個數(不包括結尾的空字元'\0')

語法:

#include <string.h>

size_t strlen(const char *str);

示例:

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, world!";
    size_t length = strlen(str);
    // Length of the string: 13
    printf("Length of the string: %zu\n", length);

    return 0;
}

Tip: %zu只用於格式化輸出 size_t 類型的格式控制符

size_t

size_t是無符號整數類型。unsigned int 也是無符號整數,兩者還是有區別的。

size_t 被定義為足夠大以容納系統中最大可能的對象大小的無符號整數類型,可以處理比 unsigned int更大的值。

在涉及到記憶體分配、數組索引、迴圈迭代等需要表示大小的場景中,建議使用size_t類型,以保證代碼的可移植性和相容性。儘管許多編譯器將size_t 定義為 unsigned int,但不依賴於它與unsigned int之間的精確關係是一個好的編程實踐。

strcpy()

strcpy - 將源字元串(src)複製到目標字元串(dest)中,包括字元串的結束符\0。語法:

char *strcpy(char *dest, const char *src);

示例:

#include <stdio.h>
#include <string.h>

int main() {
    char source[] = "Hello, world!";
    char destination[20];
    strcpy(destination, source);
    // Destination: Hello, world!
    printf("Destination: %s\n", destination);

    return 0;
}

比如destination之前有字元串,而且比source要長,你說最後輸出什麼?

char source[] = "Hello, world!";
char destination[20] = "world, Hello!XXXXXXX";
strcpy(destination, source);

輸出不變。source 拷貝的時候會將結束符\0也複製到目標,destination 最後是Hello, world!\0XXXXXX。如果不需要拷貝結束符,可以使用 strncpy()

strncpy()

strncpy - 將源字元串的指定長度複製到目標字元串中。比如不拷貝源字元的結束符:

示例:

#include <stdio.h>
#include <string.h>

int main() {
    char source[] = "Hello, world!";
    char destination[20] = "world, Hello!XXXXXXX";
    
    // 將源字元串的指定長度複製到目標字元串中,不要source的結束符
    strncpy(destination, source, sizeof(source)-1);
    // Destination: Hello, world!XXXXXXX
    printf("Destination: %s\n", destination);

    return 0;
}

最後輸出:Destination: Hello, world!XXXXXXX

strcat()

strcat - 將源字元串(src)連接到目標字元串(dest)的末尾,形成一個新的字元串。語法:

char *strcat(char *dest, const char *src);

示例:

#include <stdio.h>
#include <string.h>

int main() {
    char destination[20] = "Hello";
    char source[] = ", world!";
    
    strcat(destination, source);
    // Destination: Hello, world!
    printf("Destination: %s\n", destination);

    return 0;
}
strncat()

strncat - 將源字元串連接到目標字元串的末尾,並限制連接的字元數量。

示例:

#include <stdio.h>
#include <string.h>

int main() {
    char destination[20] = "Hello";
    char source[] = ", world!";
    
    strncat(destination, source, 3);
    // Destination: Hello, w
    printf("Destination: %s\n", destination);

    return 0;
}

strcmp()

strcmp - 用於比較兩個字元串的大小。

  • 字元串的比較是按照字典順序進行的,根據每個字元的 ASCII 值進行比較。
  • 比如 apple 和 applea比較,第一次是 a 等於 a,繼續比較,直到第六次 \0 和 a 比較,\0 的 ASCII 是0,而a 是97(可列印字元的ASCII值通常位於32-126之間),所以 applea 更大
  • 大小寫敏感。例如 A 的 ASCII 是 65。

例如:比較字元串 str1 和字元串 str2 的大小

  • 如果 str1 小於 str2,則返回一個負整數(通常是 -1)。
  • 如果 str1 大於 str2,則返回一個正整數(通常是 1)。
  • 如果 str1 等於 str2,則返回 0。

示例:

#include <stdio.h>
#include <string.h>

int main() {
    char str1[] = "apple";
    char str2[] = "applea";

    int result = strcmp(str1, str2);

    if (result < 0) {
        printf("str1 is less than str2\n");
    } else if (result > 0) {
        printf("str1 is greater than str2\n");
    } else {
        printf("str1 is equal to str2\n");
    }

    return 0;
}

輸出:str1 is less than str2

strncmp()

strncmp - 比較兩個字元串的前n個字元是否相等

示例:

#include <stdio.h>
#include <string.h>

int main() {
    char str1[] = "apple";
    char str2[] = "applea";

    // int result = strcmp(str1, str2);
    int result = strncmp(str1, str2, strlen(str1));

    if (result < 0) {
        printf("str1 is less than str2\n");
    } else if (result > 0) {
        printf("str1 is greater than str2\n");
    } else {
        printf("str1 is equal to str2\n");
    }

    
    return 0;
}

輸出:str1 is equal to str2

strchr()

strchr - 在一個字元串中查找指定字元第一次出現的位置。語法:

// str是要搜索的字元串;
// c是要查找的字元。
char* strchr(const char* str, int c);

函數返回值:

  • 如果找到指定字元,則返回該字元在字元串中的地址(指針)。
  • 如果未找到指定字元,則返回NULL。

Tip:可以通過地址相減返回字元在字元串中出現的索引值。請看示例:

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, world!";
    char* result = strchr(str, 'o');
    
    if (result != NULL) {
        // 返回字元'o'的位置,並輸出字元 'o' 到結尾的字元串
        printf("找到了字元'o',位置為:%s\n", result);
        // 地址相減,返回字元第一次出現的索引
        printf("找到了字元'o',位置為:%ld\n", result - str);
    }
    else {
        printf("未找到字元'o'\n");
    }
    
    return 0;
}

輸出:

開始運行...

找到了字元'o',位置為:o, world!
找到了字元'o',位置為:4

運行結束。
strrchr

strrchr - 相對strchr()逆序查找。

修改上述示例(strchr)一行代碼:

- char* result = strchr(str, 'o');
+ char* result = strrchr(str, 'o');

運行:

開始運行...

找到了字元'o',位置為:orld!
找到了字元'o',位置為:8

運行結束。

strstr

strstr - 用於在一個字元串中查找指定子字元串的第一次出現位置。語法:

char* strstr(const char* str1, const char* str2);

示例:

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, World!";
    char *subStr = "World";
    char *result = strstr(str, subStr);

    if (result != NULL) {
        printf("找到子字元串:%s\n", result);
    } else {
        printf("未找到子字元串。\n");
    }

    return 0;
}

關鍵字

C 語言有如下關鍵字:

關鍵字 描述 關鍵字 描述
auto 聲明自動變數 enum 聲明枚舉類型
break 跳出當前迴圈或開關語句 extern 聲明外部變數或函數
case 開關語句分支標簽 float 聲明單精度浮點型變數或函數返回值類型
char 聲明字元型變數或函數返回值類型 for 迴圈語句
const 聲明只讀變數 goto 無條件跳轉語句
continue 結束當前迴圈的迭代,並開始下一次迭代 if 條件語句
default 開關語句的預設分支 int 聲明整型變數或函數返回值類型
do 迴圈語句的迴圈體 long 聲明長整型變數或函數返回值類型
double 聲明雙精度浮點型變數或函數返回值類型 register 聲明寄存器變數
else 條件語句中否定條件的執行體 return 從函數返回值
short 聲明短整型變數或函數返回值類型 signed 聲明有符號數類型
sizeof 獲取某個數據類型或變數的大小 static 聲明靜態變數
struct 聲明結構體類型 switch 開關語句
typedef 聲明類型別名 union 聲明聯合體類型
unsigned 聲明無符號數類型 void 聲明無類型
volatile 說明變數可以被意外修改,應立即從記憶體中讀取或寫入而不進行優化 while 迴圈語句

重點說一下:static、const(已講過)、extern。

auto

在C語言中,auto 關鍵字並不是必需的,因為所有在函數內部聲明的變數預設都是自動變數。所以在實際編碼中,很少使用 auto 關鍵字進行變數聲明

#include <stdio.h>

int main() {
    auto int x = 10; // 等於 int x = 10;
    
    printf("The value of x is: %d\n", x); // 輸出:The value of x is: 10
    
    return 0;
}

在現代的C語言標準中(C99及以上),auto 關鍵字的使用已經不常見,並且很少被推薦使用,因為它已經成為了預設行為

register

比如 for(int i = 0; i< 1000; i++),每次i都會自增1,如果編譯器沒有任何優化,有可能會導致寄存器記憶體之間的數據交互發生一千次。如果將 i 聲明成寄存器變數(register int count;),可能就無需交互這麼多次。但這也只是給編譯器提供一個建議,指示它將變數存儲在寄存器中。實際上,編譯器可以選擇忽略這個建議,根據自身的優化策略和限制來決定是否將變數存儲在寄存器中。

Tip: 寄存器是不能被直接取地址。C 語言標準已經從 C99 開始將 register 關鍵字標記為過時(deprecated)

extern

extern - 用於聲明變數或函數的外部鏈接性。

通俗點說,比如我在b.c中定義了一個方法,在另一個文件中想使用,無需重覆編寫,通過 extern 聲明後可直接使用。編譯時需要將多個文件一起編譯成可執行文件。

定義b.c和main.c兩個文件:

  • b.c 中通過 extern int number 聲明 number 變數在外部已定義,不會分配記憶體空間
  • main.c 先聲明 show() 函數已在外部定義,然後使用
  • 最後通過 gcc 將這兩個文件編譯成 main 可執行函數

完整代碼如下:

b.c:

#include <stdio.h>
extern int number;  // 聲明外部變數 number 已存在。不會分配記憶體空間

void show() {
    printf("x = %d\n", number);  // 使用外部變數 number
}

main.c:

#include <stdio.h>

extern void show();  // 聲明函數 show 的存在

// 全局變數
int number = 101;
int main() {
    show();  // 調用 b.c 中的函數,列印外部變數 number
    return 0;
}

兩兩個文件一起編譯,運行輸出 x = 101

pjl@pjl-pc:~/$ gcc main.c b.c -o main && ./main
x = 101

static

static 有3個作用:

  • static int number = 101;, 指明 number 只能在本文件中使用,其他文件即使使用了 extern 也不能訪問
  • static void show(), 指明 show 只能在本文件中使用,其他文件即使使用了 extern 也不能訪問
  • static 修飾局部變數,會改變變數的聲明周期,直到程式結束才釋放

通過三個示例一一說明。

:在 extern 示例基礎上進行。

示例1:修改 main.c:

- int number = 101;
+ static int number = 101;

編譯報錯如下:

pjl@pjl-pc:~/$ gcc main.c b.c -o main
/usr/bin/ld: /tmp/ccEOKXoI.o: in function `show':
b.c:(.text+0xa): undefined reference to `number'
collect2: error: ld returned 1 exit status

示例2:修改 b.c:

- void show() {
+ static void show() {

編譯報錯:

pjl@pjl-pc:~/$ gcc main.c b.c -o main
/usr/bin/ld: /tmp/cc8XfhVS.o: in function `main':
main.c:(.text+0xe): undefined reference to `show'
collect2: error: ld returned 1 exit status

示例3:請問下麵這段代碼輸出什麼?

#include <stdio.h>
void show(); 

void fn1(){
    int i = 1;
    printf("%d\n", ++i);
}

int main() {
    for(int i = 0; i < 3; i++){
        fn1();
    }
    return 0;
}

輸出三個2。因為 fn1() 每次執行完,存放在棧中的變數 i 就被釋放。

如果給 i 增加 static 會輸出什麼:

- int i = 1;
+ static int i = 1;

輸出2 3 4

Tip:在C語言中,全局變數靜態變數都屬於靜態存儲類別,預設情況下會被分配到靜態數據區。靜態數據區在程式啟動時被分配,在程式結束時釋放。

練習

Tip:以下4個都是字元串相關的編程練習

練習1

題目:查找字元數組中字元的位置,例如 hello e,輸出1。

實現:

#include <stdio.h>
#include <string.h>

int findIndex(char array[], char target) {
    int length = strlen(array);
    for (int i = 0; i < length; i++) {
        if (array[i] == target) {
            return i;
        }
    }
    return -1; // 字元不在數組中
}

int main() {
    char array[] = "hello";
    char target = 'e';
    int index = findIndex(array, target);

    if (index != -1) {
        printf("字元 %c 的位置是:%d\n", target, index);
    } else {
        printf("字元 %c 不在數組中\n", target);
    }

    return 0;
}

輸出:字元 e 的位置是:1

練習2

題目:查找字元數組中字元的位置,例如 hello ll,輸出2。

實現:

#include <stdio.h>
#include <string.h>

int findIndex(char array[], char substring[]) {
    char *result = strstr(array, substring);
    if (result != NULL) {
        return result - array;
    }
    return -1; // 字元串不在數組中
}

int main() {
    char array[] = "hello";
    char substring[] = "ll";
    int index = findIndex(array, substring);

    if (index != -1) {
        printf("字元串 \"%s\" 的位置是:%d\n", substring, index);
    } else {
        printf("字元串 \"%s\" 不在數組中\n", substring);
    }

    return 0;
}

輸出:字元串 "ll" 的位置是:2

練習3

題目:在字元串指定位置插入字元串

實現

#include <stdio.h>
#include <string.h>

void insertString(char str[], int pos, const char insert_str[]) {
    int len1 = strlen(str);
    int len2 = strlen(insert_str);

    if (pos < 0 || pos > len1)
        return;  // 無效的插入位置
    
    // 創建臨時數組,用於存儲插入後的新字元串
    char temp[len1 + len2 + 1];
  
    // 將原字元串中插入位置之前的部分複製到臨時數組
    strncpy(temp, str, pos);
    
    // 將要插入的字元串複製到臨時數組的合適位置
    strcpy(&temp[pos], insert_str);

    // 追加原字元串中插入位置之後的部分
    strcat(temp, &str[pos]);

    // 將新字元串複製回原字元串
    strcpy(str, temp);
}

int main() {
    char original_str[100] = "Hello, world!";
    int pos = 7;
    char insert_str[100] = "beautiful ";

    insertString(original_str, pos, insert_str);
    printf("%s\n", original_str);

    return 0;
}

輸出:Hello, beautiful world!

練習4

題目:計算字元串中子串的次數,例如 "helloworldhelloworldhelloworld hello" 中 hello 出現4次

#include <stdio.h>
#include <string.h>

int countSubstringOccurrences(const char* str, const char* substring) {
    int count = 0;
    int substring_length = strlen(substring);
    const char* ptr = strstr(str, substring);

    while (ptr != NULL) {
        count++;
        ptr += substring_length;
        ptr = strstr(ptr, substring);
    }

    return count;
}

int main() {
    const char* str = "helloworldhelloworldhelloworld hello";
    const char* substring = "hello";

    int count = countSubstringOccurrences(str, substring);
    // 4
    printf("%d\n", count);

    return 0;
}
作者:彭加李
出處:https://www.cnblogs.com/pengjiali/p/17492014.html
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 使用 QCustomPlot 繪圖庫輔助開發時整理的學習筆記。本篇介紹如何使用 QCustomPlot 繪製 x-y 曲線圖,需要 x 軸數據與 y 軸數據都已知,示例中使用的 QCustomPlot 版本為 Version 2.1.1,QT 版本為 5.9.2。 ...
  • 某日二師兄參加XXX科技公司的C++工程師開發崗位第19面: > 面試官:什麼是智能指針? > > 二師兄:智能指針是C++11引入的類模板,用於管理資源,行為類似於指針,但不需要手動申請、釋放資源,所以稱為智能指針。 > > 面試官:C++11引入了哪些智能指針? > > 二師兄:三種,分別是`s ...
  • # 高階函數 ## 函數可以作為參數進行傳遞和返回值進行返回 ```Scala //傳一個a乘b 就返回一個函數,邏輯是實現兩數相乘 //傳一個a*b 返回一個函數,邏輯是實現兩數相乘 //傳一個axb 返回一個函數,邏輯是實現兩數相乘 def funTest6(str:String,fun:(St ...
  • typora-copy-images-to: upload # 頁面預覽 ## 訂單詳情 ![image-20230227071834134](https://s2.loli.net/2023/06/19/8rXsPWOn3MdlRNx.png) ![image-20230227071900964] ...
  • 緩衝池是主存儲器中的一個區域,在訪問 table 和索引數據時 InnoDB 會對其進行緩存。緩衝池允許直接從記憶體中訪問頻繁使用的數據,從而加快處理速度。在專用伺服器上,通常將高達 80% 的物理記憶體分配給緩衝池。 ...
  • > 在[上一章](https://www.yuque.com/docs/share/adb5b1e4-f3c6-46fd-ba4b-4dabce9b4f2a?# 《現代C++學習指南-類型系統》)我們探討了C++的類型系統,並提出了從低到高,又從高到低的學習思路,本文就是一篇從高到低的學習指南,希望 ...
  • ### 實踐環境 Python3.6 ### 介紹 `multiprocessing`是一個支持使用類似於線程模塊的API派生進程的包。該包同時提供本地和遠程併發,通過使用子進程而不是線程,有效地避開了全局解釋器鎖。因此,`multiprocessing`模塊允許程式員充分利用給定機器上的多個處理器 ...
  • # Manacher演算法是什麼 ~~Manacher演算法就是馬拉車。~~ Manacher演算法就是用於解決迴文子串的個數的。 # 問題引入 [P3805:【模板】manacher 演算法](https://www.luogu.com.cn/problem/P3805) # 題目大意 給出一個只由小寫英 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...