翁恺老师的c语言学习笔记
翁愷老師講的超級好,人也超級可愛,b站的彈幕也很可愛。
運算符
前綴后綴
關(guān)系運算符(比較)
所有關(guān)系運算符的優(yōu)先級比算術(shù)運算符的低,比賦值運算符的高。
e.g. 7>=3+4
int a=r>0
判斷是否相等的 == 和 != 的優(yōu)先級比其他的低,而連續(xù)的關(guān)系運算是從左到右進(jìn)行的。
5>3 == 6>4
6>5>4 結(jié)果為0
a == b == 6
a == b > 0
級聯(lián)的if-else
if()
str;
else if()
str;
else
str;
(對齊寫,格式好看)
多路分支switch-case
case是開始的地方,break是結(jié)束的地方。
隨機數(shù) srand(time(0))
time是C語言獲取當(dāng)前系統(tǒng)時間的函數(shù),以秒作單位,代表當(dāng)前時間自Unix標(biāo)準(zhǔn)時間戳(1970年1月1日0點0分0秒,GMT)經(jīng)過了多少秒。
形式為time_t time(time_t * t);
該函數(shù)提供兩種返回方式,返回值,和指針參數(shù)。
可以根據(jù)需要選擇。當(dāng)參數(shù)t為空指針(NULL)時,只返回值。
而NULL的定義是(void *) 0, 所以time(0)也就是time(NULL)的另一種寫法,表示只通過返回值獲取時間值。
如果得到的數(shù)太大,則可以a%100,范圍會在0~99。
break和continue 從嵌套的循環(huán)中跳出
break和continue只能對他所在的那層循環(huán)使用。怎么跳出三重循環(huán)?(1)接力break:設(shè)置標(biāo)志,滿足標(biāo)志為1時,每個循環(huán)都有一個break;(2)goto:goto out; out: 程序跳到out所在位置。
-1的n次方
如果在循環(huán)中,可以初始sign=1,循環(huán)中每次sign=-sign。
整數(shù)分解
(1)先逆序(c*10+b)*10+a再從右開始輸出,但不適合700這種末尾有0的數(shù)字,結(jié)果只為7,而不是700。
(2)先計算這個整數(shù)的位數(shù)cnt,構(gòu)造mask=pow(10,cnt-1),d=a/mask, a=a%mask, mask/=10,循環(huán)以mask為判定條件。注意邊界值和特殊值。
左對齊 %-10d
sizeof() 某個類型或變量占據(jù)的字節(jié)數(shù)
sizeof是靜態(tài)運算符,它的結(jié)果在編譯時刻就決定了;
不要在sizeof的括號里做運算,這些運算不會做的。
整數(shù)類型
●char: 1字節(jié)(8比特) -128~127(默認(rèn)補碼)
●short: 2字節(jié) -32768~32767
●int: 取決于編譯器(CPU) ,通常的意義是“1個字”(字長)-232-1~232-1-1
●long:取決于編譯器(CPU), 通常的意義是“1個字”
●long long: 8字節(jié)
字長:
補碼
補碼加原碼得到溢出的0。對于-a,其補碼就是(1)0-a,實際是2n- a,n是這種類型的位數(shù)。
8位:
00000000 -> 0
11111111 ~ 10000000 -> -1 ~ -128
00000001 ~ 01111111 -> 1 ~127
unsigned
如果一個字面量常數(shù)想要表達(dá)自己是unsigned,可以
在后面加u或U,e.g.255U。
用I或L表示long(long)。
*unsigned的初衷并非擴(kuò)展數(shù)能表達(dá)的范圍,而是為
了做純二進(jìn)制運算,主要是為了移位。
整數(shù)的輸入輸出
只有兩種形式: int或long long
%d: int
%u: unsigned
%ld: long long
%lu: unsigned long long
8進(jìn)制和16進(jìn)制
一個以0開始的數(shù)字字面量是8進(jìn)制
一個以0x開始的數(shù)字字面量是16進(jìn)制
%o用于8進(jìn)制,%x用于16進(jìn)制
8進(jìn)制和16進(jìn)制只是如何把數(shù)字表達(dá)為字符串,與內(nèi)部如何表達(dá)數(shù)字無關(guān)
浮點類型
浮點的輸入輸出
計算機能表示的數(shù)是離散的,導(dǎo)致某些數(shù)不能精確表示,只能用相近的數(shù)表示。
printf輸出inf表示超過范圍的浮點數(shù):+∞、-∞
printf輸出nan表示不存在的浮點數(shù)
inf: -12.0/0.0 +12.0/0.0(浮點數(shù)的設(shè)定可以) 12/0(編譯不通過)
nan:0.0/0.0
帶小數(shù)點的字面量是double而非float,float需要用f或F后綴來表明身份。
怎么判斷兩個浮點數(shù)是否相等:
f1==f2可能失敗
fabs(f1-f2) < 1e-12 (float用1e-8就可以了)
選擇浮點類型:
如果沒有特殊需要,只使用double,
現(xiàn)代CPU能直接對double做硬件運算。
算錢錢
不能用浮點數(shù)算錢錢,可以看作整數(shù)(元角分)來做運算。
強制類型轉(zhuǎn)換
(int)3.9001
(int)(1.0/3.0) 強制類型轉(zhuǎn)換的優(yōu)先級高于四則運算。
a<b<c
像4<x< 6這樣的式子,不是C能正確計算的式子,因為4< x的
結(jié)果是一個邏輯值(0或1)。
優(yōu)先級
短路
所以,不要把賦值,包括復(fù)合賦值組合進(jìn)表達(dá)式。
參數(shù)傳遞
C語言在調(diào)用函數(shù)時,永遠(yuǎn)只能 傳值(而不是變量) 給函數(shù)。
傳值:每個函數(shù)有自己的變量空間,參數(shù)也位于這個獨立的空間中,和其他函數(shù)沒有關(guān)系。
本地變量(塊)
本地變量是定義在塊內(nèi)的,它可以是定義在函數(shù)的塊內(nèi),也可以定義在語句的塊內(nèi),甚至可以隨便拉一 對大括號來定義變量。
程序運行進(jìn)入這個塊之前,其中的變量不存在,離開這個塊,其中的變量就消失了。
塊外面定義的變量在里面仍然有效。
塊里面定義了和外面同名的變量則掩蓋了外面的。
main函數(shù)
return 0 是有意義的,有些人需要這個結(jié)果,表示正確執(zhí)行。
數(shù)組下標(biāo)
聲明數(shù)組時,c99以前是只能是常量,c99是支持下標(biāo)是變量的,只是vs2015不支持。但數(shù)量一旦確定就不再更改。
數(shù)組初始化
數(shù)組的大小
sizeof(a)給出的是整個數(shù)組所占據(jù)的大小,單位是字節(jié)。
數(shù)組大小:sizeof(a)/sizeof(a[0])
數(shù)組作為函數(shù)參數(shù)時
數(shù)組作為函數(shù)參數(shù)時,往往必須再用另一個參數(shù)來傳入數(shù)組的大小。
數(shù)組作為函數(shù)的參數(shù)時: 不能在[ ]中給出數(shù)組的大小,不能再利用sizeof來計算數(shù)組的元素個數(shù)!
構(gòu)造素數(shù)的多種方法
數(shù)組例子:素數(shù)
二維數(shù)組的初始化
32.取地址運算
&運算符取得變量的地址。它的操作數(shù)必須是變量。
指針
指針變量就是記錄地址的變量。
訪問那個地址上的變量 * :
* 是一個單目運算符,用來訪問指針的值所表示的地址上的變量,可以做右值也可以做左值。
左值
指針最常見的錯誤:定義了指針變量,還沒有指向任何變量,就開始使用指針。
int *p;
*p=10; 錯誤,要先給p賦予值,即它指向的地址。
指針和const
指針本身和所指的變量都可能const。
指針是const:
所指是const:
const數(shù)組
●數(shù)組變量是const的指針,所以不能被賦值。
int b[]=a;//錯誤
int a[] <==> int* const a=…
p+1
p+1相當(dāng)于p+sizeof(類型)。
給一個指針加1表示要讓指針指向下一個變量。
那么*(p+n) <-> a[n]
*p++
0地址
動態(tài)內(nèi)存分配
C99可以用變量做數(shù)組定義的大小,C99之前呢?
如果內(nèi)存分配失敗會返回0或NULL。
free只能還申請來的空間的首地址。
字符數(shù)組:char word[] = {'H','e','l','l',‘o','!'};
字符串:char word[] = {'H','e','l','l', 'o','!','\0'};
字符串:
字符串變量:
\0不是字符串的一部分但是占據(jù)數(shù)組的一個字節(jié)。
C語言的字符串是以字符數(shù)組的形態(tài)存在的,不能用運算符對字符串做運算,通過數(shù)組的方式可以遍歷字符串。
唯一特殊的地方是字符串字面量可以用來初始化字符數(shù)組。
以及標(biāo)準(zhǔn)庫提供了一系列字符串函數(shù)。
字符串常量:
指針還是數(shù)組:
如果要構(gòu)造一個字符串->數(shù)組
如果要處理一個字符串->指針
在%和s之間的數(shù)字表示最多允許讀入的字符的數(shù)量,這個數(shù)字應(yīng)該比數(shù)組的大小小1。
vs中不支持%7s這種寫法,應(yīng)
常見錯誤:
指針不知道指向哪里了。
putchar:
getchar:
strlen:返回s的字符串長度(不包括結(jié)尾的0)。
strcmp:比較兩個字符串,返回:
●0: s1==s2
●1: s1>s2
●-1: s1<s2
strcpy:
strcat:
安全問題:strcpy和strcat都可能出現(xiàn)安全問題,如果目的地沒有足夠的空間?
安全版本:
字符串中找字符:
字符串中找字符串:
聲明:enum color c; //enum不能少
小技巧:
這樣需要遍歷所有的枚舉量或者需要建立一個用枚舉量做下標(biāo)的數(shù)組的時候就很方便了。
聲明枚舉量的時候可以指定值。
如果有意義上排比的名字,用枚舉比const int方便。
枚舉比宏(macro) 好,因為枚舉有int類型。
結(jié)構(gòu)可以做賦值運算,s1=s2。
結(jié)構(gòu)作為函數(shù)參數(shù):
整個結(jié)構(gòu)可以作為參數(shù)的值傳入函數(shù);這時候是在函數(shù)內(nèi)新建一個結(jié)構(gòu)變量, 并復(fù)制調(diào)用者的結(jié)構(gòu)的值;也可以返回一個結(jié)構(gòu);這與數(shù)組完全不同。
輸入結(jié)構(gòu):
沒有直接的方式可以一次scanf一個結(jié)構(gòu)。
一個小問題:
結(jié)構(gòu)體是函數(shù)參數(shù)時,傳入函數(shù)的是外面那個結(jié)構(gòu)的克隆體,而不是指針。那么主函數(shù)怎么得到結(jié)構(gòu)體的值呢?(1)在這個調(diào)用的函數(shù)中,完全可以創(chuàng)建一個臨時的結(jié)構(gòu)變量,然后把這個結(jié)構(gòu)返回給調(diào)用者。return s;
(2)(更好)結(jié)構(gòu)指針作為參數(shù)。但是函數(shù)還是可以寫成返回這個指針,即函數(shù)是struct date* 類型,這樣可以方便進(jìn)入別的計算。
用->表示指針所指的結(jié)構(gòu)變量中的成員。
自定義數(shù)據(jù)類型typedef
C語言提供了一個叫做typedef的功能來聲明一個已有的數(shù)據(jù)類型的新名字。
聯(lián)合union
存儲:
所有的成員共享一個空間;同一時間只有一個成員是有效的;union的大小是其最大的成員。
sizeof (union)=sizeof (每個成員)的最大值
初始化:
對第一個成員做初始化。
_func_ ,輸出用%s ,表示當(dāng)前函數(shù)的名字。
全局變量
初始化:
沒有做初始化的全局變量會得到0值;指針會得到NULL值;只能用編譯時刻已知的值來初始化全局變量;它們的初始化發(fā)生在main函數(shù)之前。
被隱藏的全局變量:
如果函數(shù)內(nèi)部存在與全局變量同名的變量,則全局變
量被隱藏。
靜態(tài)本地變量static:能在函數(shù)結(jié)束后繼續(xù)保有原值的本地變量
在本地變量定義時加上static修飾符就成為靜態(tài)本地變量;
當(dāng)函數(shù)離開的時候,靜態(tài)本地變量會繼續(xù)存在并保持其值;
靜態(tài)本地變量的初始化只會在第一次進(jìn)入這個函數(shù)時做,以后進(jìn)入函數(shù)時會保持上次離開時的值。
實質(zhì):
靜態(tài)本地變量實際上是特殊的全局變量,它們位于相同的內(nèi)存區(qū)域。靜態(tài)本地變量具有全局的生存期,函數(shù)內(nèi)的局部作用域,static在這里的意思是局部作用域(本地可訪問)。
返回指針的函數(shù)
●返回本地變量的地址是危險的,已經(jīng)不可控。
●返回全局變量或靜態(tài)本地變量的地址是安全的。
●返回在函數(shù)內(nèi)malloc的內(nèi)存是安全的,但是容易造成問題。
●最好的做法是返回傳入的指針。
tips:
不要使用全局變量來在函數(shù)間傳遞參數(shù)和結(jié)果;
使用全局變量和靜態(tài)本地變量的函數(shù)是線程不安全的。
#開頭的是編譯預(yù)處理指令,它們不是C語言的成分,但是C語言程序離不開它們。
#define用來定義一個宏。
預(yù)定義的宏:
一切都要括號:
●整個值要括號
●參數(shù)出現(xiàn)的每個地方都要括號
為什么?
注意:#define 結(jié)束一定不要加分號。
●在使用和定義這個函數(shù)的地方都應(yīng)該#include這個頭文件。
●一般的做法就是任何.c都有對應(yīng)的同名的.h,把所有對外公開的函數(shù)的原型和全局變量的聲明都放進(jìn)去。
不對外公開的函數(shù):
在.h文件中加入變量的聲明。
這個有疑惑(只把聲明寫在頭文件)就去收藏夾(小疑惑)。
標(biāo)準(zhǔn)頭文件結(jié)構(gòu):
p112 聲明
printf:%[flags][width][.prec][hlL]type
所以這里的6可以替換為一個變量。
%n:
scanf:%[flag]type
文件輸入輸出
打開文件的標(biāo)準(zhǔn)代碼:
按位異或
左移<<
右移>>:
可變數(shù)組
可變數(shù)組的缺陷:1. 擴(kuò)容時每次復(fù)制浪費時間;2. 萬一想要擴(kuò)容,卻沒有更大的內(nèi)存了。由此引入鏈表。
在p125鏈表的函數(shù)中注意的點
指針做函數(shù)參數(shù)時,在函數(shù)內(nèi)部做運算時,指針?biāo)傅膬?nèi)容可以被修改,但修改指針本身(使指針指向別處)不會影響外部的指針。
p125鏈表的函數(shù)
任何在“->”左邊的指針必須check,是否為空。
圖形交互
總結(jié)
以上是生活随笔為你收集整理的翁恺老师的c语言学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一种通感一体化的信号设计与性能分析
- 下一篇: jquery 获取系统默认年份_你没有看