主頁 > 後端開發 > 關于指標、陣列、字串的恩怨,這里有你想知道的一切

關于指標、陣列、字串的恩怨,這里有你想知道的一切

2023-03-25 07:39:36 後端開發

關于指標、陣列、字串的恩怨,這里有你想知道的一切

目錄
  • 關于指標、陣列、字串的恩怨,這里有你想知道的一切
    • 記憶體組成
      • 堆區
      • 堆疊區
      • 靜態存盤區
      • 代碼區
    • 字串定義 - 一維
      • char s[10] = "Hello"
      • char *s = "Hello"
    • 字串定義 - 二維
      • char s[10][10] = {"Hello","World"}
      • char *s[10] = {"Hello", "World"}
    • 對二維陣列結構的認識
      • 關于二維陣列
      • 二維陣列中的指標等價關系
      • 陣列結構中對“指標常量”的理解
    • 指標 vs 陣列 記憶體結構一圖流
    • One More Thing
        • 題面
        • 輸入格式
        • 輸出格式

記憶體組成

在這里插入圖片描述

堆區

堆區 (Heap):由程式員手動申請釋放的記憶體空間,

  1. C中:malloc()colloc()函式申請,用free()釋放

若不用free()釋放,容易造成記憶體泄露(即記憶體被浪費、耗盡),

  • ptr = (castType*) malloc(size);

    傳入引數為記憶體的位元組數,記憶體未被初始化,

  • ptr = (castType*)calloc(n, size);

    存入引數為記憶體塊數與每塊位元組數,記憶體初始化為0

  • free(ptr);

    釋放申請的記憶體,

  1. C++中:new申請,delete釋放,newdelete都是運算子
  • int *arr = new int[10];
  • delete[] arr;

堆疊區

堆疊區 (Stack):由系統管理,存放函式引數與區域變數,函式完成執行,系統自行釋放堆疊區記憶體,

靜態存盤區

靜態存盤區 (Static Storage Area):在編譯階段分配好記憶體空間并初始化,

其中全域區存放靜態變數(static修飾的變數)、全域變數(具有全域作用域的變數);常量區存放常量(又稱為字面量),

常量可分為整數常量(如1000L)、浮點常量(如314158E-5L)、字符常量(如'A'、'\n')和字串常量(如"Hello")

const關鍵字修飾的的變數無法修改,但存放的位置取決于變數本身是全域變數還是區域變數,當修飾的變數是全域變數,則放在全域區,否則依然在堆疊區分配,

static關鍵字修飾的變數存在全域區的靜態變數區,

常變數宏定義的概念不同,

常變數存盤在靜態存盤區,初始化后無法修改,

宏定義在預處理階段就被替換,不存在與任何記憶體區域,

代碼區

代碼區 (Code Segment):存放程式體的二進制代碼,

/*示例代碼*/

int a = 0;          //靜態全域變數區
char *p1;           //編譯器默認初始化為NULL,存在靜態全域變數區

void main()
{
    int b;                //堆疊
    char s[] = "abc";     //堆疊
    char *p1 = "123";     //"123"在字串常量區,p1在堆疊區
    
    p2 = (char *)malloc(10); //堆區
    strcpy(p2, "123");       //"123"放在字串常量區
    
    const int d = 0;      //堆疊
    static int c = 0;     //c在靜態變數區,0為文字常量,在代碼區
    static const int d;   //靜態常量區
    
}

字串定義 - 一維

char s[10] = "Hello"

記憶體:靜態存盤區上的字面量"Hello"被復制到堆疊區,陣列在堆疊區上的存盤方式為'H''e''l''l''o''\0',可以通過s[i]修改,但這不會影響到靜態存盤區上的"Hello"

定義與使用:

#include <stdio.h>

void f(char s[10]) {      //等價于char *s
    printf("%s\n", s);
}

int main() {
    char s[10] = "LeeHero";
    s[3] = 'Z';
    printf("%s\n", s);   //輸出:LeeZero
    printf("%s\n", s+1); //輸出:eeZero
    printf("%c\n", s[3]);//輸出:Z
 
    f(s); //陣列名作為函式引數傳遞時,會退化成指向陣列首元素的指標 !IMPORTANT
    return 0;
} 

格式控制符 %s 跟隨一個地址,并當做是字串第一個元素對應的地址.

從該首地址開始決議,直到 '\0' 結束,

在這里指的是 s[0] = 'H' 的地址,

char *s = "Hello"

