1.typedef:型別重命名
一切合法的變數名的定義(普通變數、指標變數、陣列變數、函式指標、結構體)都可以用typedef轉換成型別名
加typedef之前
unsigned int UINT; //普通變數
int* PINT; //指標變數
int Array[10]; //陣列變數
void (*pfun)(); //函式指標
struct Student stu; //定義結構體變數stu
struct Student *pstu;//定義結構體指標pstu
加上typedef之后
typedef unsigned int UINT; //UINT型別名
typedef int* PINT; //PINT指標型別名
typedef int Array[10]; //Array陣列型別名
typedef void (*pfun)(); //函式指標型別名
typedef struct Student stu; //stu型別
//使用stu s1;
typedef struct Student *pstu; //結構體指標型別
//使用:pstu p1 = NULL;
(1)給已有的型別名起別名
typedef unsigned char u_int8;
typedef unsigned short u_int16;
typedef unsigned int u_int32;
typedef unsigned double u_int64;
(2)對已有的宣告,變數名的定義加上typedef 變成型別名
#include <stdio.h>
typedef int Arr[10];
int main()
{
Arr a = { 1, 2, 3, 4, 5 };
for (int i = 0; i < 5; i++)
{
printf("%4d ", a[i]);
}
printf("\n");
}
結果:

結構體經典寫法:
#include <stdio.h>
struct Student
{
...;
}stu, *pstu;
//這樣是定義了stu結構體變數和pstu結構體變數指標
//前面加上typedef后
typedef struct Student
{
...;
}stu, *pstu;
//stu便成了自定義的結構體型別
//pstu變成了自定義的結構體指標的型別
//從而可以使用該型別進行定義變數
2.請問p和q的型別
int* p, q;
結果:
*和變數名結合,不是與型別名結合,所以p是int指標型別,q是int型別;

