主頁 > 後端開發 > 前端學習C語言 - 初級指標

前端學習C語言 - 初級指標

2023-06-26 07:57:45 後端開發

初級指標

本篇主要介紹:指標和變數的關系、指標型別、指標的運算子、空指標和野指標、指標和陣列指標和字串、const 和指標、以及gdb 除錯段錯誤

基礎概念

指標是一種特殊的變數,存放地址的變數就是指標,

int num = 1; 會申請4個位元組的記憶體來存放數字1,每次訪問 num 就是訪問這4個位元組,

訪問記憶體中的這4個位元組,不僅可以通過名稱(例如 num),還可以通過地址

Tip& 不僅是位運算子,還是取地址運算子,例如 int* ptr = #,就是取變數 num 的地址并將其保存到指標變數 ptr 中

請看示例:

#include <stdio.h>

int main() {
    int num = 10;

    // num 的地址:0x7fff4dbf01d8
    printf("num 的地址:%p\n", &num);
    // num 的地址加1 :0x7fff4dbf01dc,
    printf("num 的地址加1 :%p\n", &num + 1);

    // j 存放連續記憶體的第一個位元組地址
    int *j = &num;

    // 10,通過地址訪問
    printf("%d", *j);

    return 0;
}

&num&num + 1 相差4個位元組,說明 &num 表示整數,

普通變數存放值,而指標用于存放地址,

通過 int *j = &num 將變數num的首地址給到指標 j(j的型別是 int *),最后通過地址(*j) 訪問整數1,

int *j 是一個int型別的指標,還有 char、float等指標型別,指標型別必須匹配,比如將 j 的指標型別換成 char,則會警告,就像這樣:

- int *j = &num;
+ char *j = &num;

運行:

/workspace/CProject-test/main.c:12:11: warning: incompatible pointer types initializing 'char *' with an expression of type 'int *' [-Wincompatible-pointer-types]
    char *j = &num;
          ^   ~~~~
1 warning generated.
num 的地址:0x7ffddcfe5328
num 的地址加1 :0x7ffddcfe532c
10

Tip: 指標 j 也有地址,也就是指標的指標,現在不研究

練習

題目:請問輸出什么?

#include <stdio.h>

int main() {
    int num = 10;
    int *p = &num;
    printf("用指標訪問資料 num :%d\n", *p);

    *p = 11;
    printf("用過指標修改 num 資料:%d\n", num);

    return 0;
}

提示:資料可以通過變數訪問,也能使用地址(指標)訪問,就像通知同學去嵌入式實驗室上課,或者是 303 上課,其中*p = 11; 等價于 num = 11;

輸出:

用指標訪問資料 num :10
用過指標修改 num 資料:11

星號的作用

指標 * 有兩個主要作用(根據* 前面有無型別做區分):

  • 指標型別宣告
  • 取值(又稱解參考運算子),例如,*ptr 表示獲取指標變數 ptr 所指向記憶體地址上的值,

請看示例:

#include <stdio.h>

int main() {
    int num = 10;
    // 指標型別宣告
    int *p = &num;

    // 取值
    printf("%d\n", *p); // 10

    // 取值
    *p = 11;
    printf("%d\n", num); // 11

    return 0;
}

指標型別

所占位元組

在32位系統上,指標通常占用4個位元組;而在64位系統上,指標通常占用8個位元組,請看示例:

#include <stdio.h>

int main() {
    printf("char型別指標所占位元組數為:%zu\n", sizeof(char*));
    printf("short型別指標所占位元組數為:%zu\n", sizeof(short*));
    printf("int型別指標所占位元組數為:%zu\n", sizeof(int*));
    printf("long型別指標所占位元組數為:%zu\n", sizeof(long*));
    printf("float型別指標所占位元組數為:%zu\n", sizeof(float*));
    printf("double型別指標所占位元組數為:%zu\n", sizeof(double*));
    printf("long long型別指標所占位元組數為:%zu\n", sizeof(long long*));
    return 0;
}