// 等價于const char *s = "Hello"

記憶體:s是指向字面量"Hello"的指標,字面量在靜態記憶體區,因此該字串不可被修改,

定義與使用:

#include <stdio.h>

void f(char s[10]) {       //等價于char *s
    printf("%s\n", s);
}

int main() {
    char *s = "LeeHero";
    //s[3] = 'Z';          //無法執行 
    printf("%s\n", s);     //輸出:LeeHero
    printf("%s\n", s+1);   //輸出:eeHero
    printf("%c\n", s[3]);  //輸出:H
 
    f(s);
    
    return 0;
} 

字串定義 - 二維

char s[10][10] = {"Hello","World"}

記憶體:靜態存盤區上的字面量"Hello""World"被拷貝在堆疊區,與一維定義方式同理,可以通過語法糖s[i][j]修改字符,

定義與使用:

#include <stdio.h>

void f(char (*s)[10]) {        //形參s是個指標,指向有10個元素的字符陣列
                               //把(*s)[10] 改成 s[][10] ,其他不變,最后效果相同
    printf("%s\n", s[1]);      //輸出:Zero
    s[1][0] = 'H';             //通過語法糖s[i][j]修改字符
    printf("%s\n", s[1]);      //輸出:Hero
    printf("%c\n", s[0][1]);   //輸出:e
}

int main() {
    char s[10][10] = {"Lee","Hero"};
    //s[1] = "Hey";            //無法執行,這種賦值方式僅在初始化時可用
    s[1][0] = 'Z';
    printf("%s\n", s);         //輸出:Lee
    printf("%s\n", *s+1);      //輸出:ee
    printf("%s\n", s[0]+1);    //輸出:ee
    
    printf("%c\n", *(s[0]+1)); //輸出:e
    printf("%c\n", s[0][1]);   //輸出:e
    
    printf("%s\n", s+1);       //輸出:Zero
    printf("%s\n", s[1]);      //輸出:Zero
    
    f(s);
    
    printf("%s\n", s[1]);      //輸出:Hero 這意味著函式內部的修改不是區域生效的
    return 0;
} 

對于列印結果的一些解釋:

· 對二維陣列進行操作與輸出

  1. s 等價于&s[0],是指向[存盤"Lee"的一維陣列]的指標

  2. s+1等價于&s[1],是指向[存盤"Zero"的一維陣列]的指標

  3. *s+1等價于(*s)+1s通過*決議首先得到[一維陣列"Lee"]

    即指向[一維陣列"Lee"的第一個元素'L'的地址]的指標s[0]

    對該指標+1,相當于s[0]+1,使得指標指向[一維陣列"Lee"第二個元素'e'的地址]

    格式控制符%s將該元素看成字串的首地址,因而列印出"ee"

· 二維陣列傳參

