C語言-指針講解(3)

文章目錄

  • 1.字符指針變量
    • 1.1 字符指針變量類型是什么
    • 1.2字符指針變量的兩種使用方法:
    • 1.3字符指針筆試題講解
    • 1.3.1 代碼解剖
  • 2.數組指針變量
    • 2.1 什么是數組指針
    • 2.2 數組指針變量是什么?
      • 2.2.3 數組指針變量的舉例
    • 2.3數組指針和指針數組的區別是什么?
      • 2.3.1 數組指針和指針數組區別舉例
    • 2.4 數組指針變量是怎么初始化
  • 3.二維數組傳參的本質
  • 4.函數指針變量
    • 4.1 函數指針變量的創建
      • 4.1.1什么是函數指針變量呢?
    • 4.2 函數指針變量的使用
    • 4.3 兩段有趣的代碼
    • 4.4. typedef關鍵字
      • 4.4.1 typedef關鍵字是什么?
      • 4.4.2 typedef 關鍵字用法舉例
        • 4.4.2.1 舉例1
        • 4.4.2.1 舉例2
        • 4.4.2.1 舉例3
        • 4.4.2.1 舉例4
  • 5.函數指針數組
    • 5.1 什么是函數指針數組?
      • 5.2 如何定義函數指針數組?
      • 5.3 函數指針數組舉例
  • 6.轉移表
    • 6.1.1用函數指針數組作為轉移表實現計算器的代碼邏輯
    • 6.1.2用函數指針作為轉移表實現計算器的代碼邏輯

在上一篇博客中:
C語言-指針講解(2)
我們更為深層地給大家介紹了指針的其他基礎用法
讓下面我們來回顧一下講了什么吧:
1.野指針指向的位置是不可知的。我們只有做到:

  • 對指針初始化
  • 小心數組越界
  • 當指針變量不再使用時,應及時置NULL,指針使用之前檢查有效性。

才能在寫代碼避免出現野指針的情況。
2.assert.h頭文件定義了宏assert(),用于在運行中確保程序符合指定程序,如果不符合,就報錯運行運行。這個宏常常被稱為“斷言”。
3.學習指針的用處以及指針傳址調用的用法
4.除了sizeof(數組名)和&數組名,其他情況下數組名都是數組首元素的地址。
5.二級指針是存放一級指針的指針,二級指針是存放一級指針的地址。二級指針的相關運算。
6.存放指針的則稱作指針數組,指針數組每個元素都是用來存放地址的。
7.指針數組模擬二維數組的實例



那么這次博主會給大家介紹指針進階的地方,具體內容看下圖所示:



在這里插入圖片描述

1.字符指針變量

1.1 字符指針變量類型是什么

我們知道,字符變量類型是char。
那同理,字符指針變量類型是char*。

1.2字符指針變量的兩種使用方法:

int main()
{char ch = 'w';char *pc = &ch;//用指針變量pc來接收ch變量的地址*pc = 'w';//通過對指針變量pc進行解引用操作訪問到ch變量的值return 0;
}

還有一種使用方法:

int main()
{const char* pstr = "hello bit.";//這里是把一個字符串放到pstr指針變量里了嗎?printf("%s\n", pstr);return 0;
}

這里需要注意的是:
這行代碼:const char* pstr = "hello bit."很容易讓同學以為是把字符串hello bit.放到字符指針pstr里了,但其實這是不對的。它本質上是把字符串hello bit.首字符的地址放到了pstr中。
如下圖所示:
在這里插入圖片描述
通過此圖,我們更能直觀地看到上面代碼的意思實際上是把一個字符串的首字符h的地址存放到指針變量pstr中。


1.3字符指針筆試題講解

下面來自一道《劍指offer》關于字符串相關的筆試題,我們來學習一下。

