系統性學習C語言-第十六講-深入理解指針(6)

系統性學習C語言-第十六講-深入理解指針(6)

  • 1. ` sizeof ` 和 ` strlen ` 的對比
    • 1.1 ` sizeof `
    • 1.2 ` strlen `
    • 1.3 ` sizeof ` 和 ` strlen ` 的對比
  • 2. 數組和指針筆試題解析
    • 2.1 一維數組
    • 2.2 字符數組
    • 2.3 二維數組
  • 3. 指針運算筆試題解析
    • 3.1 題目1:
    • 3.2 題目2
    • 3.3 題目3
    • 3.4 題目4
    • 3.5 題目5
    • 3.6 題目6
    • 3.7 題目7

1. sizeofstrlen 的對比

1.1 sizeof

在學習操作符的時候,我們學習了 sizeofsizeof 計算變量所占內存空間大小的,單位是字節,

如果操作數是類型的話,計算的是使用類型創建的變量所占內存空間的大小。

sizeof 只關注占用內存空間的大小,不在乎內存中存放什么數據。

比如:

#include <stdio.h>
int main()
{int a = 10;printf("%d\n", sizeof(a));printf("%d\n", sizeof a);printf("%d\n", sizeof(int));return 0;
}

在這里插入圖片描述

1.2 strlen

strlen 是 C語言 庫函數,功能是求字符串長度。函數原型如下:

size_t strlen ( const char * str );

統計的是從 strlen 函數的參數 str 中這個地址開始向后,\0 之前字符串中字符的個數。

strlen 函數會?直向后找 \0 字符,直到找到為止,所以可能存在越界查找。

#include <stdio.h>
int main()
{char arr1[3] = {'a', 'b', 'c'};char arr2[] = "abc";printf("%d\n", strlen(arr1));printf("%d\n", strlen(arr2));printf("%d\n", sizeof(arr1));printf("%d\n", sizeof(arr2));return 0;
}

在這里插入圖片描述

1.3 sizeofstrlen 的對比

在這里插入圖片描述

2. 數組和指針筆試題解析

2.1 一維數組

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));

在對代碼進行分析之前我們先回憶幾個重要知識點。

  • 數組名通常代表數組首元素的地址,但是有例外。

  • sizeof(數組名) ,此時數組名代表整個數組。

  • &數組名 ,此時取出的地址為整個數組的地址。

在對上面的知識點進行回憶后,我們便可以對代碼進行分析。

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a)); //為數組名的特殊用法,代表整個數組,結果為 16
printf("%d\n",sizeof(a+0)); //數組名并未單獨放在 sizeof 內部,所以代表數組首元素,結果為 4/8
printf("%d\n",sizeof(*a)); //數組名為首元素地址,對其解引用后代表首元素,首元素類型為整形,結果為 4
printf("%d\n",sizeof(a+1));//數組首元素地址 + 1,仍為地址,結果為 4/8
printf("%d\n",sizeof(a[1]));//數組中第二個元素的字節數大小,結果為 4
printf("%d\n",sizeof(&a));//取出整個數組的地址,但仍為地址,結果為 4/8
printf("%d\n",sizeof(*&a));//先取出整個數組的地址,然后再解引用,仍然相當于直接求整個數組的字節數大小,結果為 16
printf("%d\n",sizeof(&a+1));//取出整個數組的地址然后 + 1,仍為地址,結果為 4/8
printf("%d\n",sizeof(&a[0]));//求數組第一個元素的地址的字節數大小,仍為地址,結果為 4/8 
printf("%d\n",sizeof(&a[0]+1));//相當于求第二個元素的地址字節數大小,仍為地址,結果為 4/8

在這里插入圖片描述

這里作者的運行環境為 32位,故地址的字節數為 4。

2.2 字符數組

練習 1:

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));

與上面一樣的步驟,接下來我們對代碼進行解析。

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//計算整個數組的字節數大小,為 6
printf("%d\n", sizeof(arr+0));//計算數組首元素地址的大小,為 4/8
printf("%d\n", sizeof(*arr));//計算首元素的大小,元素為字符類型,為 1
printf("%d\n", sizeof(arr[1]));//計算首元素的大小,元素為字符類型,為 1
printf("%d\n", sizeof(&arr));//取出整個數組的地址,結果仍為地址,字節數為 4/8
printf("%d\n", sizeof(&arr+1));//取出整個數組的地址,然后 + 1,相當于跳過了整個數組后的地址,仍為地址,字節數為 4/8
printf("%d\n", sizeof(&arr[0]+1));//相當于取出的是整個數組第二個元素的地址,仍為地址,字節數為 4/8