輸出:

char型別指標所占位元組數為:8
short型別指標所占位元組數為:8
int型別指標所占位元組數為:8
long型別指標所占位元組數為:8
float型別指標所占位元組數為:8
double型別指標所占位元組數為:8
long long型別指標所占位元組數為:8

練習

題目:請問整數型別的指標和字符型別的指標加1分別是幾個位元組?

#include <stdio.h>

int main() {
    int num = 10;

    printf("num 的地址:%p\n", &num);
    printf("num 的地址加1 :%p\n", &num + 1);

    char ch = 'a';

    printf("ch 的地址:%p\n", &ch);
    printf("ch 的地址加1 :%p\n", &ch + 1);
    return 0;
}

輸出:

num 的地址:0x7fffe8244288
num 的地址加1 :0x7fffe824428c
ch 的地址:0x7fffe8244287
ch 的地址加1 :0x7fffe8244288

答案int * 加1是4個位元組;char * 加1是1個位元組,&num 和 &ch 分別代表該變數的全部位元組,

指標交換資料

比如這段代碼是不能實作 a、b 兩數交換,請看示例:

#include <stdio.h>

void swap(x, y){
    int tmp = x;
    x = y;
    y = tmp;
}
int main() {
    int a = 1;
    int b = 2;
    swap(a, b);
    printf("a:%d\n", a);
    printf("b:%d\n", b);
    return 0;
}
a:1
b:2

分析:呼叫 swap(a, b) 這里是一個值傳遞,找到函式入口地址,對引數 x、y 申請空間和賦值,通過 tmp 變數完成了 x和y的交換,最后回收區域變數 x、y和tmp,釋放空間,而 a,b資料沒有變化,

可以通過指標來實作兩數的交換,請看示例:

#include <stdio.h>

void swap(int* x, int* y){
    int tmp = *x;
    *x = *y;
    *y = tmp;
}
int main() {
    int a = 1;
    int b = 2;
    swap(&a, &b);
    printf("a:%d\n", a);
    printf("b:%d\n", b);
    return 0;
}
a:2
b:1

分析:通過 swap(&a, &b) 將 a b 的地址傳給 x 和 y,通過 x 和 y 指標對 a 和 b 進行交換,雖然最后會銷毀swap中的區域變數,但 a 和 b的值已經完成了交換,

指標的運算子

指標和變數的關系

練習1

題目:輸出什么?

#include <stdio.h>

int main() {
    int a = 10, *pa = &a, *pb;
    printf("%d\n", *pa);
    pb = pa;
    printf("%d\n", *pb);
    return 0;
}

輸出:10 10

分析:


int a = 10, 
// pa 指向變數 a
*pa = &a, 
// 定義一個整數型的指標 pb
*pb;
printf("%d\n", *pa);

// pb 也指向變數 a
pb = pa;
printf("%d\n", *pb);
return 0;

練習2

題目:輸出什么?

#include <stdio.h>

int main() {
    int x = 3, y = 0, *px = &x;

    y = *px + 5;
    printf("%d\n", y);

    y= ++*px;
    printf("%d\n", y);

    printf("%p\n", px);

    y = *px++; 
    printf("%p\n", px);
    printf("%d\n", y);

    return 0;
}

輸出:

8
4
0x7ffc48b9be38
0x7ffc48b9be3c
4

分析:

  • y= ++*px; 等效 ++(*px),如果是 ++* 是不對的
類似 y = ++i,等于先執行 ++,在執行 y = i,
這里先對 (*px) 執行 ++,在回傳  *px 的值
  • y = *px++;
先執行 y = *px,然后是 px++,px是整數型別的地址,加1就是加4個位元組,

練習3

題目:輸出什么?

#include <stdio.h>

int main() {
    int x = 3, y = 0, *px = &x;
    printf("%p\n", px);
    y = (*px)++; 
    printf("%p\n", px);
    printf("%d\n", x);

    return 0;
}

輸出:

0x7ffef1dc4d58
0x7ffef1dc4d58
4