二維陣列主要有兩種傳參方式(以下兩種是函式宣告的方式,宣告函式后,都是使實參為陣列名來呼叫函式:f(s);

  1. void f(char (*s)[10]) {} —— 一維陣列指標作形參

    二維陣列名實際上就是指向一維陣列的指標,因此這里形參s是個指向行元素的指標,與二維陣列名匹配,

  2. void f(char s[][10]) {} —— 二維陣列指標作形參
    對于這種方法,僅二維陣列的陣列列數可以省略,不可省略行數,f(char s[][])是錯誤的,

    也就是說,1.和2.方式中都需要正確指定行數,

  3. f(char **s)f(char *s[])的方式宣告函式雖然能編譯輸出,但編譯器可能會出現以下警告資訊:

    [Warning] passing argument 1 of 'f' from incompatible pointer type
    [Note] expected 'char **' but argument is of type 'char (*)[10]'
    

    P.S. 當然,如果一定要用二維指標作實參f(char **s),在傳參的時候可以將s強制轉化:f((char **)s),函式內部操作元素可以通過*((int *)a+i*10+j)的方式……但何必呢,

    如果一定要試試,這里也有個例子:

    #include <stdio.h>
                
    void f(char **s) {                     //形參s是個二維指標
        printf("%c\n", *((char *)s));      //輸出:L
        printf("%s\n", ((char *)s));       //輸出:Lee
        printf("%c\n", *((char *)s+10));   //輸出:H
        printf("%s\n", ((char *)s+10));    //輸出:Hero
    }
                
    int main() {
        char s[10][10] = {"Lee","Hero"};
        f((char **)s);                     //“我一定要把s看做二維指標去傳參!”
        return 0;
    }
    
    

char *s[10] = {"Hello", "World"}

記憶體:類比char *s = "Hello",這里s是一個指標陣列,s[0]s[1]是兩個指標,分別指向字面量"Hello""World",指向的內容可以訪問,無法修改,

定義與使用:

#include <stdio.h>

void f(char **s) {
    printf("%s\n", s[0]);        //輸出:Lee
    printf("%c\n", s[0][0]);     //輸出:L
}

int main() {
    char *s[10] = {"Lee","Hero"};
    printf("%s\n", s[0]);        //輸出:Lee(等價于*s)
    printf("%c\n", s[0][0]);     //輸出:L  (等價于*s[0]) 

    f(s);
    return 0;
} 

解釋:

陣列名作為函式引數傳遞時,會退化成指向陣列首元素的指標,

當把s作為引數傳遞給f()函式時,實際上是把指標陣列的首地址傳遞給了f()函式,這樣,f()函式中的s就是一個二級指標,它指向了指標陣列的第一個元素,也就是第一個字串的地址,

f()函式接受一個二級指標作為引數,由此,f()函式中的s[0]s[0][0]與主函式中的s[0]s[0][0]含義相同,

#include <stdio.h>

int main() {
    
	/* s[10][10]與*s[10]的對比 */
    
    char *s[10] = {"Lee","Hero"};
    printf("%d %d\n", sizeof(s), &s);            //輸出:80 6487488
    printf("%s\n", s);                           //無輸出! 
    
    printf("%d %d\n", sizeof(s[0]), &s[0]);      //輸出:8  6487488
    printf("%s\n", s[0]);                        //輸出:Lee(等價于*s)
    
    printf("%d %d\n", sizeof(s[0][0]), &s[0][0]);//輸出:1  4210692
    printf("%c\n\n", s[0][0]);                   //輸出:L  (等價于*s[0]) 
    
    char t[10][10] = {"Lee","Hero"};
    printf("%d %d\n", sizeof(t), &t);            //輸出:100 6487376
    printf("%s\n", t);                           //輸出:Lee
    
    printf("%d %d\n", sizeof(t[0]), &t[0]);      //輸出:10  6487376
    printf("%s\n", t[0]);                        //輸出:Lee(等價于*t)
    
	printf("%d %d\n", sizeof(t[0][0]), &t[0][0]);//輸出:1   6487376
    printf("%c\n", t[0][0]);                     //輸出:L  (等價于*t[0])
    
    /* *s[10]內容無法修改 */
    t[1][0] = 'Z';           //修改二維陣列元素
    printf("%s\n", t[1]);    //輸出:Zero
    s[1][0] = 'Z';           //程式運行到這里崩潰!
    printf("%s\n", s[1]);    //無輸出!
    
    return 0;
} 

對二維陣列結構的認識

關于二維陣列

a[i][j] : 第 \(i\) 行第 \(j\) 列元素

a[i]:一級指標常量,指第 \(i\) 行首元素地址,第 \(i\) 行本質為一維陣列,a[i]+j是第 \(i\) 行第 \(j\) 列元素的地址

a:陣列指標常量,是二維陣列的起始地址,第 \(0\) 行的起始地址,

image-20230323214508306

二維陣列中的指標等價關系

優先級:() \(>\) ++ \(>\) 指標運算子* \(>\) +

二級指標 <—— 一級指標 <—— <—— 陣列元素 <—— <——
a &a[0] *a+j a[0]+j &a[0][j] *(*a+j) *(a[0]+j) a[0][j]
a+i &a[i] *(a+i)+j a[i]+j &a[i][j] *(*(a+i)+j) *(a[i]+j) a[i][j]

image-20230323232346347

陣列結構中對“指標常量”的理解

指標常量:不能修改指標所指向的地址,但指向的值可以改變,

陣列名是指標常量,陣列名代表陣列的首地址,它的值不能改變,也就是說不能讓陣列名指向其他地址,

二維陣列中a[i][j]中,a[i]可以看做是指向第 \(i\) 個一維陣列的指標,它的值是第 \(i\) 個一維陣列的首地址,a[i] 的值不能改變,也就是說不能讓 a[i] 指向其他地址,可以類比為指標常量,

總之,陣列結構中各元素地址都是連續且無法更改的,

char a[10][10] = {"Lee", "Hero"};
char *p[10] = {0} //定義指標陣列

p[0] = a[0];
p[1] = a[1]; 
p[0] = p[1];      //合法

a[0] = a[1];      //非法

指標 vs 陣列 記憶體結構一圖流

圖由ECNU16級的陽太學長提供~

image-20230325010908380

image-20230325002950287

One More Thing

當二維陣列遇見qsort()庫函式,關于比較函式cmp(const void *a, const void *b)的迷思

利用qsort()函式對一個整數陣列進行排序,一般格式如下:

#include <stdio.h>
#include <stdlib.h>

// 比較函式,用于升序排序整數
int cmp(const void *a, const void *b) {
    int n1 = *(int *)a;
    int n2 = *(int *)b;
    return n1 - n2;
}

int main() {
    int arr[] = {10, 5, 15, 12, 90, 80};
    int n = sizeof(arr) / sizeof(arr[0]), i;
    
    // 呼叫qsort庫函式,傳入陣列指標,元素個數,元素大小和比較函式
    qsort(arr, n, sizeof(int), cmp);

    // 列印排序后的陣列
    printf("Sorted array: ");
    for (i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
    
    /* 輸出結果:Sorted array: 5 10 12 15 80 90 */
    
    return 0;
}

可見,傳入cmp()函式的引數是兩個void型指標,指向我們需要排序的陣列中的每個元素,在上面的例子中,int n1 = *(int *)a;即是將void型指標強制轉換成int型指標后用*解地址,得到的便是陣列中的元素,

ECNU Online Judge有這樣一道題:[郵件地址排序]

題面

現接收到一大批電子郵件,郵件地址格式為:用戶名@主機域名,要求把這些電子郵件地址做主機域名的字典序升序排序,如果主機域名相同,則做用戶名的字典序降序排序,

輸入格式

第一行輸入一個正整數 \(n\),表示共有 \(n\) 個電子郵件地址需要排序,接下來 \(n\) 行,每行輸入一個電子郵件地址(保證所有電子郵件地址的長度總和不超過 \(10^6\)),

  • 對于 \(50\%\) 的資料,保證 \(n \leqslant 100, |s_i| \leqslant 100\)

用戶名只包含字母數字和下劃線,主機域名只包含字母數字和點,

輸出格式

按排序后的結果輸出 \(n\) 行,每行一個電子郵件地址,

為節省記憶體,通過比較逆天的試例,考慮用指標與malloc()動態記憶體管理存盤郵件地址:

image-20230325020950813

為了和這篇博客主題契合,這里只介紹這種資料存盤結構的實作方式與cmp()的設計方法:

/* 資料輸入 */

int T; //要輸入的郵件個數
scanf("%d", &N);

//建立指標陣列 email
char **email;
email = (char **)malloc(N * sizeof(char*)); //相當于實作了char *email[N]

//使指標陣列 email 中的每個指標元素都指向一個郵件地址字串
for (int i = 0; i < N; i++) {
    scanf("%s", s);  //讀取一個字串
    LEN = strlen(s); //獲取字串長度
    p = (char *)malloc((LEN+1) * sizeof(char)); //分配每個字串的存盤空間
    strcpy(p, s);    //把字串復制到p處,這兩行相當于實作了char p[LEN+1] = {s}
    *(email + i) = p;
    //使指標陣列 email 中的指標元素指向 p ,p也是個指標,但借助malloc()動態分配,實作了字串的功能
}

資料輸入完畢后最終實作的效果,類似于char *email[50] = {"[email protected]", "[email protected]"}的定義方式,只是一維字符陣列的長度是借助malloc()動態分配的,并不是個定值,

資料輸入完畢,我們現在得到了一個名為email的指標陣列,陣列里的每個元素都是一個指標,指向共 \(N\) 個字串,

設計cmp()時,傳入cmp()函式的引數是兩個void型指標,指向我們需要排序的陣列中的每個元素,因此,void型指標指向一級指標,這樣的void型指標就是二維指標——char **

int cmp (const void *a, const void *b) {
    char *p1 = *((char **)a);
    char *p2 = *((char **)b); //對二級指標a、b進行一次解地址,得到的就是一級指標p1,p2
                              //通過 *(p1+i) *(p2+i) 操作就可以決議到[一級指標所指字串]的每個字符
                              //從而做進一步的比較處理
    /* 后續省略 */
    return ret;
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/548026.html

標籤:其他

上一篇:odoo 開發入門教程系列-模型和基本欄位

下一篇:P1036 [NOIP2002 普及組] 選數

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more