C语言面试题详解(第5节)
发表于: 2019-02-16 20:09:27 | 已被阅读: 30 | 分类于: C语言
本系列文章主要分析国内外知名公司的C语言面试题,但目的绝不仅仅只是为了做题,而是为了检查自己的知识欠缺点,巩固自己的内功。
这系列文章已经发布了 4 篇,每一篇文章都有朋友回复说讨论这些“偏题”和“怪题”没有意义,“要是写出这样的代码,早就被开除了”。可是正如我之前所说的一样,
似乎咱们国内很多程序员都不太注重基础,可是基础不牢,怎么能建高楼呢?
事实上,本系列文章讨论的C语言题目,都是来自国内外优秀的知名企业的面试题或者笔试题。如果朋友们能够静下心来琢磨琢磨,相信对自己的技术提升还是非常有帮助的。
本节来看看这个题目
下面这道题目来自美国某著名计算机嵌入式公司的面试题,请看如下 C语言代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void GetMemory(char *p, int num)
{
p = (char*)malloc(sizeof(char)*num);
}
int main()
{
char *str = NULL;
GetMemory(str, 100);
strcpy(str, "hello");
printf("str: %s\n", str);
return 0;
}
# gcc t.c
# ./a.out
Segmentation fault
初步分析
相信没有人会故意写出无法运行的C语言代码,该程序员的初衷应该是: 通过 GetMemory() 函数从堆中分配 num 个字节的内存空间,并且把这段内存的首地址通过参数 p 传出。
在 main() 中,他预想 str 会指向系统分配给程序的 100 字节内存段,此时将字符串“hello”拷贝给 str 自然没有问题,程序最终会输出:
str: hello
然而事与愿违。那么,这到底是怎么回事呢?这其实就是一道非常基础的题目,相信有朋友应该能够看出,这道题目其实就是下面这个问题的变形:
#include <stdio.h>
void set(int a)
{
a = 8;
}
int main()
{
int a = 3;
set(a);
printf("a=%d\n", a);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char* ptr;
void GetMemory(ptr p, int num)
{
p = (ptr)malloc(sizeof(char)*num);
}
int main()
{
ptr str = NULL;
GetMemory(str, 100);
strcpy(str, "hello");
printf("str: %s\n", str);
return 0;
}
进一步分析
那么,该如何修改,才能使C语言程序按照该程序员的
或者说,为什么 set() 函数没有影响 main() 函数里的变量 a。
相信大家都知道,C语言程序运行在内存中。实际上,系统分配给程序的内存可以划分为好几个段,每发生一次函数调用,系统就会从栈划分出一小片区域(即所谓的“栈帧”)给函数使用。请看下图:
函数的局部变量都存在于自己的栈帧中,而函数的参数也是它自己的局部变量,所以 GetMemory() 函数中的参数 p 实际上存在于橘黄色内存段中,而 main() 函数中的 str 则存在于浅绿色的内存段中,显然 p 不会影响到 str。
当 GetMemory() 函数执行完毕后,系统会回收它所用过的栈帧,这其实就是一般C语言编程教科书上常说的“局部变量在函数运行完毕后,就自动释放了”的原因。
好了,现在知道为什么 GetMemory() 函数没能把申请到的内存段返回给 str 了,那怎样修改才能让C语言程序按照
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char* ptr;
void GetMemory(ptr* p, int num)
{
*p = (ptr)malloc(sizeof(char)*num);
}
int main()
{
ptr str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf("str: %s\n", str);
return 0;
}
# gcc t.c
# ./a.out
str: hello
小结
你看,这道面试题其实注重的仍然只是基础。要是基础不牢,出现问题却找不到,甚至对其视而不见就麻烦了。