分析:*px++ 表示指標加1,(*px)++ 表示值加1,

指標初始化

指標初始化有兩種方法:已經存在的空間和自己申請空間,

已經存在的空間,例如:

#include <stdio.h>
#include <stdlib.h>
int main() {
    int num;
    int* p = &num;
    *p = 10;

    char *str = "abc";
    printf("%s\n", str); // abc,把字串的地址賦值給指標變數
    return 0;
}

自己申請空間可以使用 malloc 函式,申請的是 void 型別指標,也稱為通用型別指標,請看示例:

#include <stdio.h>
// malloc 需要引入 <stdlib.h>
#include <stdlib.h>
int main() {
    // 申請16個位元組
    int* q = malloc(sizeof(int) * 4); // 在堆里申請了16個位元組
    // int* q = (int *)malloc(sizeof(int) * 4); // 推薦
    
    *q = 10;
    // 釋放申請的16個位元組
    free(q);
    return 0;
}

申請空間,使用完需要使用 free() 釋放,

Tip:根據 C99 標準以及更高版本的標準,顯式的型別轉換是建議的做法,以確保型別的安全性和可讀性,

空指標和野指標

下面這段代碼 p 就是一個野指標,運行報錯:段錯誤 (核心已轉儲)

#include <stdio.h>

int main() {
    int* p;
    *p = 1;
    return 0;
}

這里宣告一個指標 p,里面是一個亂數,例如 0x7ffe71df3f40,接著往指向的記憶體放1,由于這塊記憶體不知道是否存在,即使存在也不能訪問,于是報段錯誤

直接手寫一個地址也不可以,就像這樣:

#include <stdio.h>

int main() {
    
    // warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'long' [-Wint-conversion]
    // 這個警告是因為你正在將一個 long 型別的運算式賦值給一個 int* 型別的指標變數,導致型別不匹配,
    // int* p = 0x7ffe71df3f40;
    int* p = (int *)0x7ffe71df3f40;
    *p = 100;
    return 0;
}
// 分段錯誤 (核心已轉儲)"
Segmentation fault (core dumped)

空指標也不能使用:

int* p = NULL;
*p = 100;

// 輸出:`Segmentation fault (core dumped)`

但空指標會讓你可控,就像這樣:

int* p = NULL;

if (p != NULL) {
    printf("p is not NULL\n");
}else{
    printf("p is NULL\n");
}

// 輸出:p is NULL

指標和陣列

指標當陣列用

遍歷一個陣列,可以這樣:

#include <stdio.h>

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int length = sizeof(arr) / sizeof(arr[0]);  // 計算陣列的長度
    // 1 2 3 4 5 
    for (int i = 0; i < length; ++i) {
        printf("%d ", arr[i]);
    }

    return 0;
}

使用指標遍歷陣列有兩種方式(效果相同),請看示例:

#include <stdio.h>

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int length = sizeof(arr) / sizeof(arr[0]);  // 計算陣列的長度

    // 指標遍歷方式1
    /*
    int* pArr = arr;
    for (int i = 0; i < length; ++i) {
        printf("%d ", *(pArr + i));
    }
    */

    // 指標遍歷方式2
    int* pArr = arr;
    for (int i = 0; i < length; ++i) {
        printf("%d ", pArr[i]);
    }

    return 0;
}

Tip:在陣列一文中我們知道陣列名表示首元素地址,這里*(pArr + i)會依次遍歷陣列或許是因為指標是int型別吧!

總結pArr[i] 等于 *(pArr + i),在這里[]不再是取某個索引,而是表示取值,

指標和字符陣列

題目:分析 char a[] = "Hello";char *b = "World";

  • 都可以用for遍歷元素,例如:
#include <stdio.h>

int main() {
    char a[] = "Hello";
    char *b = "World";

    // Iterating over 'a'
    printf("Characters in 'a':\n");
    for (int i = 0; a[i] != '\0'; i++) {
        printf("%c\n", a[i]);
    }

    // Iterating over 'b'
    printf("\nCharacters in 'b':\n");
    for (int i = 0; b[i] != '\0'; i++) {
        printf("%c\n", b[i]);
    }

    return 0;
}

