本文介绍几个非常经典的笔试题,原题+详细解析,供参考
- 题目1:非法访问+内存泄漏
- 题目2:返回栈空间地址问题--非法访问
- 题目3:内存泄漏
- 题目4:非法访问
题目1:非法访问+内存泄漏
void Getmemory(char* p)
{
p = (char*)malloc(100);
}
void test(void)
{
char* str = NULL;
Getmemory(str);
strcpy(str, "hello world");
printf(str);
}
int main()
{
test();
return 0;
}
请问运行Test 函数会有什么样的结果?
结果:
解析:
void Getmemory(char* p)//用p来接收str的数据,p是形参,形参是实参的一份临时拷贝
{
p = (char*)malloc(100);//给p开辟一个100字节的空间。
//还有这里开辟了空间后,并没有释放,造成内存泄漏。
}
void test(void)
{
char* str = NULL;
Getmemory(str);//将str这个指针传过去,相当于传值过去,并不是传址输入,对形参的改变并不会影响实参。
strcpy(str, "hello world");//这里的str还是空指针,并没有空间给它拷贝,形成NULL非法访问,这里就出错了。
printf(str);
}
int main()
{
test();
return 0;
}
1.str传给p的时候,p是str的临时拷贝,有自己的独立空间,当GetMemory函数内部申请了空间后,地址放在p中,str仍然是NULL。当Getmemory函数返回之后,strcpy拷贝的时候,形成了非法访问。
2.在Getmemory函数内部,动态申请空间,但是没有释放,造成内存泄漏
正确做法1:
void Getmemory(char** p)//str是一级指针,&str就是二级指针
{
*p = (char*)malloc(100);//*p就相当于str,就是给str开辟一个100字节的空间
}
void test(void)
{
char* str = NULL;
Getmemory(&str);//这里进行传址输入,利用形参修改实参
strcpy(str, "hello world");//这里的str就拥有了100字节的空间了
printf(str);
free(str);//释放空间
str=NULL//手动置NULL
}
int main()
{
test();
return 0;
}
正确做法2:
char* Getmemory(char* p)//那Getmemory函数返回值就要改成char *类型接收指针
{
p = (char*)malloc(100);
return p;//将p返回
}
void test(void)
{
char* str = NULL;
str=Getmemory(str);//这里用指针str来接收Getmemory函数内部形参开辟的空间
strcpy(str, "hello world");
printf(str);
free(str);//释放空间
str=NULL//手动置NULL
}
int main()
{
test();
return 0;
}
题目2:返回栈空间地址问题–非法访问
char* Getmemory(void)
{
char p[] = "hello world";
return p;
}
void test(void)
{
char* str = NULL;
str = Getmemory();
printf(str);
}
int main()
{
test();
return 0;
}
请问运行Test 函数会有什么样的结果?
结果:
解析:
char* Getmemory(void)
{
char p[] = "hello world";//创建一个数组p,里面存放着字符串
return p;//返回数组名,也就是返回了数组首元素的地址
}
void test(void)
{
char* str = NULL;
str = Getmemory();//Getmemory函数的返回值用str来接收
//数组p的首元素地址用str来接收
//但要注意的是,p数组是在Getmemory内部创建,创建在栈区,出了函数,这个空间就要返回给操作系统,不再受指针p操控。
//所以str虽然得到了数组的首元素地址,但这片空间已经不再属于数组空间了,所以形成了非法访问
printf(str);//打印str指向的字符
}
int main()
{
test();
return 0;
}
这个问题统称为返回栈空间地址问题
就是在栈上开辟的空间,并将指向这块空间的地址返回,但这块空间的使用者发现改变,不再是原先的使用者了,而再根据地址找到这块空间来访问就会出问题。
这个要按自己的实际需求来正确修改。
题目3:内存泄漏
void Getmemory(char** p, int num)
{
*p = (char*)malloc(num);
}
void test(void)
{
char* str = NULL;
Getmemory(&str, 100);
strcpy(str, "xiao tao");
printf(str);
}
int main()
{
test();
return 0;
}
请问运行Test 函数会有什么样的结果?
解析:
这个题目跟第一题的修改后的题目差不多
void Getmemory(char** p, int num)
{
*p = (char*)malloc(num);//开辟100个字节空间给*p *p就是str
//所以给str开辟了100字节的空间
}
void test(void)
{
char* str = NULL;
Getmemory(&str, 100);//传址输入,可以通过对形参修改而修改实参
strcpy(str, "xiao tao");//对str指向的空间进行拷贝
printf(str);//打印拷贝后的空间内容
//最最重要的一点是,空间申请后,释放呢?这里没有释放所以最后会造成内存泄漏
free(str);//释放内存
str = NULL;
}
int main()
{
test();
return 0;
}
题目4:非法访问
void test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "xiao tao");
free(str);
if (str != NULL)
{
strcpy(str, "666");
printf(str);
}
}
int main()
{
test();
return 0;
}
请问运行Test 函数会有什么样的结果?
解析:
void test(void)
{
char* str = (char*)malloc(100);//开辟100个字节的空间
strcpy(str, "xiao tao");//给指向srt的空间进行拷贝
free(str);//释放空间
//free的功能是将原先指向这块空间的指针与这块空间之间的联系断开,这块空间不再首这个指针调控,回归到操作系统,供有需要的使用
//而free释放空间后并不会将原先指向这块空间的指针置为空指针,还是指向原先的地方,所以下面的操作就进行下去了
//所以这个指针又去访问那块空间让其被覆盖成666,这就造成非法访问了
if (str != NULL)//如果str不为空指针进行下面操作
{
strcpy(str, "666");
printf(str);//打印指向str那块空间的内容
}
}
int main()
{
test();
return 0;
}
正确做法:在不改变原意的基础上修改:
void test(void)
{
char* str = (char*)malloc(100);//开辟100个字节的空间
strcpy(str, "xiao tao");//给指向srt的空间进行拷贝
free(str);//释放空间
str = NULL;//释放空间后手动置为NULL,让下面的操作无法进行
if (str != NULL)//如果str不为空指针进行下面操作
{
strcpy(str, "666");
printf(str);//打印指向str那块空间的内容
}
}
int main()
{
test();
return 0;
}