文章目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、常见的动态内存错误
1. 对NULL指针的解引用操作
下面的例子来具体看一下:
int main()
{
int* p = (int*)malloc(1000);
int i = 0;
//使用
for (i = 0; i < 250; i++)
{
*(p + i) = i;
}
return 0;
}
上面代码中如果p的值是NULL空指针,就会出现问题
解决办法:对malloc函数的返回值进行判断
int main()
{
int* p = (int*)malloc(1000);
int i = 0;
if (p == NULL)
{
return 1;
}
//使用
for (i = 0; i < 250; i++)
{
*(p + i) = i;
}
free(p);
p = NULL;
return 0;
}
2. 对动态开辟空间的越界访问
下面的例子来具体看一下:
int main()
{
int* p = (int*)malloc(100);
int i = 0;
if (p == NULL)
{
return 1;
}
//使用
//越界访问了
for (i = 0; i <= 25; i++)//这里<=25
{
*(p + i) = i;
}
return 0;
}
上面代码中如果大于25就会造成越界访问,就会出现问题
解决办法:自己写代码时对内存边界进行检查
3. 对非动态开辟内存使用free释放
下面的例子来具体看一下:
int main()
{
int a = 10;
int* p = &a;
free(p);
p = NULL;
return 0;
}
如果我们去运行就会发现出现问题:
上面代码中是对非动态开辟的内存进行释放,就会出现问题
在这里a属于局部变量,局部变量使用完成后,就会自动回收。
4. 使用free释放一块动态开辟内存的一部分
下面的例子来具体看一下:
int main()
{
int* p = (int*)malloc(100);
if (p == NULL)
{
return 1;
}
//使用
int i = 0;
for (i = 0; i < 10; i++)
{
*p = i;
p++;
}
//释放空间
free(p);
p = NULL;
return 0;
}
如果我们去运行也会发现出现问题:
上面代码中p进行了++操作并没有指向动态内存的起始位置
我们必须从他的起始位置开始释放空间,不能释放其中的一部分
5. 对同一块动态内存多次释放
下面的例子来具体看一下:
int main()
{
int* p = malloc(100);
if (p == NULL)
return 1;
free(p);
free(p);//这就会出现错误
p = NULL;
return 0;
}
上面代码中同一块动态内存多次释放,就会出现问题
6. 动态开辟内存忘记释放(内存泄漏)
下面的例子来具体看一下:
void test()
{
int* p = malloc(100);
}
int main()
{
test();
return 0;
}
上面代码中对动态开辟的内存忘记释放,就会出现内存泄漏
内存泄漏(Memory Leak):是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
二、经典笔试题
题目1
代码如下(示例):
void GetMemory(char *p) {
p = (char *)malloc(100);
}
void Test(void) {
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
请问运行Test 函数会有什么样的结果?
解析:
调用test函数,函数内部创建了str放进去空指针, 把str传给了GetMemory函数,形参p其实是str的一份临时拷贝,p里面放的也是空指针,执行下面语句相当于向内存申请了100字节空间,强制类型转换为char * 把这个地址存到p中,函数调用结束后,形参变量就销毁了 没有变量或者指针记住申请空间的起始地址,内存也无法进行释放,就形成了内存泄漏。str是空指针,把hello world 放到空指针中就出现问题了,对空指针解引用,就形成非法访问内存程序就会崩溃。
题目2
代码如下(示例):
char *GetMemory(void) {
char p[] = "hello world";
return p; }
void Test(void) {
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行Test 函数会有什么样的结果?
解析:
调用test函数,创建了str指针置为NULL str接收这个函数的返回值,函数内部中创建了一个数组p,这个p是临时变量,函数调用结束后,p就回收了。但是我们返回了p的地址也就是数组的起始地址,放进str中,但是返回后,其实p已经回收了,把空间还给了操作系统,当我们拿这个指针访问空间时,此时这个指针就是野指针,所以就会打印随机值。
题目3
代码如下(示例):
void GetMemory(char **p, int num) {
*p = (char *)malloc(num);
}
void Test(void) {
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
请问运行Test 函数会有什么样的结果?
解析:
这个代码可以正常打印hello,但是没有释放动态开辟的空间。下面是对代码的修改。
void GetMemory(char** p, int num)
{
*p = (char*)malloc(num);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
//忘记释放
free(str);
str = NULL;
}
题目4
代码如下(示例):
void Test(void) {
char *str = (char *) malloc(100);
strcpy(str, "hello");
free(str);
if(str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
请问运行Test 函数会有什么样的结果?
解析:str指针,指向申请的空间起始地址,把hello拷进申请的空间内,拷贝完成会释放申请的空间,str还指向这个地址,但是这块空间已经回收了,在把world拷贝放到str指向的空间中,把hello改成了world,这就是空指针,形成非法访问。下面是对代码的修改。把str置为空指针防止后面程序使用这个指针,形成空指针,造成非法访问。
void Test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
str = NULL;//把str置为空指针
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
注:以上笔试题来源nice2016校招,《高质量的C C++编程》
总结
以上就是一些关于动态内存的问题
🌟Hello world 我们下期见!