【C++內存管理之三野指針、內存泄漏、內存覆蓋及應對策略


發生內存錯誤時間非常麻煩的事情。編譯器不能發現這些錯誤,只能在程序運行時才能捕捉到。常見的內存錯誤有三種,野指針、內存泄漏和內存覆蓋

一、野指針問題

野指針是指向了被釋放或沒有訪問權限的內存指針。

1、訪問權限

//野指針
int* p;
p = 10;
//報錯,使用了未初始化的變量p

2、指向被釋放的內存
在這裏插入圖片描述

二、內存泄漏

內存泄露(memory lock)是指由於疏忽或錯誤造成程序未能釋放已經不再使用的內存的情況。

1、內存使用完之後,沒有釋放;
2、對new或malloc出的指針進行重新賦值。
內存泄漏查詢方法

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
int main(){
    _CrtSetBreakAlloc();
    ....................
    _CrtDumpMemoryLeaks();
    return 0;
}

詳解:
https://blog.csdn.net/daaikuaichuan/article/details/80874436

三、內存覆蓋

strcpy、memcpy、strcat容易發生內存覆蓋問題
1、strcpy函數

char* strcpy(char* dst, const char* src, int size) {
	assert(src);
	assert(dst);
	if (dst <= src || dst > src + size) {
		char* d = dst;
		const char* s = src;
		while (size--) {
			*d++ = *s++;
		}
	}
	else {//發生內存覆蓋,逆向複製
		char* d = dst + size - 1;
		const char* s = src + size - 1;
		while (size--) {
			*d-- = *s--;
		}
	}
	return dst;
}

2、memcpy函數

void* memcpy(void* dst, const void* src, int size) {
	if (src != nullptr || dst != nullptr) {
		return nullptr;
	}
	char* d = (char*)dst;
	char* s = (char*)src;
	if (d <= s || d > s + size) {
		while (size--) {
			*d++ = *s++;
		}
	}
	else {//發生內存覆蓋,逆向複製
		d = d + size - 1;
		s = s + size - 1;
		while (size--) {
			*d-- = *s--;
		}
	}
}

3、strcat函數

char* strcat(char* dst, const char* src) {
	assert(src);
	assert(dst);
	char* p = dst;
	while (*dst != '\0') {
		dst++;
	}
	while (*dst++ = *src++ != '\0');
	return p;
}

四、常見錯誤及對策

1、內存分配失敗
內存分配失敗卻使用了它
指針p爲函數參數,在函數入口處進行檢查:

assert(p != NULL);

new或malloc申請內存進行判斷:

if(p == NULL)

2、內存操作越界
常見的數組越界,發生在下標多‘1’或少‘1’;
指針超過變量範圍(野指針)
3、指針越界
4、空指針
在這裏插入圖片描述
常見對策

規則
規則1 用malloc或new申請內存之後,應該立即檢查指針值是否爲NULL。防止使用指針值爲NULL的內存。
規則2 不要忘記爲數組和動態內存賦初值。防止將未被初始化的內存作爲右值使用。
規則3 避免數組或指針的下標越界,特別要當心發生“多1”或者“少1”操作。
規則4 動態內存的申請與釋放必須配對,防止內存泄漏。
規則5 用free或delete釋放了內存之後,立即將指針設置爲NULL,防止產生“野指針”。

野指針與內存泄漏的關係

  1. 指針銷燬了,並不表示所指的空間也得到釋放了: 內存泄漏!
  2. 內存釋放了,並不代表指針被銷燬或者指向了NULL ;未初始化的指針(野指針)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章