結合1,想同時定義p和q兩個指標:
#include <stdio.h>
typedef int *PTR;
int main()
{
PTR p,q;
return 0;
}
結果:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iHyypOrk-1635073955441)(C:\Users\小小怪咯\AppData\Roaming\Typora\typora-user-images\image-20211014154707137.png)]](https://img.uj5u.com/2021/10/26/277717260733272.png)
3.關鍵字sizeof
- sizeof是一個關鍵字,在編譯期間確定型別和大小;
#include <stdio.h>
int main()
{
int a = 0;
int x;
//在編譯期確定
x = sizeof(++a);
//等價于x = 4;
printf("a = %d\n", a);
return 0;
}
//結果a = 0
- sizeof和strlen()的區別
-
呼叫時機不同:sizeof是關鍵字,編譯期間確定型別和大小
? strlen()是函式,在運行期間呼叫函式
-
功能不同:strlen()是專門計算字串的長度;
? sizeof在計算字串所占用的空間大小;
char buff[] = {"helloworld"};
int len = strlen(buff); //len = 10;
int size = sizeof(buff); // size = 11;
4、進制數轉換的貪心演算法
博客
5、c/c++的常變數不同側重點
vs2019的全域變數未初始化默認為0,區域變數未初始化是隨機值,使用該值編譯不通過
-
c中的常變數側重與"變數",不能使用常變數定義陣列,編譯期不通過;
-
c++中的常變數側重于"常",可以使用該常變數定義陣列;
-
C++常變數類似于宏,卻有不同與宏
- 編譯時期不同
- 與宏有所不同:宏在預編譯時進行宏替換;使用常變數定義陣列是在編譯期進行確定的;
- 是否存在型別和占用空間
- 宏不存在型別,不占用空間
- 常變數有型別,占用空間
- 安全性
- 宏不存在型別,沒有型別檢查,不安全
- 常變數有資料型別,有型別檢查,比較安全
- 編譯時期不同
6、’ ’ 和" "
’ ‘是字符的定界符, 在’前面加上\后轉義變成單引號字符–》\’
例如:
char ch = '''; //error ''是定界符,想使用單引號字符需要轉義
char ch = '\''; //true
""是字串的定界符
7、ascii碼值
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-guE4NOl4-1635073955442)(C:\Users\小小怪咯\AppData\Roaming\Typora\typora-user-images\image-20211023171614795.png)]](https://img.uj5u.com/2021/10/26/277717260733274.png)
8、轉義字符

9、關于0 ‘0’ ‘\0’
int main()
{
char cha = 0; //ASCII值為0對應的字符就是空字符
char chb = '0'; //字符0對應的ASCII值48
char chc = '\0'; //等于cha == 》空字符
char chd = ' '; //空格字符ascii值是32
return 0;
}
10、關于\000 和\xff
\000將八進制數000轉換成十進制對應的ascii碼值,碼值對應的字符;
- 其中八進制數有效范圍000~377,因為char一位元組最大取值255,其對應的八進制數就是377;八進制數超出該范圍編譯器就會報錯
char str[] = {"pzj\141hello"};
//八進制的141轉換成十進制的97 //pzjahello
//如果是"pzj\1411hello" //pzja1hello
//如果是"pzj\148hello" //只會轉義\14因為8超出0~7
//如果是"pzj\889hello" //此時的\就會被省略
int len = strlen(str); //len = 9
\x00將十六進制的00轉換成十進制對應的ASCII碼值,碼值對應的字符;
-
其中十六進制數的有效范圍是0~ff,因為char最大255,對應的十六進制數就是ff;十六進制數超出該范圍也會報錯
char str[] = {"hello\61xworld"}; //helloaworld
10、字串與\0
字串的printf("%s")列印、strcpy拷貝、strcat連接、等函式都是以字串的\0作為結束條件
char str[] = {"hello\0world"};
int size = sizeof(str); //size = 12
int len = strlen(str); //len = 5
printf("%s\n", str); //hello
11、宏和字串
#define MAX 1000
int main()
{
char str[] = {"helloMAX"};
printf("%s\n", str); //helloMAX
}
- 原因:MAX是字串的一部分,不是識別符號,不會被宏替換
12、char ch = 'abcd’問題
C++有一個叫做“多字符文字”的東西,'1234'就是一個例子,他們有型別int,它是實作–定義了它們所具有的值以及它們可以包含多少字符,
那算不了什么直接與字符被表示為整數的事實有關,但在實作中,很有可能'1234'定義為:
'1' + 256 * '2' + 256 * 256 * '3' + 256 * 256 * 256 * '4'
或:
'4' + 256 * '3' + 256 * 256 * '2' + 256 * 256 * 256 * '1'
13、作用域(可見性)和生存期
- 作用域:針對的是編譯和鏈接的程序
- 函式、全域變數從定義起(整個檔案可見)全域可見,沒有區域函式一說
- 生存期(生命期):針對的是程式的執行程序
- 區域變數的生存周期:函式被呼叫開始,函式執行結束時消亡,釋放存盤空間,存盤在.stack區
- 全域變數的生存期:從程式開始運行時開始,到程式執行結束時結束,存盤在.data區
- 動態生命期(堆區空間):識別符號由特定的函式呼叫或運算來創建和釋放,如果呼叫malloc()為變數分配存盤空間開始,free()釋放存盤空間結束,存盤在堆區.heap
編譯錯誤:g_value未定的識別符號
#include <stdio.h>
void Test()
{
int a = g_value;
}
int g_value = 10;
int main()
{
Test();
return 0;
}
錯誤理解:誤認為程式一邊編譯一邊運行,g_value存在于.data段
14、C語言運算子優先級
| 優先級 | 運算子 | 名稱或含義 | 使用形式 | 結合方向 | 說明 |
|---|---|---|---|---|---|
| 1 | [] | 陣列下標 | 陣列名[常量運算式] | 左到右 | |
| () | 圓括號 | (運算式) 函式名(形參表) | |||
| . | 成員選擇(物件) | 物件.成員名 | |||
| -> | 成員選擇(指標) | 物件指標->成員名 | |||
| 2 | - | 負號運算子 | -運算式 | 右到左 | 單目運算子 |
| (型別) | 強制型別轉換 | (資料型別)運算式 | |||
| ++ | 自增運算子 | ++變數名 變數名++ | 單目運算子 | ||
| – | 自減運算子 | –變數名 變數名– | 單目運算子 | ||
| * | 取值運算子 | *指標變數 | 單目運算子 | ||
| & | 取地址運算子 | &變數名 | 單目運算子 | ||
| ! | 邏輯非運算子 | !運算式 | 單目運算子 | ||
| ~ | 按位取反運算子 | ~運算式 | 單目運算子 | ||
| sizeof | 長度運算子 | sizeof(運算式) | |||
| 3 | / | 除 | 運算式 / 運算式 | 左到右 | 雙目運算子 |
| * | 乘 | 運算式*運算式 | 雙目運算子 | ||
| % | 余數(取模) | 整型運算式%整型運算式 | 雙目運算子 | ||
| 4 | + | 加 | 運算式+運算式 | 左到右 | 雙目運算子 |
| - | 減 | 運算式-運算式 | 雙目運算子 | ||
| 5 | << | 左移 | 變數<<運算式 | 左到右 | 雙目運算子 |
| >> | 右移 | 變數>>運算式 | 雙目運算子 | ||
| 6 | > | 大于 | 運算式>運算式 | 左到右 | 雙目運算子 |
| >= | 大于等于 | 運算式>=運算式 | 雙目運算子 | ||
| < | 小于 | 運算式<運算式 | 雙目運算子 | ||
| <= | 小于等于 | 運算式<=運算式 | 雙目運算子 | ||
| 7 | == | 等于 | 運算式==運算式 | 左到右 | 雙目運算子 |
| != | 不等于 | 運算式!= 運算式 | 雙目運算子 | ||
| 8 | & | 按位與 | 運算式&運算式 | 左到右 | 雙目運算子 |
| 9 | ^ | 按位異或 | 運算式^運算式 | 左到右 | 雙目運算子 |
| 10 | | | 按位或 | 運算式|運算式 | 左到右 | 雙目運算子 |
| 11 | && | 邏輯與 | 運算式&&運算式 | 左到右 | 雙目運算子 |
| 12 | || | 邏輯或 | 運算式||運算式 | 左到右 | 雙目運算子 |
| 13 | ?: | 條件運算子 | 運算式1? 運算式2: 運算式3 | 右到左 | 三目運算子 |
| 14 | = | 賦值運算子 | 變數=運算式 | 右到左 | |
| /= | 除后賦值 | 變數/=運算式 | |||
| *= | 乘后賦值 | 變數*=運算式 | |||
| %= | 取模后賦值 | 變數%=運算式 | |||
| += | 加后賦值 | 變數+=運算式 | |||
| -= | 減后賦值 | 變數-=運算式 | |||
| <<= | 左移后賦值 | 變數<<=運算式 | |||
| >>= | 右移后賦值 | 變數>>=運算式 | |||
| &= | 按位與后賦值 | 變數&=運算式 | |||
| ^= | 按位異或后賦值 | 變數^=運算式 | |||
| |= | 按位或后賦值 | 變數|=運算式 | |||
| 15 | , | 逗號運算子 | 運算式,運算式,… | 左到右 |
易錯點:
int main()
{
int a = 1, b = 2;
a *= b + 5; //+的優先級高于 *= 所以 a = a * (b + 5) --> a = 7
printf("%d\n", a); //7
}
15、指標存盤——小端存盤
小端存盤:高位數存放在高地址,低位數存放在低地址;
數值存盤和地址存盤都遵循小端存盤

16、標準輸入檔案0、標準輸出檔案1、標準錯誤輸出檔案2
當一個程式開始運行時,默認會打開這三個檔案;
- 標準輸入檔案stdin:對應的檔案描述符為0,通過某種映射關系將鍵盤輸入映射成標準輸入檔案;stdin在記憶體上是有行緩沖區的,當遇到換行(’\n’)才會輸入到緩沖區;
- 標準輸出檔案stdout:對應的檔案描述符為1,通過某種映射關系將螢屏輸出映射成標準輸出檔案;stdout在記憶體上是有行緩沖區的,當遇到換行(’\n’)才會輸出到螢屏;
- 標準錯誤檔案stderr:對應的檔案描述符為2,是無緩沖區的,是直接輸出在螢屏上;
程式案例:從鍵盤獲取字符輸出字符個數
17、宏和typedef
#define PINT int* //宏替換,不考慮型別和大小
typedef int* TINT; //型別重命名,會進行型別和大小識別
int main()
{
PING a, b; //int* a, b;
TINT p, q; //int* p; int* q;
}
18、extern關鍵字
extern用在全域變數或者函式的宣告之前,用來說明“此變數、函式是在別處定義的,要在此處參考”;
使用情景:同一個工程下的不同檔案
檔案fun.c
int g_max = 10;
void fun()
{
g_max +=10;
printf("%d\n", g_max);
}
檔案main.c
#include <stdio.h>
extern int g_max;
extern void fun();
int main()
{
int a = g_max;
fun();
}
C++中的extern的其他用法;
19、static關鍵字的使用
記憶函式:該函式中含有靜態區域變數;
靜態區域變數:當函式第一次被呼叫,函式中的區域靜態變數被初始化,當這個函式被再次呼叫時,不會對該靜態變數進行初始化,會保留上次函式執行結束后區域變數的值(作用域不變,生存期改變)
-
注意:C語言的靜態區域變數只能用常量進行初始化一次;
? C++可以用常量和變數進行初始化一次
問題解答:
-
形參能否加上static
答:加上,編譯通過,但是該變數是一個“壞”存盤類;
所以形參不加static
-
記憶函式是怎樣實作第一次初始化的時候呼叫,后面不呼叫?
答:在編譯階段,編譯器將記憶函式中的靜態區域變數存放在.data段中并給該變數一個記錄值val = 1,當程式執行到定義靜態區域變數的陳述句時,先對記錄值進行判斷,如果val == 1說明第一次呼叫,執行完畢后val–;否則val == 0 ,則跳過這條陳述句;

- 注意:static int a = 10; 在多執行緒中需要考慮執行緒安全,多個執行緒同時執行該條陳述句,該值其中的val值會被同時拿到,這樣就可能會多次執行該陳述句,單例模式的問題就需要考慮執行緒安全
靜態全域變數:靜態全域變數只能在當前檔案中使用(作用域受限制,生存期不變)
-
注意1:當全域變數、函式加上static后,作用域受限于本檔案,其他檔案無法訪問;就算其他檔案加上extern關鍵字宣告也無法使用
main.c檔案
#include <stdio.h>
extern int g_max;
extern void fun();
int main()
{
int a = g_max; //編譯報錯,無法決議的命令g_max
fun();
return 0;
}
fun.c檔案
static int g_max = 10;
static void fun()
{
printf("%d\n", g_max);
}
注意2:希望fun.c檔案中的const int a = 10; 常變數被其他檔案呼叫,就在該變數定義前加上extern,同時使用的檔案也要加上該變數的extern宣告
main.c檔案
#include <stdio.h>
extern int g_max;
int main()
{
int a = g_max;
printf("%d\n", a);
return 0;
}
fun.c檔案
extern const int g_max = 10; //外部可見的常變數
? //extern static int g_max = 10;
? //extern外部可見與static本檔案可見矛盾
靜態函式:static說明的函式字可以在當前c檔案中使用(作用域受限,生存期不變)
20、4G的虛擬空間

21、資料在記憶體中存放的位置
#include <stdio.h>
int g_maxa = 10
int g_maxb;
int g_maxc = 0;
static int g_maxd; //默認是0
static int g_maxe = 0;
static int g_maxf = 10;
int main()
{
int maxa = 10
int maxb;
int maxc = 0;
static int maxd;
static int maxe = 0;
static int maxf = 10;
}
22、const修飾定義的變數和#define宏替換的區別(見5)
-
處理物件不同:const修飾的是定義的變數,而宏替換定義的是常量
-
處理時期不同:const修飾的變數是在編譯期間確定,宏替換是在預編譯期進行替換;
-
是否占用空間和有型別:const修飾的變數有大小和型別,宏替換的常量不占空間、不具有型別檢查
23、淺談宏函式
就是單純的替換
#include <stdio.h>
#define SUM(x, y) x*y
int main()
{
int a = 3, b = 4;
int c = SUM(a + 1, b + 2);
//int c = a+1*b+2
printf("%d\n", c);
return 0;
}
//
解決方案
/
#define SUM(x, y) (x)*(y)
哼哼~啊啊啊啊啊~結束啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦!!!!!!!!!!!!!!!!!!!!!!!!!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/336180.html
標籤:其他
上一篇:晚上8點在地鐵上收到boss需求:把400多張表的關系畫出來明早客戶要!
下一篇:Linux精簡教程