輸出:

開始運行...

Characters in 'a':
H
e
l
l
o

Characters in 'b':
W
o
r
l
d

運行結束,
  • 為什么指標也可以通過索引訪問特定字符?
    比如 char *b = "World";,可以將字串視為字符陣列,使用指標來指向該陣列的首地址,指標可以通過偏移來訪問特定位置的元素,包括字串中的字符,

練習

題目:下面代碼中 p1[0]p2[0]p3[0]的值分別是多少?

// 申請4*4個位元組,每個位元組地址假如是:0x100(存放1) 0x104(存放2) 0x108 0x10c
int a[] = {1,2,3,4};

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

int *p2 = (int*)((int)a + 1);

int *p3 = (int*)(a + 1);

分析:

  • (int*)(&a + 1) - &a 表示整個陣列,加1則到下一個陣列,然后將陣列指標強轉成整數指標,指向第5個元素,其實已經越界了,
  • (int*)((int)a + 1) - a 表示陣列首元素地址,(int)a 將地址轉為整數,以前是加1個元素,現在就是加1,然后又將整數轉為整數指標,亂了(就好比訪問 0x101 0x102 0x103 0x104
  • (int*)(a + 1) - a 表示陣列首元素地址,加1則是第二個元素地址 0x104,不強轉也可以,

結論:只有p3[0](等價于 *(p3 + 0))是一個正常的元素,也就是2.

指標和字串

題目:用陣列和指標定義字串有什么區別?

#include <stdio.h>

int main() {
    char str[] = "HelloWorld";
    // HelloWorld
    printf("%s\n", str);

    char* s = "HelloWorld";
    // HelloWorld
    printf("%s\n", s);

    return 0;
}

Tip: 字串的輸出都是首地址,比如這里的 str 是陣列的首地址,s 指標指向的也是首地址,

分析:
char str[] = "HelloWorld"; 在堆疊中定義一個陣列,用11個位元組存盤HelloWorld(還有一個 \0),請看示例:

#include <stdio.h>

int main() {
    char str[] = "HelloWorld";
    str[0]++; 
    // IelloWorld
    printf("%s\n", str); 
    // error: cannot increment value of type 'char[11]'
    str++;
    // printf("%s\n", str);
    return 0;
}

陣列名(str++)不可以修改,str 就是陣列首元素地址,已經固定了,可認為它是常量,但陣列內容可以修改,

char* s = "helloWorld";helloWorld 放在只讀資料區,s 是區域變數,放在堆疊中,占8個位元組,請看示例:

#include <stdio.h>

int main() {
    char* s = "helloWorld";
    
    s++;
    // elloWorld
    printf("%s\n", s);

    // 報錯:Segmentation fault (core dumped)
    s[0]++;

    return 0;
}

指標可以加加,但指標指向的內容不能修改,

str 只是個名字,不占空間,如果一定要說占多少,那就是它執行的陣列占11個位元組,而 s 是8個位元組,指向一個只讀區,占 11 個位元組,

練習

題目:分析以下示例,

#include <stdio.h>

int main() {
    char str[20];
    str = "HelloWorld";

    char* s;
    s = "HelloWorld";
    // HelloWorld
    printf("%s\n", s);

    return 0;
}

分析:

// 分配20個位元組的記憶體,并把首地址給 str
char str[20];
// str 是只讀的,不能再賦值,報錯:`error: array type 'char[20]' is not assignable`
str = "HelloWorld";

// 定義一個指標 s
char* s;
// 將 HelloWorld 的首地址給 s
s = "HelloWorld";

擴展

自定義strcpy()函式

題目:實作原生字串拷貝方法strcpy,strcpy 其用法如下:

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

int main() {
    char source[] = "Hello";
    char destination[10]; // 目標字串需要足夠的空間來容納 source 字串

    strcpy(destination, source);

    printf("Source string: %s\n", source);
    printf("Destination string: %s\n", destination);

    return 0;
}

實作:

#include <stdio.h>

char* strcpy_custom(char* destination, const char* source) {
    // 字串陣列末尾有一個特殊的空字符 '\0' 來表示字串的結束,逐個復制字符,直到遇到源字串的結束標志 '\0'
    while (*source != '\0') {
        *destination = *source;
        destination++;
        source++;
    }

    *destination = '\0'; // 在目標字串末尾添加結束標志 '\0'

    return destination;
}

int main() {
    // 定義兩個字符陣列
    char source[] = "Hello";
    char destination[10]; // 目標字串需要足夠的空間來容納 source 字串

    // 陣列名,表示首元素的地址,加 1 是加一個元素(比如這里1個位元組)
    strcpy_custom(destination, source);

    printf("Source string: %s\n", source);
    printf("Destination string: %s\n", destination);

    return 0;
}

Tipconst char* source 中 const 的作用請看const 和指標

輸出:

開始運行...

Source string: Hello
Destination string: Hello

運行結束,

將 while 替換成下面一行代碼效果也相同:

char* strcpy_custom(char* destination, const char* source) {
    /*
    while (*source != '\0') {
        *destination = *source;
        destination++;
        source++;
    }

    *destination = '\0'; 
    */

    // 替換成
    while((*destination++ = *source++) != '\0');
    return destination;
}

分析:(*destination++ = *source++) != '\0':

之前的是首先判斷,在賦值,`*source != '\0'`、`*destination = '\0';`,這里是先賦值

后置++會放在運算式最后,所以等于:

(*destination = *source) != '\0';
destination++;
source++;

const 和指標

首先補充下(int*)的作用,之前說到 const 定義的變數可以被修改,我們寫了如下代碼:

#include <stdio.h>

int main() {
    const int val =5;

    int *ptr= (int*)&val;
    *ptr=10;

    printf("val = %d\n",val);
    printf("*ptr = %d\n", *ptr);

    return 0;
}

其中 int *ptr= (int*)&val; 是將一個 const int 型別的變數 val 地址強制轉換為 int* 型別的指標,并將指標存盤在 ptr 中,這種型別轉換是不安全的,因為它丟失了 val 的常量性質,

const char* source 宣告一個常量指標,以下代碼僅做示意:

#include <stdio.h>

int main() {
    const char* source = "Hello";
    char* mutableSource = "World";

    printf("%c\n", source[0]);
    printf("%c\n", mutableSource[0]);

    // 以下操作是非法的,會導致編譯錯誤
    // source[0] = 'h'; // 不能修改字符資料

    // 合法
    // 盡管mutableSource是一個非常量指標,看起來可以進行修改,但修改字串常量是不被允許的,并且這可能導致未定義行為,
    mutableSource[4] = 'w'; // 可以修改字符資料
    return 0;
}

運行:

開始運行...

H
W
Segmentation fault (core dumped)

運行結束,
就近原則

const 有個就近原則

  • 比如:const int* p1 = &num;,const 修飾的是 *,所以 *p1 不能修改, p1 可以修改
  • 比如:int* const p2 = &num;,const 修飾 p2,所以 p2 不能修改,*p2 可以修改

請看示例:

#include <stdio.h>

int main() {
    int num = 1;
    const int* p1 = &num; // const 修飾的是 *,所以 *p1 不能修改, p1 可以修改

    p1++;
    // (*p1)++;

    int* const p2 = &num; // const 修飾 p2,所以 p2 不能修改,*p2 可以修改

    // p2++;
    (*p2)++;

    const int* const p3 = &num; // 兩個都不能修改
    // p3++;
    // (*p3)++;

    return 0;
}

gdb 除錯段錯誤

GDB(GNU Debugger)是一款強大的除錯器,用于幫助開發者查找和解決程式中的錯誤,通過與源代碼互動,并提供諸如斷點設定、變數觀察、記憶體檢查等功能,GDB允許開發者逐行執行程式并分析其運行狀態,
除了上文使用的 run,還有如下操作

  • run:運行程式,
  • break <line_number>:在指定行設定斷點,
  • break <function_name>:在指定函式設定斷點,
  • continue:繼續執行程式直到下一個斷點或程式結束,
  • next:逐程序地執行程式,
  • step:逐陳述句地執行程式,
  • print <variable>:列印變數的值,
  • backtrace:顯示函式呼叫的堆疊跟蹤資訊,
  • quit:退出GDB除錯會話,

使用 gdb 除錯段錯誤的程序如下:

撰寫代碼:

pjl@pjl-pc:~/pjl$ cat demo-3.c
#include <stdio.h>

int main() {
    int* p;
    *p = 1;

    return 0;
}

編譯運行發現段錯誤:

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

將代碼編譯為可除錯的可執行檔案,在gcc或g++編譯時,添加"-g"選項可以生成包含除錯資訊的可執行檔案,

// 增加 -g
pjl@pjl-pc:~/pjl$ gcc demo-3.c -o demo-3 -g

// 啟動GDB并加載可執行檔案
pjl@pjl-pc:~/pjl$ gdb demo-3
GNU gdb (Ubuntu 9.1-0kylin1) 9.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from demo-3...

(gdb) 

輸入 run(還有其他操作) 找到是第5行代碼報錯:

...
// run:運行程式,
(gdb) run
Starting program: /home/pjl/pjl/demo-3

Program received signal SIGSEGV, Segmentation fault.
0x0000555555555135 in main () at demo-3.c:5
5           *p = 1;
(gdb)

高級指標

提前透露:指標遇上陣列

題目:以下代碼輸出什么?

#include <stdio.h>

int main() {
    char * string[] = {"Hello", "World" };
    printf("%s\n", string);
    return 0;
}

分析:
我們知道定義字串有以下兩種方法:

char str[] = "HelloWorld";
char* s = "HelloWorld";

Tip: string 在 C 中不是關鍵字,也不是保留字,就是一個普通變數名,

[] 的優先級是非常高的,這里首先是定義一個陣列(string[]),其次就是指標,合起來就是一個指標陣列,

首先在只讀區分配兩塊記憶體分別存放 Hello(地址比如是 0x100) 和 World(地址比如是 0x200),指標陣列是16個位元組,本質就是陣列,只不過里面放的是指標,比如前8個位元組的地址是0x1000,那么 string 就是 0x1000,因為陣列名就是陣列首元素地址,

所以要輸出這兩個字串,可以這么寫:

#include <stdio.h>

int main() {
    char * string[] = {"Hello", "World" };

    // Hello
    printf("%s\n", string[0]);
    // World
    printf("%s\n", string[1]);
    return 0;
}
作者:彭加李
出處:https://www.cnblogs.com/pengjiali/p/17502968.html
本文著作權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連接,

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

標籤:其他

上一篇:PGO前瞻

下一篇:返回列表

標籤雲
其他(161559) Python(38248) JavaScript(25513) Java(18259) C(15238) 區塊鏈(8272) C#(7972) AI(7469) 爪哇(7425) MySQL(7266) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4606) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2437) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1971) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(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
最新发布
  • 前端學習C語言 - 初級指標

    ## 初級指標 本篇主要介紹:`指標和變數的關系`、指標型別、`指標的運算子`、空指標和野指標、`指標和陣列`、`指標和字串`、const 和指標、以及`gdb 除錯段錯誤`。 ### 基礎概念 > 指標是一種特殊的變數。存放地址的變數就是指標。 `int num = 1;` 會申請4個位元組的記憶體 ......

    uj5u.com 2023-06-26 07:57:45 more
  • PGO前瞻

    原文在[這里](https://go.dev/blog/pgo-preview)。 > 原文發布于2023年2月8日 在構建Go二進制檔案時,Go編譯器會進行優化,以盡可能生成性能最佳的二進制檔案。例如,常量傳播可以在編譯時對常量運算式進行求值,避免了運行時的計算開銷;逃逸分析可以避免對區域作用域對 ......

    uj5u.com 2023-06-26 07:57:39 more
  • 記錄一個在寫專案中遇到的Maven依賴無法匯入的問題

    # 記錄一個在寫專案中遇到的Maven依賴無法匯入的問題 專案是一個父專案做依賴管理,三個子專案,今天遇到一個問題: 子專案中匯入的依賴,怎么都匯入不進去,maven倉庫中已經有了,idea提示也沒有問題,如圖: ![](https://img2023.cnblogs.com/blog/295824 ......

    uj5u.com 2023-06-26 07:52:22 more
  • CouchDB教程_編程入門自學教程_菜鳥教程-免費教程分享

    ## 教程簡介 CouchDB 是一個開源的面向檔案的資料庫管理系統,可以通過 RESTful JavaScript Object Notation (JSON) API 訪問。術語 “Couch” 是 “Cluster Of Unreliable Commodity Hardware” 的首字母縮 ......

    uj5u.com 2023-06-26 07:52:12 more
  • B+ tree implemented in Java

    ## B+樹相關介紹 > B+樹是一棵**多叉排序樹**,即每個非葉子節點可以包含多個子節點,其整體結構呈扁平化,所以其非常適配于資料庫和作業系統的檔案系統中。且B+樹能夠保持資料的穩定有序,插入和洗掉都擁有較穩定的**對數時間復雜度**。 **B+樹的特性**:以 m 階為例,m 表示內部節點即非 ......

    uj5u.com 2023-06-26 07:52:08 more
  • 深入Python網路編程:從基礎到實踐

    **Python,作為一種被廣泛使用的高級編程語言,擁有許多優勢,其中之一就是它的網路編程能力。Python的強大網路庫如socket, requests, urllib, asyncio,等等,讓它在網路編程中表現優秀。本文將深入探討Python在網路編程中的應用,包括了基礎的socket編程,到 ......

    uj5u.com 2023-06-26 07:50:53 more
  • celery筆記七之周期/定時任務及crontab定義

    > 本文首發于公眾號:Hunter后端 > 原文鏈接:[celery筆記七之周期/定時任務及crontab定義](https://mp.weixin.qq.com/s/sNShaRbuM2gm2qn_codaTg) periodic task,即為周期,或者定時任務,比如說每天晚上零點零分需要運行一 ......

    uj5u.com 2023-06-26 07:45:03 more
  • 【python基礎】檔案-檔案路徑

    # 1.檔案路徑 我們發現不管是寫入還是寫出操作,我們提供的都是檔案名,其實這里準確說應該是檔案路徑。當我們簡單把檔案名傳遞給open函式時,Python將在當前執行程式的檔案所在的目錄中查找檔案名所代表的檔案。 根據組織檔案的方式,可能需要打開不在當前執行程式檔案所屬目錄中的檔案。如果此時我們把該 ......

    uj5u.com 2023-06-26 07:42:46 more
  • 深入Python網路編程:從基礎到實踐

    **Python,作為一種被廣泛使用的高級編程語言,擁有許多優勢,其中之一就是它的網路編程能力。Python的強大網路庫如socket, requests, urllib, asyncio,等等,讓它在網路編程中表現優秀。本文將深入探討Python在網路編程中的應用,包括了基礎的socket編程,到 ......

    uj5u.com 2023-06-26 07:42:33 more
  • ArcPy批量對大量遙感影像相減做差

    本文介紹基于**Python**中**ArcPy**模塊,對大量柵格遙感影像檔案**批量**進行**相減做差**的方法。 首先,我們來明確一下本文的具體需求。現有一個存盤有多張`.tif`格式遙感影像的檔案夾,其中每一個遙感影像的檔案名中都包含有該影像的成像年份,且每一個遙感影像的空間范圍、像元大小 ......

    uj5u.com 2023-06-26 07:42:24 more