#include <stdio.h>
int main()
{char str1[] = "hello bit.";char str2[] = "hello bit.";const char *str3 = "hello bit.";const char *str4 = "hello bit.";if(str1==str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if(str3==str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}

大家不妨看看這個代碼運行結果是什么,輸出的是哪兩條語句?
在這里插入圖片描述

我們不妨看一下vs的運行結果:
在這里插入圖片描述
看到這里,也許有同學會有疑問為什么輸出的是那兩句。接下來我們給大家仔細分析一下。

1.3.1 代碼解剖

如下圖所示:
在這里插入圖片描述

  • 之前我們講過,除sizeof(數組名)和&數組名,其他情況下數組名都是數組首元素的地址。 因此這行代碼:if(str1==str2) 本質上就是兩個地址間進行比較。雖然這里的str1和str2數組存的內容是相同的,但本質上它們都是用相同的常量字符串去初始化不同的數組,這樣就會開辟出不同的內存塊。所以str1和str2不同。
  • 而這里的str3和str4指向的是同一個常量字符串。通常C/C++會把常量字符串存儲到單獨的一個內存區域, 所以當幾個指針指向同一個字符串的時候,它們實際上會指向同一塊內存。所以str3和str4是相同的。


2.數組指針變量

2.1 什么是數組指針

數組指針,顧名思義它就是一種指針,里面存放的是數組的地址。

2.2 數組指針變量是什么?

根據前面的指針介紹,我們知道:
1.整形指針變量:int * ptr,存放的是整型變量的地址,能夠指向整形數據的指針。
2.浮點型指針變量:float * pf;存放浮點型變量的地址,能夠指向浮點型數據的指針。
那數組指針變量:就是存放的是數組的地址,能夠指向數組的指針變量。

2.2.3 數組指針變量的舉例

我們來看一下,下面哪個代碼是數組指針變量?

int *p1[10];
int (*p2)[10];

大家可以先思考一下:
在這里插入圖片描述
這里的數組指針變量是這個:

int (*p)[10];

解釋如下:

p先和*結合,說明p是一個指針變量,然后它指向的是一個大小為10個整型的數組。所以p是一個指針,指向一個數組指針,叫數組指針。

可能有同學會有疑問,為什么p要和*先結合呢?
我們來看下圖所示:

在這里插入圖片描述
從圖中我們可以清晰看到,[]的優先級是比* 要高的。所以我們必須加上()來保證p先和*結合。



2.3數組指針和指針數組的區別是什么?

這兩個概念在詞語雖然很相近,但事實是兩個不同的事實。

2.3.1 數組指針和指針數組區別舉例

代碼如下:

int *a[5]int (*a)[5];

分析:**我們從上面代碼,和剛剛給出操作符優先級的圖可以得知,它們之前相差一個括號,根據優先級的關系(()>[]>*),如果不加括號,a會先與[]結合,加了括號,a則會和 *結合,由此可見,加括號為的是改變運算的結合順序

  • int *a[5]沒有括號,a會先與[]結合,所以它是一個數組。
  • int (*a)[5]加了括號,a會與 *結合,所以它是一個指針。

根據上面分析我們得出以下結論:

  • int * [5]是指針數組,它本質上是一個數組,數組里面存放的是指針,指針類型是int*,指向的是一個整形數組。
    int( * a)[5]是數組指針,它本質是一個指針,里面存放的是數組的地址,指向的是數組的類型是int[5]。


2.4 數組指針變量是怎么初始化

我們知道:數組指針變量是用來存放數組地址的,那如何獲取數組的地址呢,我們之前學習的&數組名,這個&數組名可以把整個數組的地址取出來。

1. int arr[10]={0};
2. &arr;//得到的是數組的地址

如果我們要存放個數組的地址,就得存放在數組指針變量中,
代碼如下:

int (*p)[10] =&arr

在這里插入圖片描述
我們在調試中也能看到&arr和p的類型是完全一致的。
因此,那個數指針組類型解析如下:
在這里插入圖片描述



3.二維數組傳參的本質

有了數組指針的理解,我們就能夠講一下二維數組傳參的本質了。
過去我們有一個二維數組傳參給一個函數的時候,我們是這么寫的:

#include <stdio.h>
void test(int a[3][5], int r, int c)
{int i = 0;int j = 0;for(i=0; i<r; i++){for(j=0; j<c; j++){printf("%d ", a[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};test(arr, 3, 5);return 0;
}

這里實參是二維數組,形參也可以寫成二維數組的形式,那還有什么其他的寫法呢?

首先我們可以再次理解一下二維數組:二維數組起始可以看做每個元素是一維數組的數組,也就是二維數組的每個元素是一個一維數組。那么二維數組的首元素就是第一行,是個一維數組。

如下圖所示:
在這里插入圖片描述

所以,我們根據數組名是數組首元素的地址這個規則,二維數組的數組名表示的就是第一行的地址,是一維數組的地址。根據上面的例子,第一行的一維數組的類型就是int[5],所以第一行的地址的類型就是數組指針類型int(*)[5]。那就意味著二維數組傳參本質也是傳遞了地址,傳遞的是第一行這個一維數組的地址,那么形參也是可以寫成指針形式的。

代碼如下:

#include <stdio.h>
void test(int (*p)[5], int r, int c)
{int i=0;int j=0;for(i=0;i<r;i++){for(j=0;j<c;j++){printf("%d ", *(*(p+i)+j));}printf("\n");}
}
int main()
{int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};test(arr, 3, 5);return 0;
}

可能有同學對上述代碼不理解什么意思?

printf("%d ", *(*(p+i)+j));

我們就來解釋一下吧~

  • 我們知道,二維數組的數組名是第一行數組的地址。至于我們為什么要+j?
  • 這是因為我們要拿到二維數組中每個元素的地址,而如果說不加j的話,我們總是拿到都是二維數組所在那行的第一個元素地址,這顯然是不合理的。
  • 另外,我們看到外層還有一個*,因為是( * (p+i)+j)只是拿到的是每個元素的地址,但我們目的是要拿到它每個元素的值,因此我們還要再對它進行解引用操作。也就是在最外層的括號左邊,再加個 * 才能獲取二維數組每個元素的值

總結:二維數組傳參,形參的部分可以寫成數組,也可以寫成指針形式。



4.函數指針變量

4.1 函數指針變量的創建

4.1.1什么是函數指針變量呢?

通過前面我們介紹整型指針,數組指針的時候,我們類比關系,不難的得出結論:
函數指針變量是用來存放函數地址,未來通過地址來調用函數的。

那么函數是否有地址呢?
我們不妨測試下面這幾行代碼:

#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("test: %p\n", test);printf("&test: %p\n", &test);return 0;
}

輸出結果如下:

我們可以看到vs編譯器確實打印出來了地址。
因此我們可以得出以下結論:

  • 函數是有地址的。
  • 函數名就是函數的地址
  • 可以通過&函數名的方式獲得函數的地址。

但如果我們要把函數的地址存放起來,那應該怎么做呢?

我們應該創建函數指針變量來存放函數的地址。

其實函數指針變量的寫法其實和數組指針非常類似。
代碼如下所示:

void test()
{printf("hehe\n");
}void (*pf1)() = &test;
void (*pf2)()= test;int Add(int x, int y)
{return x+y;
}int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;//x和y寫上或者省略都是可以的

函數指針類型解析:
在這里插入圖片描述

4.2 函數指針變量的使用

這里我們來給大家演示一下函數指針指向的函數的例子。

在這里插入圖片描述

	include <stdio.h>int Add(int x, int y){return x+y;}int main(){int(*pf3)(int, int) = Add;printf("%d\n", (*pf3)(2, 3));printf("%d\n", pf3(3, 5));return 0;}

在這里插入圖片描述

4.3 兩段有趣的代碼

接下來有兩段有趣的函數指針的代碼,給大家講一下代碼里面的邏輯~

代碼1:

(*(void (*)())0)();

這個代碼的含義可能很多人都無法理解,但沒事,接下來我將把代碼拆解來給大家講解一下。
我們先看下圖:
在這里插入圖片描述
解剖代碼1

  • 從上圖,我們知道:它其實把0這個整數強制轉換為(void (*)()這種函數指針類型,想讓0當做這種函數的地址。

當我們分析到這樣子,這個代碼的意思也就一目了然了。

它這個代碼1本質的意思就是:
調用0地址處的函數,函數的參數為無參,返回的類型為void。

代碼2:

void (*signal(int , void(*)(int)))(int);

我們繼續來分析一下這個代碼,看看它是什么意思。
同樣地,我們可以把這個代碼拆解成這樣,方便大家可以理解。
在這里插入圖片描述
解剖代碼2:

從上面我們的代碼分析圖可以得知:

  • 聲明的signal函數有2個參數,第一個參數是int類型的,第二個參數是函數指針類型的,該函數指向的是int類型,返回的類型是void。
  • signal函數的返回類型也是一個函數指針,該函數指針向的函數,參數是int,返回的類型也是void。

另外,這兩段代碼均出自:《C陷阱和缺陷》這本書,大家有興趣的話可以找來看看~



4.4. typedef關鍵字

4.4.1 typedef關鍵字是什么?

typedef關鍵字,顧名思義,就是用來類型重名名的。可以將復雜的類型,簡單化。

4.4.2 typedef 關鍵字用法舉例

4.4.2.1 舉例1

1.比如,我們覺得數據類型 unsingned int寫起來不方便,如果寫成uint就方便多了,那我們可以怎么寫呢?
具體如下圖所示:
在這里插入圖片描述

4.4.2.1 舉例2

如果是指針類型,能否重名呢?其實也是可以的,比如:將double*重命名為ptr,要怎么寫呢?
具體寫法如下所示:
在這里插入圖片描述

4.4.2.1 舉例3

那我們能否對數組指針和函數指針進行重命名呢,這個也是可以的。但是這個跟之前的重名稍微有點區別:
如果我們數組類型是int(*)[10],要重命名為tmp,那我們可以這樣寫:

typedef int(*tmp)[10];//新的類型名必須在*右邊,這里就是將int(*)[10]類型重命名為tmp
int main() {int(*arr)[10];tmp v;return 0;
}

如下圖所示:
在這里插入圖片描述

同時,我們通過vs調試,發現變量v也是數組指針int(*)[10]類型。

4.4.2.1 舉例4

同理:函數指針類型的重命名也是一樣的,比如,將void(*)(int)類型重命名為ptr_t,就可以這樣寫:

1 typedef void(*pfr_t)(int);//新的類型名必須在*的右邊

如果說,我們要簡化之前的這個代碼,我們該怎么寫呢?

void (*signal(int,void(*)(int)))(int);

如下圖所示:在這里插入圖片描述

從圖中,我們發現當我們把函數指針類型重命名為parr_t,vs編譯器是沒有發生任何報錯的。



5.函數指針數組

我們已經到知道:

數組是一個存放相同類型數據的存儲空間,并且我們之前也學習了指針數組。
比如:

int *arr[10];
//數組的每個元素是int*

5.1 什么是函數指針數組?

如果我們把函數的地址存到一個數組中,那這個數組就叫函數指針數組。


5.2 如何定義函數指針數組?

我們來看下這行代碼:

int (*parr1[3])();

代碼分析:

由于我們前面介紹過,[]的優先級比*要高,因此,[]會先和parr1結合,說明parr1是數組。那數組的內容是什么呢?答案是:int(*)();

5.3 函數指針數組舉例

如下圖所示:
在這里插入圖片描述
代碼分析:

從圖中我們發現,由于函數指針p1和p2都是相同的類型,且返回的數據類型為int。因此我們可以創建一個函數指針數組來把兩個函數指針的地址存進去。



6.轉移表

我們前面介紹了函數指針數組和函數指針的概念和基本用法。
那它們的用途是什么呢:轉移表
接下來我將介紹用函數指針函數指針數組作為轉移表實現計算器的代碼邏輯:

一般來說,我們實現計算器的邏輯是這么寫的。

#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");printf("請選擇:");scanf("%d", &input);switch (input){case 1:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("選擇錯誤\n");break;}} 		while (input);return 0;
}

雖然這樣這個計算器代碼這么寫也是可以的。
但是我認為這個代碼有以下不足的:

  • switch語句中case子語句很多代碼都是相似的,這樣會顯得有點冗余。
  • 如果這個計算器要增加更多的計算功能,比如:
    a%b,a&b,a^b,a|b。那這樣的話就Switch的case子語句就會寫得更多,這樣整個代碼邏輯就會變得復雜了。

那如何優化這個計算器的代碼邏輯呢?

6.1.1用函數指針數組作為轉移表實現計算器的代碼邏輯

這個代碼我們可以改進成這樣:

#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}void menu() {printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");
}int main()
{int input = 0;int(*ptr[5])(int x,int y) = {0,add,sub,mul,div};//轉移表//至于這里為什么函數指針數組要寫5個,主要是因為數組的下標是從0開始的,而這里存的add~div函數地址最好用下標1-4來表示,這樣可以方便后續計算。do{menu();printf("請選擇:");scanf("%d", &input);if (input >= 1 && input <= 4) {int x = 0;int y = 0;int ret = 0;printf("請輸入兩個操作數:");scanf("%d %d", &x, &y);ret = (*ptr[input])(x, y);printf("%d\n", ret);}else if (input == 0) {printf("退出計算器。\n");}else {printf("輸入有誤,請重新輸入:\n");}} while (input);return 0;
}

分析代碼

從上面這行代碼:

int(*ptr[5])(int x,int y) = {0,add,sub,mul,div};

我們用函數指針數組ptr[5]來把add,sub,mul,div這四個函數的地址分別存進函數指針數組里面去。這里就相當于一個跳板,也就是我們說的轉移表,后續根據用戶輸入input的值,通過函數數組指針ptr下標的值來調用所對應的函數。而那個變量x和y是調用函數時所傳的參數。

6.1.2用函數指針作為轉移表實現計算器的代碼邏輯

代碼如下:

#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}void menu() {printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");
}void calc(int(*ptr)(int x, int y)) {int x = 0;int y = 0;int ret = 0;printf("請輸入兩個操作數:");scanf("%d %d", &x, &y);ret = (*ptr)(x, y);printf("%d\n", ret);
}int main()
{int input = 0;do{menu();printf("請選擇>:");scanf("%d", &input);switch (input) {case 1:calc(add);break;case 2:calc(sub);break;case 3:calc(mul);break;case 4:calc(div);break;case 0:printf("退出計算器。\n");break;default: {printf("輸入有誤,請重新輸入:\n");}}} while (input);return 0;
}

分析代碼:

  • 從上述代碼中,我們是封裝了一個calc函數。根據用戶輸入input的值,進到switch所對應的case的子語句中,并把對應的函數地址傳給calc函數。然后在calc函數它的參數是函數指針類型,返回類型的是int。由于我們只用在calc函數內部進行打印,因此只用在calc函數中左邊寫上個void類型即可。
  • 接著進入calc函數內部,根據用戶輸入變量x和y的值,將函數指針ptr的地址和參數x,y的值調用所對應的函數,并把最終計算的結果返回到ret,從而實現計算出兩個操作數的結果出來。


**好了,今天的指針講解3到這就結束了。 **
在這里插入圖片描述
**如果覺得博主講得不錯的話,歡迎大家支持一下博主!!謝謝大家~ **

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

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

相關文章

npm ERR! node-sass@4.13.0 postinstall: `node scripts/build.js`

npm ERR! node-sass4.13.0 postinstall: node scripts/build.js npm config set sass_binary_sitehttps://npm.taobao.org/mirrors/node-sass npm install npm run dev Microsoft Windows [版本 10.0.19045.2965] (c) Microsoft Corporation。保留所有權利。C:\Users\Administr…

4.操作系統常見面試題(2)

3.4 虛擬內存 直接使?物理內存會產??些問題 1. 內存空間利?率的問題&#xff1a;各個進程對內存的使?會導致內存碎?化&#xff0c;當要? malloc 分配?塊很?的內存空間時&#xff0c;可能會出現雖然有?夠多的空閑物理內存&#xff0c;卻沒有?夠?的連續空閑內存這種…

手動實現 git 的 git diff 功能

這是 git diff 后的效果&#xff0c;感覺挺簡單的&#xff0c;不就是 比較新舊版本&#xff0c;新增了就用 "" 顯示新加一行&#xff0c;刪除了就用 "-" 顯示刪除一行&#xff0c;修改了一行就用 "-"、"" 顯示將舊版本中的該行干掉了并…

騰訊云AMD服務器標準型SA5實例AMD EPYC Bergamo處理器

騰訊云服務器標準型SA5實例是最新一代的標準型實例&#xff0c;CPU采用AMD EPYC? Bergamo全新處理器&#xff0c;采用最新DDR5內存&#xff0c;默認網絡優化&#xff0c;最高內網收發能力達4500萬pps。騰訊云百科txybk.com分享騰訊云標準型SA5云服務器CPU、內存、網絡、性能、…

Python 忽略warning警告錯誤 + 跳過報錯繼續執行程序

如何主動產生warning錯誤: import warnings def fxn(): warnings.warn("deprecated", DeprecationWarning) with warnings.catch_warnings(): warnings.simplefilter("ignore") fxn() 那么如何來控制警告錯誤的輸出呢? import warnings warnings.fi…

Modown主題v8.12 安裝教程和主題下載

親測」Modown主題v8.12學習版 上傳好主題選擇該主題就好了設置 設置好的首頁 內容頁&#xff1a; WordPress主題Modown和WordPress插件Erphpdown想必正在使用WordPress程序建站的站長都非常熟悉&#xff0c;因為這兩款應用在WordPress站長圈子里還是比較知名的&#xff0c;所以…

計算機畢業設計 基于SpringBoot的無人智慧超市管理系統的設計與實現 Java實戰項目 附源碼+文檔+視頻講解+答疑

博主介紹&#xff1a;?從事軟件開發10年之余&#xff0c;專注于Java技術領域、Python人工智能及數據挖掘、小程序項目開發和Android項目開發等。CSDN、掘金、華為云、InfoQ、阿里云等平臺優質作者? &#x1f345;文末獲取源碼聯系&#x1f345; &#x1f447;&#x1f3fb; 精…

GoLang Filepath.Walk遍歷優化

原生標準庫在文件量過大時效率和內存均表現不好 1400萬文件遍歷Filepath.Walk 1400萬文件重寫直接調用windows api并處理細節 結論 1400萬文件遍歷時對比 對比條目filepath.walkwindows api并觸發黑科技運行時間710秒22秒內存占用480M38M 關鍵代碼 //超級快的文件遍歷 fun…

【HuggingFace Transformer庫學習筆記】基礎組件學習:pipeline

一、Transformer基礎知識 pip install transformers datasets evaluate peft accelerate gradio optimum sentencepiece pip install jupyterlab scikit-learn pandas matplotlib tensorboard nltk rouge在host文件里添加途中信息&#xff0c;可以避免運行代碼下載模型時候報錯…

企業計算機服務器中了360勒索病毒怎么辦,360勒索病毒解密文件恢復

計算機技術的不斷發展&#xff0c;為企業的生產運營提供了極大便利&#xff0c;不僅提升了辦公效率&#xff0c;還促進了企業的發展。企業計算機在日常工作中一定加以防護&#xff0c;減少網絡威脅事件的產生&#xff0c;確保企業的生產生產運營。最近&#xff0c;網絡上的360后…

微信小程序富文本拓展rich-text

微信小程序富文本插件 功能介紹 支持解析<style>標簽中的全局樣式支持自定義默認的標簽樣式支持自動設置標題 若html中存在title標簽,將自動把title標簽的內容設置到頁面的標題上,并在回調bindparse中返回,可以用于轉發支持添加加載提示 可以在Parser標簽內添加加載提…

8:kotlin 類型檢查和轉換(Type checks and casts)

在運行時可以執行類型檢查以檢查對象的類型。類型轉換將對象強制轉換為不同的類型 is 和 !is 可以使用is或者!is來判斷實例是不是指定的類型 fun main() {var obj : Any "cast"if (obj is String) {println(obj.length) // 4}obj 123if (obj !is String) { pr…

動態規劃 之 鋼條切割

自頂向下遞歸實現(Recursive top-down implementation) 程序CUT-ROD對等式(14.2)進行了實現&#xff0c;偽代碼如下&#xff1a; CUT-ROD(p, n)if n 0return 0q -∞for i 1 to nq max{q, p[i] CUT-ROD(p, n - i)}return q上面解決中重復對一個子結構問題重復求解了&#…

Qt無邊框窗口設置陰影

//設置窗體透明this->setAttribute(Qt::WA_TranslucentBackground, true);//設置無邊框this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);QVBoxLayout* pMainLay new QVBoxLayout(this);CLoginRealWidget* pRealWidget new …

VR全景展示,“超前點播”打開娛樂行業線上營銷門戶

如今&#xff0c;人們的生活水平正在逐步提高&#xff0c;這種提高不僅僅是體現在衣食住行上&#xff0c;更多方面是體現在大眾的娛樂活動上。我們可以看到&#xff0c;相比于過去娛樂種類的匱乏&#xff0c;現如今&#xff0c;各種娛樂活動可謂是百家爭鳴&#xff0c;例如溫泉…

目標檢測YOLO實戰應用案例100講-基于多光譜圖像融合的光伏組件故障 檢測

目錄 前言 國內外研究現狀 多光譜圖像配準研究現狀 光伏區域識別研究現狀

java學習part10 this

90-面向對象(進階)-關鍵字this調用屬性、方法、構造器_嗶哩嗶哩_bilibili 1.java的this java的this性質類似cpp的this&#xff0c; 但它是一種引用&#xff0c;所以用 this. xxx來調用。 this代表當前的類的實例&#xff0c;所以必須和某個對象結合起來使用&#xff0c;不能…

webrtc的RTCPeerConnection使用

背景&#xff1a; 平時我們很少會需要使用到點對點單獨的通訊&#xff0c;即p2p,一般都是點對服務端通訊&#xff0c;但p2p也有自己的好處&#xff0c;即通訊不經過服務端&#xff0c;從服務端角度這個省了帶寬和壓力&#xff0c;從客戶端角度&#xff0c;通訊是安全&#xff…

Javaweb之前端工程化的詳細解析

3 前端工程化 3.1 前端工程化介紹 我們目前的前端開發中&#xff0c;當我們需要使用一些資源時&#xff0c;例如&#xff1a;vue.js&#xff0c;和axios.js文件&#xff0c;都是直接再工程中導入的&#xff0c;如下圖所示&#xff1a; 但是上述開發模式存在如下問題&#xff…

git的使用:本地git下載、sshkey的添加、github倉庫創建及文件上傳

一、github創建賬號 即github注冊賬號&#xff0c;登錄github官網&#xff0c;根據提示注冊即可 github官網 二、git客戶端下載安裝 已有很多git下載安裝的博文了&#xff0c;在此就不贅述 三、sshkey的生成與添加 1、sshkey的生成以及查看 // sshkey的生成命令&#xff…