在這里插入圖片描述

練習 2:

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

解析:

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));//從首元素地址開始計算,由于 strlen 的特性,數組中并沒有存儲 \0,最終結果為隨機值
printf("%d\n", strlen(arr+0));//從首元素開始計算,與上面的解析同理,最終結果仍為隨機值
printf("%d\n", strlen(*arr));//*arr 解析出的結果為 a,a 的 ASCII值為 97,strlen 會將這個值作為地址進行訪問,最終結果為非法訪問
printf("%d\n", strlen(arr[1]));//arr[1] 解析出的結果為 b,與上面的解析同理,最終結果仍為非法訪問
printf("%d\n", strlen(&arr));//從數組的地址開始計算,結果為隨機值,與上面的解析同理
printf("%d\n", strlen(&arr+1));//從跳過整個數組的第一個地址開始計算,結果為隨機值,與上面解析同理
printf("%d\n", strlen(&arr[0]+1));//從數組的第二個元素地址開始計算,結果為隨機值,與上面解析同理

因有非法訪問,所以無法插入實機演示結果

練習 3:

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));

解析:

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//求整個數組的字節數,結果為 7
printf("%d\n", sizeof(arr+0));//求數組首元素地址的字節數,結果為 4/8
printf("%d\n", sizeof(*arr));//求首元素的字節數,元素類型為字符,結果為 1
printf("%d\n", sizeof(arr[1]));//求數組第二個元素的字節數,元素類型為字符,結果為 1
printf("%d\n", sizeof(&arr));//求整個數組地址的字節數,結果為 4/8
printf("%d\n", sizeof(&arr+1));//求跳過整個數組后第一個地址的字節數,結果為 4/8
printf("%d\n", sizeof(&arr[0]+1));//求數組第二個地址的字節數,結果為 4/8

在這里插入圖片描述

練習 4:

char arr[] = "abcdef";
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

解析:

char arr[] = "abcdef";
printf("%d\n", strlen(arr));//從首元素地址開始計算,結果為 6
printf("%d\n", strlen(arr+0));//從首元素地址開始計算,結果為 6
printf("%d\n", strlen(*arr));//*arr 地結果為 a ,對應地 ASCII值 為 97,strlen 會將 97 作為地址進行訪問,結果為非法訪問
printf("%d\n", strlen(arr[1]));//結果為非法訪問,arr[1] 結果為 b,其余解析與上面一樣
printf("%d\n", strlen(&arr));//從整個數組地地址開始計算,結果為 6
printf("%d\n", strlen(&arr+1));//從跳過整個數組地第一個地址開始計算,結果為隨機值
printf("%d\n", strlen(&arr[0]+1));//從數組地第二個元素地址開始計算,結果為 5

練習 5:

char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));

解析:

char *p = "abcdef";
printf("%d\n", sizeof(p));//計算指針 p 的大小,結果為 4/8
printf("%d\n", sizeof(p+1));//計算第二字符 b 的地址大小,結果為 4/8
printf("%d\n", sizeof(*p));//計算第一元素 a 的字節大小,結果為 1
printf("%d\n", sizeof(p[0]));//計算第一元素 a 的字節大小,結果為 1
printf("%d\n", sizeof(&p));//計算指針 p 的地址大小,結果為 4/8
printf("%d\n", sizeof(&p+1));//計算跳過指針 p 地址后的第一個地址大小,結果為 4/8
printf("%d\n", sizeof(&p[0]+1));//計算 b 的地址大小,結果為 4/8

在這里插入圖片描述

練習 6:

char *p = "abcdef";
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1));

解析:

char *p = "abcdef";
printf("%d\n", strlen(p));//從 p 開始計算,結果為 6
printf("%d\n", strlen(p+1));//從數組的第二個元素開始計算,結果為 5
printf("%d\n", strlen(*p));//*p 解析為 a ,ASCII值 為 97,strlen 會將 97 當作地址進行訪問,結果為非法訪問
printf("%d\n", strlen(p[0]));//p[0] 解析為 a,結果為非法訪問
printf("%d\n", strlen(&p));//從 p 的地址開始計算,結果為隨機值
printf("%d\n", strlen(&p+1));//從跳過 p 的地址后的第一個地址進行計算,結果為隨機值
printf("%d\n", strlen(&p[0]+1));//從數組的第二個元素的地址開始計算,結尾為 5

