1. 程式人生 > >利用動態規劃演算法解01揹包問題->二維陣列傳參->cpp記憶體管理->堆和棧的區別->常見的記憶體錯誤及其對策->指標和陣列的區別->32位系統是4G

利用動態規劃演算法解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