十三誡增修--03:你不可以提取(dereference)不知指向何方的指標

作者: wtchen (沒有存在感的人)   2016-05-13 16:50:50
增加VLA跟std::array/std::vector的部份...
===============================================================
03. 你不可以提取(dereference)不知指向何方的指標(包含 null 指標)。
錯誤例子:
char *pc1; /* 未給予初值,不知指向何方 */
char *pc2 = NULL; /* pc2 起始化為 null pointer */
*pc1 = 'a'; /* 將 'a' 寫到不知何方,錯誤 */
*pc2 = 'b'; /* 將 'b' 寫到「位址0」,錯誤 */
正確例子:
char c; /* c 的內容尚未起始化 */
char *pc1 = &c; /* pc1 指向字元變數 c */
*pc1 = 'a'; /* c 的內容變為 'a' */
/* 動態分配 10 個 char(其值未定),並將第一個char的位址賦值給 pc2 */
char *pc2 = (char *) malloc(10);
pc2[0] = 'b'; /* 動態配置來的第 0 個字元,內容變為 'b'
free(pc2);
說明:指標變數必需先指向某個可以合法操作的空間,才能進行操作。
( 使用者記得要檢查 malloc 回傳是否為 NULL,
礙於篇幅本文假定使用上皆合法,也有正確歸還記憶體 )
錯誤例子:
char *name; /* name 尚未指向有效的空間 */
printf("Your name, please: ");
fgets(name,20,stdin); /* 您確定要寫入的那塊空間合法嗎??? */
printf("Hello, %s\n", name);
正確例子:
/* 如果編譯期就能決定字串的最大空間,那就不要宣告成 char* 改用 char[] */
char name[21]; /* 可讀入字串最長 20 個字元,保留一格空間放 '\0' */
printf("Your name, please: ");
fgets(name,20,stdin);
printf("Hello, %s\n", name);
正確例子(2):
若是在執行時期才能決定字串的最大空間,C提供兩種作法:
a. 利用 malloc() 函式來動態分配空間,用malloc宣告的陣列會被存在heap
須注意:若是宣告較大陣列,要確認malloc的回傳值是否為NULL
size_t length;
printf("請輸入字串的最大長度(含null字元): ");
scanf("%u", &length);
name = (char *)malloc(length);
if (name) { // name != NULL
printf("您輸入的是 %u\n", length);
} else { // name == NULL
puts("輸入值太大或系統已無足夠空間");
}
/* 最後記得 free() 掉 malloc() 所分配的空間 */
free(name);
name = NULL; //(註1)
b. C99開始可使用variable-length array (VLA)
須注意:
- 因為VLA是被存放在stack裡,使用前要確認array size不能太大
- 不是每個compiler都支援VLA(註2)
- C++ Standard不支援(雖然有些compiler支援)
float read_and_process(int n)
{
float vals[n];
for (int i = 0; i < n; i++)
vals[i] = read_val();
return process(vals, n);
}
正確例子(3):
C++的使用者也有兩種作法:
a. std::vector (不管你的陣列大小會不會變都可用)
std::vector<int> v1;
v1.resize(10); // 重新設定vector size
b. C++11以後,若是確定陣列大小不會變,可以用std::array
須注意:一般使用下(存在stack)一樣要確認array size不能太大
std::array<int, 5> a = { 1, 2, 3 }; // a[0]~a[2] = 1,2,3; a[3]之後為0;
a[a.size() - 1] = 5; // a[4] = 0;
備註:
註1. C++的使用者,C++03或之前請用0代替NULL,C++11開始請改用nullptr
註2. gcc和clang支援VLA,Visual C++不支援
補充資料:
http://www.cplusplus.com/reference/vector/vector/resize/
作者: Caesar08 (Caesar)   2016-05-13 19:01:00
c++11後,可以用std::array
作者: wtchen (沒有存在感的人)   2016-05-13 19:11:00
我都忘了還有這個,馬上加對了,請問std::array是存在stack裡嗎?
作者: Caesar08 (Caesar)   2016-05-13 19:30:00
std::array就是一個C形式的array
作者: wtchen (沒有存在感的人)   2016-05-13 19:31:00
所以一樣不能宣告太大?
作者: Caesar08 (Caesar)   2016-05-13 19:34:00
作者: wtchen (沒有存在感的人)   2016-05-13 19:46:00
寫到現在總覺得C跟C++5年內一定會分家...
作者: Caesar08 (Caesar)   2016-05-13 19:59:00
最好快點分...
作者: wtchen (沒有存在感的人)   2016-05-13 20:14:00
C++就像變心的女友一樣回不來了....
作者: tinlans ( )   2016-05-17 02:40:00
永遠檢查 malloc 的傳回值不是更好? XD
作者: wtchen (沒有存在感的人)   2016-05-19 07:00:00
我還真的很想在十三誡加這條

Links booklink

Contact Us: admin [ a t ] ucptt.com