2.3 二維數組

int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));

解析:

int a[3][4] = {0};
printf("%d\n",sizeof(a));//計算整個 a 數組的字節數大小,結果為 48
printf("%d\n",sizeof(a[0][0]));//計算第一行第一個元素的大小,元素為整形類型,結果為 4
printf("%d\n",sizeof(a[0]));//a[0] 解析為 a數組 第一行的數組名,計算整個第一行的字節數大小,結果為 16
printf("%d\n",sizeof(a[0]+1));//a[0]+1 解析為 &a[0][1] ,計算第一行第二個元素地址的大小,結果為 4/8
printf("%d\n",sizeof(*(a[0]+1)));//*(a[0]+1) 解析為 a[0][1],計算第一行第二個元素的大小,結果為 4
printf("%d\n",sizeof(a+1));//計算 a數組 第二行地址的大小,結果為 4/8
printf("%d\n",sizeof(*(a+1)));//計算 a數組 第二行的大小,結果為 16
printf("%d\n",sizeof(&a[0]+1));//取出跳過第一行后的第一個地址,也就是第二行的地址,結果為 4/8
printf("%d\n",sizeof(*(&a[0]+1)));//取出第二行的地址然后解引用,求第二行的大小,結果為 16
printf("%d\n",sizeof(*a));// a 為首元素 a[0] 的地址,對其進行解引用表示第一行,求第一行的大小,結果為16 
printf("%d\n",sizeof(a[3]));//a 數組并沒有第四行,最終結果為報錯

到此我們再對數組名的意義進行總結:

  1. sizeof(數組名) ,這里的數組名表示整個數組,計算的是整個數組的大小。

  2. &數組名,這里的數組名表示整個數組,取出的是整個數組的地址。

  3. 除此之外所有的數組名都表示首元素的地址

3. 指針運算筆試題解析

3.1 題目1:

#include <stdio.h>
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int *ptr = (int *)(&a + 1);printf( "%d,%d", *(a + 1), *(ptr - 1));return 0;
}

解析:

int *ptr = (int *)(&a + 1);

對于指針 ptr 所指向的地址 &a + 1 代表這跳過整個 a 數組地址后的第一個地址。

所以 *(ptr - 1) 就是對指針 ptr 的前一個地址進行解引用,也就是數組中最后一個元素的地址進行解引用。

對于 *(a + 1)a + 1 表示數組中第二個元素的地址,所以 *(a + 1) 表示對第二個元素的地址進行解引用。

最終的結果為 2,5

在這里插入圖片描述

3.2 題目2

//在X86環境下 
//假設結構體的??是20個字節 
//程序輸出的結果是啥? 
struct Test
{int Num;char *pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}

解析:

要解出正確答案,我們就要清楚 指針 +1 ,會產生怎樣的操作,指針 + 1 會根據指針不同的步長,從而跳過不同的字節數,

所以對于 p + 0x1 跳過的就是結構體的字節數,結構體 Test 的字節數大小為 20 ,所以 p + 0x1 跳過的字節數大小為 20,

20 轉換為 16進制 為 0x14,所以結果為 0x100014,同樣的對于 (unsigned int*)p + 0x1 我們跳過則為 unsigned int 類型的字節數,

為 4 字節,所以最終結果為 0x100004,但是在(unsigned long)p + 0x1 p 被轉換成了無符號長整形類型,不再為指針,

所以這時的 +1 就不能再遵循指針的規則,而是遵循整形的算術規則,正常 + 1,結果為 0x100001,

對于 X86 環境下的地址顯示,32位系統在顯示地址時最多能顯示 8 位,所以我們要在結果前補上兩個 0,

最終結果為:

在這里插入圖片描述

3.3 題目3

#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };int *p;p = a[0];printf( "%d", p[0]);return 0;
}

解析:

對于這道題,我們一定要辨析好二維數組的初始化方式,題目中二維數組的初始化分組部分使用的是 () ,而并非 {}

而小括號內部使用了逗號表達式,逗號表達式返回的是表達式中最后一個值,

所以實際二維數組的初始化其實應該為這樣 int a[3][2] = { 1, 3, 5 };

所以指針 pp = a[0]; 取到的是數組第一行地址,第一行包含的元素為 1,3,所以 p[0] 取到的第一個元素為 1,

最終結果為 1 。

在這里插入圖片描述

3.4 題目4

