源代碼下載:?learnc-cn.c
C語(yǔ)言在今天仍然是高性能計(jì)算的主要選擇。
C大概是大多數(shù)程序員用到的最接近底層的語(yǔ)言了,C語(yǔ)言原生的速度就很高了,但是別忘了C的手動(dòng)內(nèi)存管理,它會(huì)讓你將性能發(fā)揮到極致。
// 單行注釋以//開(kāi)始。(僅適用于C99或更新的版本。)
/*
多行注釋是這個(gè)樣子的。(C89也適用。)
*/
// 常數(shù): #define 關(guān)鍵詞
#define DAYS_IN_YEAR 365
// 以枚舉的方式定義常數(shù)
enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT};
// MON自動(dòng)被定義為2,TUE被定義為3,以此類推。
// 用#include來(lái)導(dǎo)入頭文件
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// <尖括號(hào)>間的文件名是C標(biāo)準(zhǔn)庫(kù)的頭文件。
// 標(biāo)準(zhǔn)庫(kù)以外的頭文件,使用雙引號(hào)代替尖括號(hào)。
#include "my_header.h"
// 函數(shù)的簽名可以事先在.h文件中定義,
// 也可以直接在.c文件的頭部定義。
void function_1(char c);
void function_2(void);
// 如果函數(shù)出現(xiàn)在main()之后,那么必須在main()之前
// 先聲明一個(gè)函數(shù)原型
int add_two_ints(int x1, int x2); // 函數(shù)原型
// 你的程序的入口是一個(gè)返回值為整型的main函數(shù)
int main() {
// 用printf打印到標(biāo)準(zhǔn)輸出,可以設(shè)定格式,
// %d 代表整數(shù), \n 代表?yè)Q行
printf("%d\n", 0); // => 打印 0
// 所有的語(yǔ)句都要以分號(hào)結(jié)束
///////////////////////////////////////
// 類型
///////////////////////////////////////
// 在使用變量之前我們必須先聲明它們。
// 變量在聲明時(shí)需要指明其類型,而類型能夠告訴系統(tǒng)這個(gè)變量所占用的空間
// int型(整型)變量一般占用4個(gè)字節(jié)
int x_int = 0;
// short型(短整型)變量一般占用2個(gè)字節(jié)
short x_short = 0;
// char型(字符型)變量會(huì)占用1個(gè)字節(jié)
char x_char = 0;
char y_char = 'y'; // 字符變量的字面值需要用單引號(hào)包住
// long型(長(zhǎng)整型)一般需要4個(gè)字節(jié)到8個(gè)字節(jié); 而long long型則至少需要8個(gè)字節(jié)(64位)
long x_long = 0;
long long x_long_long = 0;
// float一般是用32位表示的浮點(diǎn)數(shù)字
float x_float = 0.0;
// double一般是用64位表示的浮點(diǎn)數(shù)字
double x_double = 0.0;
// 整數(shù)類型也可以有無(wú)符號(hào)的類型表示。這樣這些變量就無(wú)法表示負(fù)數(shù)
// 但是無(wú)符號(hào)整數(shù)所能表示的范圍就可以比原來(lái)的整數(shù)大一些
unsigned short ux_short;
unsigned int ux_int;
unsigned long long ux_long_long;
// 單引號(hào)內(nèi)的字符是機(jī)器的字符集中的整數(shù)。
'0' // => 在ASCII字符集中是48
'A' // => 在ASCII字符集中是65
// char類型一定會(huì)占用1個(gè)字節(jié),但是其他的類型卻會(huì)因具體機(jī)器的不同而各異
// sizeof(T) 可以返回T類型在運(yùn)行的機(jī)器上占用多少個(gè)字節(jié)
// 這樣你的代碼就可以在各處正確運(yùn)行了
// sizeof(obj)返回表達(dá)式(變量、字面量等)的尺寸
printf("%zu\n", sizeof(int)); // => 4 (大多數(shù)的機(jī)器字長(zhǎng)為4)
// 如果`sizeof`的參數(shù)是一個(gè)表達(dá)式,那么這個(gè)參數(shù)不會(huì)被演算(VLA例外,見(jiàn)下)
// 它產(chǎn)生的值是編譯期的常數(shù)
int a = 1;
// size_t是一個(gè)無(wú)符號(hào)整型,表示對(duì)象的尺寸,至少2個(gè)字節(jié)
size_t size = sizeof(a++); // a++ 不會(huì)被演算
printf("sizeof(a++) = %zu where a = %d\n", size, a);
// 打印 "sizeof(a++) = 4 where a = 1" (在32位架構(gòu)上)
// 數(shù)組必須要被初始化為具體的長(zhǎng)度
char my_char_array[20]; // 這個(gè)數(shù)組占據(jù) 1 * 20 = 20 個(gè)字節(jié)
int my_int_array[20]; // 這個(gè)數(shù)組占據(jù) 4 * 20 = 80 個(gè)字節(jié)
// (這里我們假設(shè)字長(zhǎng)為4)
// 可以用下面的方法把數(shù)組初始化為0:
char my_array[20] = {0};
// 索引數(shù)組和其他語(yǔ)言類似 -- 好吧,其實(shí)是其他的語(yǔ)言像C
my_array[0]; // => 0
// 數(shù)組是可變的,其實(shí)就是內(nèi)存的映射!
my_array[1] = 2;
printf("%d\n", my_array[1]); // => 2
// 在C99 (C11中是可選特性),變長(zhǎng)數(shù)組(VLA)也可以聲明長(zhǎng)度。
// 其長(zhǎng)度不用是編譯期常量。
printf("Enter the array size: "); // 詢問(wèn)用戶數(shù)組長(zhǎng)度
char buf[0x100];
fgets(buf, sizeof buf, stdin);
// stroul 將字符串解析為無(wú)符號(hào)整數(shù)
size_t size = strtoul(buf, NULL, 10);
int var_length_array[size]; // 聲明VLA
printf("sizeof array = %zu\n", sizeof var_length_array);
// 上述程序可能的輸出為:
// > Enter the array size: 10
// > sizeof array = 40
// 字符串就是以 NUL (0x00) 這個(gè)字符結(jié)尾的字符數(shù)組,
// NUL可以用'\0'來(lái)表示.
// (在字符串字面量中我們不必輸入這個(gè)字符,編譯器會(huì)自動(dòng)添加的)
char a_string[20] = "This is a string";
printf("%s\n", a_string); // %s 可以對(duì)字符串進(jìn)行格式化
/*
也許你會(huì)注意到 a_string 實(shí)際上只有16個(gè)字節(jié)長(zhǎng).
第17個(gè)字節(jié)是一個(gè)空字符(NUL)
而第18, 19 和 20 個(gè)字符的值是未定義。
*/
printf("%d\n", a_string[16]); // => 0
// byte #17值為0(18,19,20同樣為0)
// 單引號(hào)間的字符是字符字面量
// 它的類型是`int`,而 *不是* `char`
// (由于歷史原因)
int cha = 'a'; // 合法
char chb = 'a'; // 同樣合法 (隱式類型轉(zhuǎn)換
// 多維數(shù)組
int multi_array[2][5] = {
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 0}
}
// 獲取元素
int array_int = multi_array[0][2]; // => 3
///////////////////////////////////////
// 操作符
///////////////////////////////////////
// 多個(gè)變量聲明的簡(jiǎn)寫(xiě)
int i1 = 1, i2 = 2;
float f1 = 1.0, f2 = 2.0;
int a, b, c;
a = b = c = 0;
// 算數(shù)運(yùn)算直截了當(dāng)
i1 + i2; // => 3
i2 - i1; // => 1
i2 * i1; // => 2
i1 / i2; // => 0 (0.5,但會(huì)被化整為 0)
f1 / f2; // => 0.5, 也許會(huì)有很小的誤差
// 浮點(diǎn)數(shù)和浮點(diǎn)數(shù)運(yùn)算都是近似值
// 取余運(yùn)算
11 % 3; // => 2
// 你多半會(huì)覺(jué)得比較操作符很熟悉, 不過(guò)C中沒(méi)有布爾類型
// 而是用整形替代
// (C99中有_Bool或bool。)
// 0為假, 其他均為真. (比較操作符的返回值總是返回0或1)
3 == 2; // => 0 (false)
3 != 2; // => 1 (true)
3 > 2; // => 1
3 < 2; // => 0
2 <= 2; // => 1
2 >= 2; // => 1
// C不是Python —— 連續(xù)比較不合法
int a = 1;
// 錯(cuò)誤
int between_0_and_2 = 0 < a < 2;
// 正確
int between_0_and_2 = 0 < a && a < 2;
// 邏輯運(yùn)算符適用于整數(shù)
!3; // => 0 (非)
!0; // => 1
1 && 1; // => 1 (且)
0 && 1; // => 0
0 || 1; // => 1 (或)
0 || 0; // => 0
// 條件表達(dá)式 ( ? : )
int a = 5;
int b = 10;
int z;
z = (a > b) ? a : b; // 10 “若a > b返回a,否則返回b?!?
// 增、減
char *s = "iLoveC"
int j = 0;
s[j++]; // "i" 返回s的第j項(xiàng),然后增加j的值。
j = 0;
s[++j]; // => "L" 增加j的值,然后返回s的第j項(xiàng)。
// j-- 和 --j 同理
// 位運(yùn)算
~0x0F; // => 0xF0 (取反)
0x0F & 0xF0; // => 0x00 (和)
0x0F | 0xF0; // => 0xFF (或)
0x04 ^ 0x0F; // => 0x0B (異或)
0x01 << 1; // => 0x02 (左移1位)
0x02 >> 1; // => 0x01 (右移1位)
// 對(duì)有符號(hào)整數(shù)進(jìn)行移位操作要小心 —— 以下未定義:
// 有符號(hào)整數(shù)位移至符號(hào)位 int a = 1 << 32
// 左移位一個(gè)負(fù)數(shù) int a = -1 << 2
// 移位超過(guò)或等于該類型數(shù)值的長(zhǎng)度
// int a = 1 << 32; // 假定int32位
///////////////////////////////////////
// 控制結(jié)構(gòu)
///////////////////////////////////////
if (0) {
printf("I am never run\n");
} else if (0) {
printf("I am also never run\n");
} else {
printf("I print\n");
}
// While循環(huán)
int ii = 0;
while (ii < 10) { // 任何非0的值均為真
printf("%d, ", ii++); // ii++ 在取值過(guò)后自增
} // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
printf("\n");
int kk = 0;
do {
printf("%d, ", kk);
} while (++kk < 10); // ++kk 先自增,再被取值
// => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
printf("\n");
// For 循環(huán)
int jj;
for (jj=0; jj < 10; jj++) {
printf("%d, ", jj);
} // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
printf("\n");
// *****注意*****:
// 循環(huán)和函數(shù)必須有主體部分,如果不需要主體部分:
int i;
for (i = 0; i <= 5; i++) {
; // 使用分號(hào)表達(dá)主體(null語(yǔ)句)
}
// 多重分支:switch()
switch (some_integral_expression) {
case 0: // 標(biāo)簽必須是整數(shù)常量表達(dá)式
do_stuff();
break; // 如果不使用break,控制結(jié)構(gòu)會(huì)繼續(xù)執(zhí)行下面的標(biāo)簽
case 1:
do_something_else();
break;
default:
// 假設(shè) `some_integral_expression` 不匹配任何標(biāo)簽
fputs("error!\n", stderr);
exit(-1);
break;
}
///////////////////////////////////////
// 類型轉(zhuǎn)換
///////////////////////////////////////
// 在C中每個(gè)變量都有類型,你可以將變量的類型進(jìn)行轉(zhuǎn)換
// (有一定限制)
int x_hex = 0x01; // 可以用16進(jìn)制字面量賦值
// 在類型轉(zhuǎn)換時(shí),數(shù)字本身的值會(huì)被保留下來(lái)
printf("%d\n", x_hex); // => 打印 1
printf("%d\n", (short) x_hex); // => 打印 1
printf("%d\n", (char) x_hex); // => 打印 1
// 類型轉(zhuǎn)換時(shí)可能會(huì)造成溢出,而且不會(huì)拋出警告
printf("%d\n", (char) 257); // => 1 (char的最大值為255,假定char為8位長(zhǎng))
// 使用<limits.h>提供的CHAR_MAX、SCHAR_MAX和UCHAR_MAX宏可以確定`char`、`signed_char`和`unisigned char`的最大值。
// 整數(shù)型和浮點(diǎn)型可以互相轉(zhuǎn)換
printf("%f\n", (float)100); // %f 格式化單精度浮點(diǎn)
printf("%lf\n", (double)100); // %lf 格式化雙精度浮點(diǎn)
printf("%d\n", (char)100.0);
///////////////////////////////////////
// 指針
///////////////////////////////////////
// 指針變量是用來(lái)儲(chǔ)存內(nèi)存地址的變量
// 指針變量的聲明也會(huì)告訴它所指向的數(shù)據(jù)的類型
// 你可以使用得到你的變量的地址,并把它們搞亂,;-)
int x = 0;
printf("%p\n", &x); // 用 & 來(lái)獲取變量的地址
// (%p 格式化一個(gè)類型為 void *的指針)
// => 打印某個(gè)內(nèi)存地址
// 指針類型在聲明中以*開(kāi)頭
int* px, not_a_pointer; // px是一個(gè)指向int型的指針
px = &x; // 把x的地址保存到px中
printf("%p\n", (void *)px); // => 輸出內(nèi)存中的某個(gè)地址
printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer));
// => 在64位系統(tǒng)上打印“8, 4”。
// 要得到某個(gè)指針指向的內(nèi)容的值,可以在指針前加一個(gè)*來(lái)取得(取消引用)
// 注意: 是的,這可能讓人困惑,'*'在用來(lái)聲明一個(gè)指針的同時(shí)取消引用它。
printf("%d\n", *px); // => 輸出 0, 即x的值
// 你也可以改變指針?biāo)赶虻闹?// 此時(shí)你需要取消引用上添加括號(hào),因?yàn)?+比*的優(yōu)先級(jí)更高
(*px)++; // 把px所指向的值增加1
printf("%d\n", *px); // => 輸出 1
printf("%d\n", x); // => 輸出 1
// 數(shù)組是分配一系列連續(xù)空間的常用方式
int x_array[20];
int xx;
for (xx=0; xx<20; xx++) {
x_array[xx] = 20 - xx;
} // 初始化 x_array 為 20, 19, 18,... 2, 1
// 聲明一個(gè)整型的指針,并初始化為指向x_array
int* x_ptr = x_array;
// x_ptr現(xiàn)在指向了數(shù)組的第一個(gè)元素(即整數(shù)20).
// 這是因?yàn)閿?shù)組通常衰減為指向它們的第一個(gè)元素的指針。
// 例如,當(dāng)一個(gè)數(shù)組被傳遞給一個(gè)函數(shù)或者綁定到一個(gè)指針時(shí),
//它衰減為(隱式轉(zhuǎn)化為)一個(gè)指針。
// 例外: 當(dāng)數(shù)組是`&`操作符的參數(shù):
int arr[10];
int (*ptr_to_arr)[10] = &arr; // &arr的類型不是`int *`!
// 它的類型是指向數(shù)組的指針(數(shù)組由10個(gè)int組成)
// 或者當(dāng)數(shù)組是字符串字面量(初始化字符數(shù)組)
char arr[] = "foobarbazquirk";
// 或者當(dāng)它是`sizeof`或`alignof`操作符的參數(shù)時(shí):
int arr[10];
int *ptr = arr; // 等價(jià)于 int *ptr = &arr[0];
printf("%zu, %zu\n", sizeof arr, sizeof ptr); // 應(yīng)該會(huì)輸出"40, 4"或"40, 8"
// 指針的增減多少是依據(jù)它本身的類型而定的
// (這被稱為指針?biāo)阈g(shù))
printf("%d\n", *(x_ptr + 1)); // => 打印 19
printf("%d\n", x_array[1]); // => 打印 19
// 你也可以通過(guò)標(biāo)準(zhǔn)庫(kù)函數(shù)malloc來(lái)實(shí)現(xiàn)動(dòng)態(tài)分配
// 這個(gè)函數(shù)接受一個(gè)代表容量的參數(shù),參數(shù)類型為`size_t`
// 系統(tǒng)一般會(huì)從堆區(qū)分配指定容量字節(jié)大小的空間
// (在一些系統(tǒng),例如嵌入式系統(tǒng)中這點(diǎn)不一定成立
// C標(biāo)準(zhǔn)對(duì)此未置一詞。)
int *my_ptr = malloc(sizeof(*my_ptr) * 20);
for (xx=0; xx<20; xx++) {
*(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx
} // 初始化內(nèi)存為 20, 19, 18, 17... 2, 1 (類型為int)
// 對(duì)未分配的內(nèi)存進(jìn)行取消引用會(huì)產(chǎn)生未定義的結(jié)果
printf("%d\n", *(my_ptr + 21)); // => 誰(shuí)知道會(huì)輸出什么
// malloc分配的區(qū)域需要手動(dòng)釋放
// 否則沒(méi)人能夠再次使用這塊內(nèi)存,直到程序結(jié)束為止
free(my_ptr);
// 字符串通常是字符數(shù)組,但是經(jīng)常用字符指針表示
// (它是指向數(shù)組的第一個(gè)元素的指針)
// 一個(gè)優(yōu)良的實(shí)踐是使用`const char *`來(lái)引用一個(gè)字符串字面量,
// 因?yàn)樽址置媪坎粦?yīng)當(dāng)被修改(即"foo"[0] = 'a'犯了大忌)
const char* my_str = "This is my very own string";
printf("%c\n", *my_str); // => 'T'
// 如果字符串是數(shù)組,(多半是用字符串字面量初始化的)
// 情況就不一樣了,字符串位于可寫(xiě)的內(nèi)存中
char foo[] = "foo";
foo[0] = 'a'; // 這是合法的,foo現(xiàn)在包含"aoo"
function_1();
} // main函數(shù)結(jié)束
///////////////////////////////////////
// 函數(shù)
///////////////////////////////////////
// 函數(shù)聲明語(yǔ)法:
// <返回值類型> <函數(shù)名稱>(<參數(shù)>)
int add_two_ints(int x1, int x2){
return x1 + x2; // 用return來(lái)返回一個(gè)值
}
/*
函數(shù)是按值傳遞的。當(dāng)調(diào)用一個(gè)函數(shù)的時(shí)候,傳遞給函數(shù)的參數(shù)
是原有值的拷貝(數(shù)組除外)。你在函數(shù)內(nèi)對(duì)參數(shù)所進(jìn)行的操作
不會(huì)改變?cè)搮?shù)原有的值。
但是你可以通過(guò)指針來(lái)傳遞引用,這樣函數(shù)就可以更改值
例子:字符串本身翻轉(zhuǎn)
*/
// 類型為void的函數(shù)沒(méi)有返回值
void str_reverse(char *str_in){
char tmp;
int ii = 0;
size_t len = strlen(str_in); // `strlen()`` 是C標(biāo)準(zhǔn)庫(kù)函數(shù)
for(ii = 0; ii < len / 2; ii++){
tmp = str_in[ii];
str_in[ii] = str_in[len - ii - 1]; // 從倒數(shù)第ii個(gè)開(kāi)始
str_in[len - ii - 1] = tmp;
}
}
/*
char c[] = "This is a test.";
str_reverse(c);
printf("%s\n", c); // => ".tset a si sihT"
*/
// 如果引用函數(shù)之外的變量,必須使用extern關(guān)鍵字
int i = 0;
void testFunc() {
extern int i; // 使用外部變量 i
}
// 使用static確保external變量為源文件私有
static int i = 0; // 其他使用 testFunc()的文件無(wú)法訪問(wèn)變量i
void testFunc() {
extern int i;
}
//**你同樣可以聲明函數(shù)為static**
///////////////////////////////////////
// 用戶自定義類型和結(jié)構(gòu)
///////////////////////////////////////
// Typedefs可以創(chuàng)建類型別名
typedef int my_type;
my_type my_type_var = 0;
// struct是數(shù)據(jù)的集合,成員依序分配,按照
// 編寫(xiě)的順序
struct rectangle {
int width;
int height;
};
// 一般而言,以下斷言不成立:
// sizeof(struct rectangle) == sizeof(int) + sizeof(int)
//這是因?yàn)閟tructure成員之間可能存在潛在的間隙(為了對(duì)齊)[1]
void function_1(){
struct rectangle my_rec;
// 通過(guò) . 來(lái)訪問(wèn)結(jié)構(gòu)中的數(shù)據(jù)
my_rec.width = 10;
my_rec.height = 20;
// 你也可以聲明指向結(jié)構(gòu)體的指針
struct rectangle *my_rec_ptr = &my_rec;
// 通過(guò)取消引用來(lái)改變結(jié)構(gòu)體的成員...
(*my_rec_ptr).width = 30;
// ... 或者用 -> 操作符作為簡(jiǎn)寫(xiě)提高可讀性
my_rec_ptr->height = 10; // Same as (*my_rec_ptr).height = 10;
}
// 你也可以用typedef來(lái)給一個(gè)結(jié)構(gòu)體起一個(gè)別名
typedef struct rectangle rect;
int area(rect r){
return r.width * r.height;
}
// 如果struct較大,你可以通過(guò)指針傳遞,避免
// 復(fù)制整個(gè)struct。
int area(const rect *r)
{
return r->width * r->height;
}
///////////////////////////////////////
// 函數(shù)指針
///////////////////////////////////////
/*
在運(yùn)行時(shí),函數(shù)本身也被存放到某塊內(nèi)存區(qū)域當(dāng)中
函數(shù)指針就像其他指針一樣(不過(guò)是存儲(chǔ)一個(gè)內(nèi)存地址) 但卻可以被用來(lái)直接調(diào)用函數(shù),
并且可以四處傳遞回調(diào)函數(shù)
但是,定義的語(yǔ)法初看令人有些迷惑
例子:通過(guò)指針調(diào)用str_reverse
*/
void str_reverse_through_pointer(char *str_in) {
// 定義一個(gè)函數(shù)指針 f.
void (*f)(char *); // 簽名一定要與目標(biāo)函數(shù)相同
f = &str_reverse; // 將函數(shù)的地址在運(yùn)行時(shí)賦給指針
(*f)(str_in); // 通過(guò)指針調(diào)用函數(shù)
// f(str_in); // 等價(jià)于這種調(diào)用方式
}
/*
只要函數(shù)簽名是正確的,任何時(shí)候都能將任何函數(shù)賦給某個(gè)函數(shù)指針
為了可讀性和簡(jiǎn)潔性,函數(shù)指針經(jīng)常和typedef搭配使用:
*/
typedef void (*my_fnp_type)(char *);
// 實(shí)際聲明函數(shù)指針會(huì)這么用:
// ...
// my_fnp_type f;
// 特殊字符
'\a' // bell
'\n' // 換行
'\t' // tab
'\v' // vertical tab
'\f' // formfeed
'\r' // 回車
'\b' // 退格
'\0' // null,通常置于字符串的最后。
// hello\n\0\. 按照慣例,\0用于標(biāo)記字符串的末尾。
'\\' // 反斜杠
'\?' // 問(wèn)號(hào)
'\'' // 單引號(hào)
'\"' // 雙引號(hào)
'\xhh' // 十六進(jìn)制數(shù)字. 例子: '\xb' = vertical tab
'\ooo' // 八進(jìn)制數(shù)字. 例子: '\013' = vertical tab
// 打印格式:
"%d" // 整數(shù)
"%3d" // 3位以上整數(shù) (右對(duì)齊文本)
"%s" // 字符串
"%f" // float
"%ld" // long
"%3.2f" // 左3位以上、右2位以上十進(jìn)制浮
"%7.4s" // (字符串同樣適用)
"%c" // 字母
"%p" // 指針
"%x" // 十六進(jìn)制
"%o" // 八進(jìn)制
"%%" // 打印 %
///////////////////////////////////////
// 演算優(yōu)先級(jí)
///////////////////////////////////////
//---------------------------------------------------//
// 操作符 | 組合 //
//---------------------------------------------------//
// () [] -> . | 從左到右 //
// ! ~ ++ -- + = *(type)sizeof | 從右到左 //
// * / % | 從左到右 //
// + - | 從左到右 //
// << >> | 從左到右 //
// < <= > >= | 從左到右 //
// == != | 從左到右 //
// & | 從左到右 //
// ^ | 從左到右 //
// | | 從左到右 //
// && | 從左到右 //
// || | 從左到右 //
// ?: | 從右到左 //
// = += -= *= /= %= &= ^= |= <<= >>= | 從右到左 //
// , | 從左到右 //
//---------------------------------------------------//
最好找一本?K&R, aka “The C Programming Language”, “C程序設(shè)計(jì)語(yǔ)言”。它是關(guān)于C最重要的一本書(shū),由C的創(chuàng)作者撰寫(xiě)。不過(guò)需要留意的是它比較古老了,因此有些不準(zhǔn)確的地方。
另一個(gè)比較好的資源是?Learn C the hard way
如果你有問(wèn)題,請(qǐng)閱讀compl.lang.c Frequently Asked Questions。
使用合適的空格、縮進(jìn),保持一致的代碼風(fēng)格非常重要。可讀性強(qiáng)的代碼比聰明的代碼、高速的代碼更重要??梢詤⒖枷?a rel="external nofollow" target="_blank" target="_blank">Linux內(nèi)核編碼風(fēng)格?。 除了這些,多多Google吧
更多建議: