原文:c++ 容易忘的基本語法和特性
標準 c++ 中容易忘記但比較重要和常用的基本語法和特性
這是 c++ 或 c in c++,而不一定是傳統 c 語言的語法和特性
零 0字面量 0 是基本型別自動適應的,指標請直接使用 0 而不是 null 巨集,如:
double dval = 0; // 0 是 double 型別,寫 0.0 多餘 double dval1 = 1; // 1 是整數型別,型別提公升 double dval2 = 1.0; // 1.0 是浮點型別 class widget ;
stddef.h 中支援老**的 null 定義:
#ifdef __cplusplus #define null 0 // 0 是各種指標型別 #else #define null ((void *) 0) // c 中 0 是整數型別 #endif
陣列由初始化自動確定大小 int a1 = ; int a2[8] = ; // 剩餘元素初始化為 0,相當於 ; int a1[8] = {}; // 或 ,全 0 的陣列
字串字面量等價於陣列 {}:
char s1 = "abc"; // 相當於 char s2[8] = "abc"; // 相當於 char s3[8] = ""; // 或 {}, ,全 0 的陣列
{} 和 "" 僅用於陣列初始化,不能賦值,如:s3[8] = "123",請用 strcpy(), memcpy()
陣列大小
sizeof: 操作符取得物件和陣列的位元組大小(變數或型別)
_countof: 取得陣列的元素個數,只應用於陣列而非指向陣列的指標,在 vc 的 stdlib.h 中定義(c++ 用模板,c 用巨集定義),等價於 sizeof(a)/sizeof(a[0])
陣列尾哨兵元素位置
c++ 編譯和執行環境保證,陣列最後乙個元素之後的乙個元素的位置(位址)總是可以訪問的,但不保證此位址單元內容可讀寫
與此相對,不保證陣列第乙個元素之前的乙個元素的位置(位址)可以訪問,這鑑於物件、陣列的記憶體邊界對齊放置
stl 演算法因此可以操作內部陣列:
char a1 = "abc123bca"; size_t c = _s::count(a1, a1 + _countof(a1), 'b'); // a1 中 b 的個數
陣列和指標
陣列名/指標 + 整數 offset,是以陣列 元素單元 為單位
指標和大小型別
請使用以下而不是其它 int 型別,保證 32/64 bit 移植性
這些型別在 stddef.h, cstddef (namespace std), crtdefs.h 中定義
stl 標準庫中的很多大小和指標差值型別都是 size_t 和 ptrdiff_t 的別名,如分配器 std::allocator 中:
typedef size_t size_type; typedef ptrdiff_t difference_type;
printf 列印指標位址
用 32/64bit 整數自定適應字首 i,對應 ptrdiff_t (signed) 或 size_t (unsigned)
用 printf 的變長寬度格式化 *
_stprintf_s(buf, _countof(buf), _t("0x%0*ix\n"), sizeof(size_t) * 2, ptr);
32bit 輸出:0x00000001
64bit 輸出:0x0000000000000001
字串字面量
其型別是 const char_type[n] 陣列,n 算上最後結尾 0 字元
大小"hello": 型別是 const char[6], sizeof() = 6
l"abc中文123": 型別是 const wchar_t[9], sizeof() = 18
"": 型別是 const char[1], sizeof() = 1
常量性請以 const char_type* 或陣列作為字串字面量的初始化、賦值左值
有些編譯器警告報錯非 const 的 char_type* 初始化、賦值 (gcc),但有些編譯時不報錯 (vc)
char* str = "abc123"; str[1] = 'b'; // 執行時 access violation void str_func(char* str); str_func("abc123"); // 危險,是否修改 str 的值?
正確的習慣:
const char* str = "abc123"; // 指標指向字面量的儲存,如 .rdata 唯讀區段 char str2 = "abc123"; // 用字母量初始化另乙個 char 物件的儲存 void str_func(const char* str); void str_func2(__out char* str); // 告訴使用者引數 str 將會修改值,約束性程式設計
轉義字元 wchar_t s1 = l"abc\u4e2d\u6587"; // unicode/ucs-2: 中 4e2d, 文 6587, unicode 16 進製轉義 \uhhhh char s2 = "\x61\x62\x63\xd6\xd0\xce\xc4"; // gbk: 中 d0d6, 文 c4ce, 16 進製轉義 \xhh char s3 = "\141\142\143\326\320\316\304"; // 同上, gbk, 8 進製轉義 \ooo
拼接編譯階段拼接,空白字元: 空格, tab, 換行符
char s = "hello" ", world";
鏈結方式
字串字面量的鏈結方式 (internal linkage) 預設使用內部鏈結方式,相當於使用 static 修飾
哪些可以作為 str_func 的模板引數 str_func
str_func<"hello"> // 錯誤, 直接寫字麵量, 內部鏈結 char hello1 = "hello"; // 正確, 非 const 的字元陣列, 外部鏈結 const char hello2 = "hello"; // 錯誤, const 全域性字元陣列, 內部鏈結, 相當於字面量 extern const char hello3 = "hello"; // 正確, extern 顯式修飾 const 全域性字元陣列, 外部鏈結
結構體初始化
{} 用於初始化 pod 結構和陣列,可以巢狀,常用這種方法初始化程式啟動時的配置資料
一旦 struct/class 中有自定義的建構函式,則不能再用 {} 初始化
enum *** ; // person 中必須沒有自定義建構函式 struct person ; // ss 可以是全域性或區域性變數 person ss = , , };
名字空間別名
名字空間可以巢狀,如果名字空間很長可以用別名代替,我習慣用 _n1_n2_n3 的短別名:
namespace _b_al = boost::algorithm;
請在較小作用域內進行名字空間匯入、短別名代替,切忌放到 .h 中,防止影響範圍擴散
for 迴圈中的 continue 會執行步進語句
以刪除 vector 中特定元素為例,i++ 不能放到 for 的步進語句中:
for (i = vec.begin(); i != vec.end();) i++; }
bool 表示式短路求值
expr1 && expr2: 只在 expr1 = true 時,才會對 expr2 求值
expr1 || expr2: 只在 expr1 = false 時,才會對 expr2 求值
這種技巧慣用在後邊的語句依賴前面語句的時候,如:
// 僅當 p != 0 時,才會訪問 p->count if (p && p->count > 42)
C 容易忘的基本語法和特性
原文 c 容易忘的基本語法和特性 標準 c 中容易忘記但比較重要和常用的基本語法和特性 這是 c 或 c in c 而不一定是傳統 c 語言的語法和特性 零 0字面量 0 是基本型別自動適應的,指標請直接使用 0 而不是 null 巨集,如 double dval 0 0 是 double 型別,寫...
C 容易忽略的特性
1 cin 標準輸入流物件,與標準輸入裝置相聯絡 通常指鍵盤 例如 cin 變數名 為提取運算子 輸入運算子 表示從鍵盤讀取資料放入變數中。2 cout 標準輸出流 流物件 與標準輸出裝置相聯絡 通常指顯示器 例如 cout 資料 為插入運算子 輸出運算子 表示將 資料 寫到顯示器上。3 cerr ...
c 基本語法 is 和 as
任何型別都可以轉化為其基型別,用隱式轉化完成 任何物件都可以轉化為其派生類,但必須顯示轉換,如 型別 物件名 使用 gettype 可以獲得任何物件的精確型別 基型別可以通過 convert 進行顯示轉換 除了string以外,其他型別都有 parse 方法,用於將字串型別轉化成對應的基本型別。例如...