//假設環境是x86環境,程序輸出的結果是啥? 
#include <stdio.h>
int main()
{int a[5][5];int(*p)[4];p = a;printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;
}

解析:

首先我們對于 p[4][2] 進行分析, p[4][2] 相當于 *(p + 4)[2],這里就和指針步長扯上關系了,指針 p 的類型為 int [4]

所以每次 + 1 時,跳過 4 個整形類型的字節,因為 p = a ,所以指針 p 與 數組 a 的首元素地址時一樣的,

所以 p[4][2] 實際上跳過了 a 數組的 18 個元素,而 a[4][2] 跳過了數組的 22 個元素,指針 - 指針計算出的是指針之間的元素個數,

所以結果為 -4,但對于第一個 -4 我們要化成十六進制地址的形式,我們先寫出 -4 的源碼,然后求出補碼。

源碼:10000000 00000000 00000000 00000100
反碼:11111111 11111111 11111111 11111011
補碼:11111111 11111111 11111111 11111100
補碼的十六進制:FFFFFFFC

所以最終的結果為:
在這里插入圖片描述

3.5 題目5

#include <stdio.h>
int main()
{int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int *ptr1 = (int *)(&aa + 1);int *ptr2 = (int *)(*(aa + 1));printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));return 0;
}

解析:

我們先對指針ptr1 進行解析,int *ptr1 = (int *)(&aa + 1); 其中 &aa + 1 是跳過整個 aa 數組后的第一個整形指針地址

*ptr2 = (int *)(*(aa + 1)); 其中 *(aa + 1)aa 表示數組首元素地址,為 &aa[0] ,+ 1 后指向 &aa[1]

所以指針 ptr2 實際代表數組 aa 的第二行。因為 ptr1,ptr2 指針的類型都為整形指針類型,所以 +1,-1 都只會跳過一個整形的地址

所以 *(ptr1 - 1) 是對 aa 數組的最后一個元素地址進行解引用,*(ptr2 - 1) 是對數組第一行最后一個元素地址進行解引用

所以最終的結果為:

在這里插入圖片描述

3.6 題目6

#include <stdio.h>
int main()
{char *a[] = {"work","at","alibaba"};char**pa = a;pa++;printf("%s\n", *pa);return 0;
}

解析:

我們先來分析字符指針數組 aa 的成員有三個,依次分別為 workatalibaba

因為 char**pa = a; ,所以指針 pa 指向數組 a 的首元素地址,pa++; 相當于 a[0] + 1 ,數組 a 的第一個元素為 work ,+1后

指向第二個元素 at ,所以最終的打印結果為 at

在這里插入圖片描述

3.7 題目7

#include <stdio.h>
int main()
{char *c[] = {"ENTER","NEW","POINT","FIRST"};char**cp[] = {c+3,c+2,c+1,c};char***cpp = cp;printf("%s\n", **++cpp);printf("%s\n", *--*++cpp+3);printf("%s\n", *cpp[-2]+3);printf("%s\n", cpp[-1][-1]+1);return 0;
}

解析:

這里我們先將所有結構以圖標的形式呈現出來,以便我們更好地進行觀察。
在這里插入圖片描述

 	printf("%s\n", **++cpp);

現在我們再對代碼進行分析,**++cpp ,其中 cpp 指針指向 cp 的首元素,在 ++ 后指向了 cp 的第二個元素 c + 2

所以結果為 POINT

 	printf("%s\n", *--*++cpp+3);

*--*++cpp+3++cpp 此時指向 cp 的第三個元素 c + 1 ,解引用符號的結合順序更高,先結合

再與 -- 符號進行結合,此時就變成了 *--(c + 1) + 3 ,結合后變成 *c + 3 ,此時就是對 c 數組的首元素,

ENTER 的第四個元素開始輸出,最終結果為 ER

 	printf("%s\n", *cpp[-2]+3);

此時 cpp 指針在與兩個自增符號進行結合后,已經指向了 cp 數組的第三個元素,所以 cpp[-2] 指向了 cp 數組的第一個元素,

就表示為 *cp+3,也就是從 FIRST 的第四個字符開始輸出,最終結果為 ST

 	printf("%s\n", cpp[-1][-1]+1);

此時的 cpp[-1] 代表 cp 的第二個元素,簡化為 cp[1][-1]+1 再次簡化為 *((c + 2) - 1) + 1 也就是 *(c + 1) + 1

NEW 的第二個字符開始輸出,結果為 EW

在這里插入圖片描述

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

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

相關文章

