利用動態規劃演算法解01揹包問題->二維陣列傳參->cpp記憶體管理->堆和棧的區別->常見的記憶體錯誤及其對策->指標和陣列的區別->32位系統是4G
1、利用動態規劃演算法解01揹包問題
https://www.cnblogs.com/Christal-R/p/Dynamic_programming.html
兩層for迴圈,依次考察當前石塊是否能放入揹包。如果能,則考察放入該石塊是否會得到當前揹包尺寸的最優解。
// 01 knapsack problem dynamic programming algorithm #include "pch.h" #include <iostream> void dynamic_program( int stone_num, int knapsack_capacity, int stone_weight[], int stone_value [], int stone_in_or_not [], int (*V)[8]) { //棧記憶體需要初始化 memset(V, 0, sizeof(V)); for (int i = 0; i < stone_num; i++) { for (int j = 1; j <= knapsack_capacity; j++) { //此時揹包無法裝入當前石塊 if (j < stone_weight[i]) { V[i][j] = V[i - 1][j]; } else { //不裝入價值更大 if (V[i - 1][j] > (V[i - 1][j - stone_weight[i]] + stone_value[i])) { V[i][j] = V[i - 1][j]; } else { //前i-1個物品的最優解與第i個物品的價值之和最大 V[i ][j] = (V[i - 1][j - stone_weight[i]] + stone_value[i]); stone_in_or_not[i] = 1; } } } } int a = 0; } void init() { int stone_num = 4, knapsack_capacity = 8; int stone_weight[] = { 2, 3, 4, 5 }; int stone_value[] = { 3, 4, 5, 6 }; int stone_in_or_not[] = { 0,0,0,0,0,0,0,0 }; int V[4][8]; dynamic_program(stone_num, knapsack_capacity, stone_weight, stone_value, stone_in_or_not, V); } int main() { init(); return 0; }
2、二維陣列傳參
https://blog.csdn.net/yunyun1886358/article/details/5659851
int main()
{
int m = 10;
int n = 10;
int** p = new int[m][n];
}
會發現編譯不通過,第二個維度長度必須為常量。那麼怎麼宣告一個兩個維度都能動態指定的二維陣列呢?看下面:
void func5(int** pArray, int m, int n) { } #include <ctime> int main() { int m = 10; int n = 10; int** pArray = new int* [m]; pArray[0] = new int[m * n]; // 分配連續記憶體 // 用pArray[1][0]無法定址,還需指定下標定址方式 for(int i = 1; i < m; i++) { pArray[i] = pArray[i-1] + n; } func5(pArray, m, n); }
這裡為二維陣列申請了一段連續的記憶體,然後給每一個元素指定定址方式(也可以為每一個元素分別申請記憶體,就不必指定定址方式了),最後將雙重指標作為實參傳遞給func5。這裡func5多了兩個形參,是二維陣列的維度
3、堆和棧的區別
主要區別有以下幾點
(1)管理方式不同(2)空間大小不同(3)能否產生碎片不同(4)生長方式不同
(5)分配方式不同(6)分配效率不同
4、常見的記憶體錯誤及其對策
(1)記憶體分配未成功,卻使用了它。因為記憶體分配會不成功。
常用解決辦法是,在使用記憶體之前檢查指標是否為NULL。
如果指標p是函式的引數,那麼在函式的入口處用assert(p!=NULL)進行檢查。
如果是用malloc或new來申請記憶體,應該用if(p==NULL) 或if(p!=NULL)進行防錯處理。
(2)記憶體分配雖然成功,但是尚未初始化就引用它。
記憶體的預設初值究竟是什麼並沒有統一的標準,儘管有些時候為零值,我們寧可信其無不可信其有。所以無論用何種方式建立陣列,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩。
(3)記憶體分配成功並且已經初始化,但操作越過了記憶體的邊界。
例如在使用陣列時經常發生下標“多1”或者“少1”的操作。特別是在for迴圈語句中,迴圈次數很容易搞錯,導致陣列操作越界。
(4)忘記了釋放記憶體,造成記憶體洩露。
含有這種錯誤的函式每被呼叫一次就丟失一塊記憶體。剛開始時系統的記憶體充足,你看不到錯誤。終有一次程式突然死掉,系統出現提示:記憶體耗盡。動態記憶體的申請與釋放必須配對,程式中malloc與free的使用次數一定要相同,否則肯定有錯誤(new/delete同理)。
(5)釋放了記憶體卻繼續使用它。發生該情況有三種可能:
1). 程式中的物件呼叫關係過於複雜,實在難以搞清楚某個物件究竟是否已經釋放了記憶體,此時應該重新設計資料結構,從根本上解決物件管理的混亂局面。
2). 函式的return語句寫錯了,注意不要返回指向“棧記憶體”的“指標”或者“引用”,因為該記憶體在函式體結束時被自動銷燬。
3). 使用free或delete釋放了記憶體後,沒有將指標設定為NULL。導致產生“野指標”。
那麼如何避免產生野指標呢?這裡列出了5條規則,平常寫程式時多注意一下,養成良好的習慣。
規則1:用malloc或new申請記憶體之後,應該立即檢查指標值是否為NULL。防止使用指標值為NULL的記憶體。
規則2:不要忘記為陣列和動態記憶體賦初值。防止將未被初始化的記憶體作為右值使用。
規則3:避免陣列或指標的下標越界,特別要當心發生“多1”或者“少1”操作。
規則4:動態記憶體的申請與釋放必須配對,防止記憶體洩漏。
規則5:用free或delete釋放了記憶體之後,立即將指標設定為NULL,防止產生“野指標”。
5、指標和陣列的區別
下面示例中,字元陣列a的容量是6個字元,其內容為 hello。a的內容可以改變,如a[0]= ‘X’。指標p指向常量字串“world”(位於靜態儲存區,內容為world),常量字串的內容是不可以被修改的。從語法上看,編譯器並不覺得語句p[0]= ‘X’有什麼不妥,但是該語句企圖修改常量字串的內容而導致執行錯誤。
6、32位系統是4G
https://blog.csdn.net/nvd11/article/details/8749375
7、各種getmemory
https://blog.csdn.net/u010027547/article/details/52292889
參考文獻:
assert()函式 : https://www.cnblogs.com/lvchaoshun/p/7816288.html
cpp記憶體管理: https://chenqx.github.io/2014/09/25/Cpp-Memory-Management/
二維陣列傳參: https://blog.csdn.net/yunyun1886358/article/details/5659851
動態規劃演算法解決01揹包問題: https://www.cnblogs.com/Christal-R/p/Dynamic_programming.html