本文介绍几个非常经典的笔试题,原题+详细解析,供参考
题目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; }