8:從USB攝像頭把聲音拿出來--ALSA大佬登場!

前言前面的章節我們從認識攝像頭開始&#xff0c;逐漸認識的YCbCr&#xff0c;并對其進行了H264的編碼以及MP4封裝。整個過程中&#xff0c;我們大致使用了V4L2和FFmpeg這兩個重量級工具&#xff0c;就像我們前面章節所講&#xff0c;V4L2只是給圖像做服務的&#xff0c;并不參…

Linux 命令:useradd

Linux useradd 命令詳細教程 useradd 是 Linux 系統中用于創建新用戶賬戶的基礎命令&#xff0c;它通過配置文件&#xff08;如 /etc/passwd、/etc/shadow&#xff09;和默認設置自動完成用戶創建流程。本文將詳細介紹其用法、參數及相關配置。資料已經分類整理好&#xff1a;h…

Pytest之收集用例規則與運行指定用例

&#x1f345; 點擊文末小卡片&#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 小伙伴們大家好呀&#xff0c;今天筆者會給大家講解一下pytest是如何收集我們寫好的用例&#xff1f;我們又有哪些方式來運行單個用例或者批量運行用例呢&#xff…

qt 使用memcpy進行內存拷貝時注意的問題

int offset sizeof(st_target_data);// 預先分配足夠空間this->featureData.resize(offsetsize);// 再執行拷貝memcpy(this->featureData.data()offset, dataa, size);注意 一定要在mencpy之前 使用resize分配足夠的空間&#xff0c;否則在方法退出時候會閃退&#xff…

微調性能趕不上提示工程怎么辦?Can Gradient Descent Simulate Prompting?——論文閱讀筆記

今天速讀一篇文章 Can Gradient Descent Simulate Prompting? 一句話總結 針對【新知識應用的場景里&#xff0c;FT效果往往追不上ICL】這個情況&#xff0c;作者引入MAML的思想↓ 內圈讓模型學習新知識形成知識FT模型&#xff1b; 外圈通過最小化ICL和知識FT模型的KL散度&…

從“直覺搶答”到“深度思考”:大模型的“慢思考”革命,思維鏈、樹、圖如何讓AI越來越像人?

注&#xff1a;此文章內容均節選自充電了么創始人&#xff0c;CEO兼CTO陳敬雷老師的新書《GPT多模態大模型與AI Agent智能體》&#xff08;跟我一起學人工智能&#xff09;【陳敬雷編著】【清華大學出版社】 GPT多模態大模型與AI Agent智能體書籍本章配套視頻課程【陳敬雷】 文…

Android系統的問題分析筆記 - Android上的調試方式 debuggerd

debuggerd 是 Android 系統中的一個重要調試工具&#xff0c;主要用于生成進程崩潰時的核心轉儲&#xff08;core dump&#xff09;和調試信息&#xff08;如堆棧跟蹤&#xff09;。以下是關于 debuggerd 的詳細說明&#xff1a; 1. 基本功能 崩潰分析&#xff1a;當 Native 進…

python 雙下劃線開頭函數

在 Python 里&#xff0c;雙下劃線開頭的函數&#xff08;準確地說是方法&#xff09;有著特殊的用途和意義。下面為你詳細介紹相關內容&#xff1a; 1. 類的特殊方法&#xff08;魔術方法&#xff09; 以雙下劃線開頭和結尾的方法&#xff0c;被稱為特殊方法或者魔術方法&…

VyOS起步指南:用Docker快速搭建網絡實驗環境

文章目錄1. VyOS是什么&#xff1f;為什么選擇它&#xff1f;2. 五分鐘快速部署&#xff1a;Docker方案3. 進入容器&#xff1a;初探VyOS世界4. 核心操作&#xff1a;像開發者一樣思考5. 踩坑提醒&#xff1a;新手常見問題6. 結語&#xff1a;網絡即代碼的未來1. VyOS是什么&am…

動態規劃理論基礎,LeetCode 509. 斐波那契數 LeetCode 70. 爬樓梯 LeetCode 746. 使用最小花費爬樓梯

動態規劃理論基礎動態規劃&#xff0c;英文&#xff1a;Dynamic Programming&#xff0c;簡稱DP&#xff0c;如果某一問題有很多重疊子問題&#xff0c;使用動態規劃是最有效的。所以動態規劃中每一個狀態一定是由上一個狀態推導出來的&#xff0c;這一點就區分于貪心&#xff…

暑期自學嵌入式——Day02(C語言階段)

點關注不迷路喲。你的點贊、收藏&#xff0c;一鍵三連&#xff0c;是我持續更新的動力喲&#xff01;&#xff01;&#xff01; 主頁&#xff1a; 一位搞嵌入式的 genius-CSDN博客https://blog.csdn.net/m0_73589512?spm1000.2115.3001.5343 目錄 Day02→數據類型&#xf…

如何單獨安裝設置包域名

前言 在 npm 中&#xff0c;直接通過 package-lock.json 無法單獨設置包的安裝地址&#xff0c;因為該文件是自動生成的依賴關系鎖定文件。但你可以通過以下方法間接實現&#xff1a; 一、在 package.json 中指定包來源&#xff08;推薦&#xff09; 在 package.json 的 depend…

存儲過程探秘:數據庫編程的藝術

文章目錄存儲過程語法格式BEGIN...END語句塊DECLARE&#xff08;聲明局部變量&#xff09;流控制語句if函數批處理操作測試2測試3存儲過程與函數的關系存儲過程 MYSQL的存儲過程是一組預處理的SQL語句&#xff0c;可以像函數一樣在數據庫中進行存儲和調用。 它們允許在數據庫…

非阻塞寫入核心:asyncio.StreamWriter 的流量控制與數據推送之道

在 asyncio 的異步編程框架中&#xff0c;如果說 asyncio.StreamReader 是你異步應用的數據輸入管道&#xff0c;那么 asyncio.StreamWriter 就是你異步應用的數據輸出管道。它是一個至關重要的組件&#xff0c;讓你能夠方便、高效且非阻塞地向連接的另一端&#xff08;如 TCP …

控制臺打開mysql服務報錯解決辦法

控制臺打開mysql服務報錯解決辦法這個MySQL錯誤表示訪問被拒絕&#xff0c;通常是因為沒有提供正確的用戶名和密碼。以下是幾種解決方法&#xff1a; 方法1&#xff1a;指定用戶名和密碼連接 mysql -u root -p然后輸入root用戶的密碼。 方法2&#xff1a;如果忘記了root密碼&am…

Unsloth 實戰:DeepSeek-R1 模型高效微調指南(下篇)

食用指南 本系列因篇幅原因拆分為上下兩篇&#xff1a; 上篇以基礎環境搭建為主&#xff0c;介紹了 Unsloth 框架、基座模型下載、導入基座模型、數據集下載/加載/清洗、SwanLab 平臺賬號注冊。 下篇&#xff08;本文&#xff09;以實戰微調為主&#xff0c;介紹預訓練、全量…

Ubuntu安裝Jenkins

Ubuntu安裝Jenkins方法1&#xff1a;使用官方的Jenkins倉庫1. 添加Jenkins倉庫2. 更新軟件包列表3. 安裝Jenkins4. 啟動Jenkins服務5. 設置Jenkins開機啟動6. 查找初始管理員密碼7. 訪問Jenkins方法2&#xff1a;使用Snap包&#xff08;適用于較新的Ubuntu版本&#xff09;1. 安…

ubuntu22.04下配置qt5.15.17開發環境

自從qt5.15版本開始&#xff0c;不再提供免費的離線安裝包&#xff0c;只能通過源碼自行編譯。剛好最近需要在ubuntu22.04下配置qt開發環境&#xff0c;于是寫篇文章記錄配置的過程。 其實一開始是想配置qt5.15.2的&#xff0c;但是在編譯配置參數這一步驟中出現如下報錯 em…

S7-1200 與 S7-300 CPS7-400 CP UDP 通信 Step7 項目編程

S7-1200 CPU 與S7-300 CP STEP7 UDP通信S7-1200 與 S7-300 CP 之間的以太網通信可以通過 UDP 協議來實現&#xff0c;使用的通信指令是在S7-1200 CPU 側調用通信-開放式用戶通信TSEND_C&#xff0c;TRCV_C指令或TCON&#xff0c;TDISCON&#xff0c;TUSEND&#xff0c;TURCV 指…

基于YOLOv11的無人機目標檢測實戰(Windows環境)

1. 環境搭建 1.1 硬件與操作系統 操作系統&#xff1a;Windows 11 CPU&#xff1a;Intel i7-9700 GPU&#xff1a;NVIDIA RTX 2080&#xff08;8GB顯存&#xff09; 1.2 安裝CUDA和cuDNN 由于YOLOv11依賴PyTorch的GPU加速&#xff0c;需要安裝CUDA和cuDNN&#xff1a; 安…