经典C面试题
12个有趣的C语言面试题
1.gets()函数
问:请找出以下代码里的问题:
- #include<stdio.h>
- int main(void)
- {
- char buff[10];
- memset(buff,0,sizeof(buff));
- gets(buff);
- printf("\n The buffer entered is [%s]\n",buff);
- return 0;
- }
答:上面代码里的问题在于函数gets()的使用,这个函数从stdin接收一个字符串而不检查它所复制的缓存的容积,这可能会导致缓存溢出。这里推荐使用标准函数fgets()取代。
2.strcpy()函数
问:以下是一个简单的password保护功能,你能在不知道password的情况下将其破解吗?
- #include<stdio.h>
- int main(int argc, char *argv[])
- {
- int flag = 0;
- char passwd[10];
- memset(passwd,0,sizeof(passwd));
- strcpy(passwd, argv[1]);
- if(0 == strcmp("LinuxGeek", passwd))
- {
- flag = 1;
- }
- if(flag)
- {
- printf("\n Password cracked \n");
- }
- else
- {
- printf("\n Incorrect passwd \n");
- }
- return 0;
- }
答:破解上述加密的关键在于利用攻破strcpy()函数的漏洞。所以用户在向“passwd”缓存输入随机password的时候并没有提前检查“passwd”的容量是否足够。所以,假设用户输入一个足够造成缓存溢出而且重写“flag”变量默认值所存在位置的内存的长“password”,即使这个password无法通过验证,flag验证位也变成了非零,也就能够获得被保护的数据了。比如:
- $ ./psswd aaaaaaaaaaaaa
- Password cracked
尽管上面的password并不对,但我们仍然能够通过缓存溢出绕开password安全保护。
要避免这种问题,建议使用 strncpy()函数。
作者注:近期的编译器会在内部检測栈溢出的可能,所以这样往栈里存储变量非常难出现栈溢出。在我的gcc里默认就是这样,所以我不得不使用编译命令‘-fno-stack-protector’来实现上述方案。
3.main()的返回类型
问:以下的代码能 编译通过吗?假设能,它有什么潜在的问题吗?
- #include<stdio.h>
- void main(void)
- {
- char *ptr = (char*)malloc(10);
- if(NULL == ptr)
- {
- printf("\n Malloc failed \n");
- return;
- }
- else
- {
- // Do some processing
- free(ptr);
- }
- return;
- }
答:由于main()方法的返回类型,这段代码的错误在大多数编译器里会被当作警告。main()的返回类型应该是“int”而不是“void”。由于“int”返回类型会让程序返回状态值。这点很重要,特别当程序是作为依赖于程序成功执行的脚本的一部分执行时。
4.内存泄露
问:以下的代码会导致内存泄漏吗?
- #include<stdio.h>
- void main(void)
- {
- char *ptr = (char*)malloc(10);
- if(NULL == ptr)
- {
- printf("\n Malloc failed \n");
- return;
- }
- else
- {
- // Do some processing
- }
- return;
- }
答:虽然上面的代码并没有释放分配给“ptr”的内存,但并不会在程序退出后导致内存泄漏。在程序结束后,全部这个程序分配的内存都会自己主动被处理掉。但假设上面的代码处于一个“while循环”中,那将会导致严重的内存泄漏问题!
提示:假设你想知道很多其它关于内存泄漏的知识和内存泄漏检測工具,能够来看看我们在Valgrind上的文章。
5.free()函数
问:以下的程序会在用户输入'freeze'的时候出问题,而'zebra'则不会,为什么?
- #include<stdio.h>
- int main(int argc, char *argv[])
- {
- char *ptr = (char*)malloc(10);
- if(NULL == ptr)
- {
- printf("\n Malloc failed \n");
- return -1;
- }
- else if(argc == 1)
- {
- printf("\n Usage \n");
- }
- else
- {
- memset(ptr, 0, 10);
- strncpy(ptr, argv[1], 9);
- while(*ptr != 'z')
- {
- if(*ptr == '')
- break;
- else
- ptr++;
- }
- if(*ptr == 'z')
- {
- printf("\n String contains 'z'\n");
- // Do some more processing
- }
- free(ptr);
- }
- return 0;
- }
答:这里的问题在于,代码会(通过添加�“ptr”)改动while循环里“ptr”存储的地址。当输入“zebra”时,while循环会在运行前被终止,因此传给free()的变量就是传给malloc()的地址。但在“freeze”时,“ptr”存储的地址会在while循环里被改动,因此导致传给free()的地址出错,也就导致了seg-fault或者崩溃。
6.使用_exit退出
问:在以下的代码中,atexit()并没有被调用,为什么?
- #include<stdio.h>
- void func(void)
- {
- printf("\n Cleanup function called \n");
- return;
- }
- int main(void)
- {
- int i = 0;
- atexit(func);
- for(;i<0xffffff;i++);
- _exit(0);
- }
这是由于_exit()函数的使用,该函数并没有调用atexit()等函数清理。假设使用atexit()就应当使用exit()或者“return”与之相配合。
7.void*和C结构体
问:你能设计一个能接受不论什么类型的參数并返回interger(整数)结果的函数吗?
答:例如以下:
- int func(void *ptr)
假设这个函数的參数超过一个,那么这个函数应该由一个结构体来调用,这个结构体能够由须要传递參数来填充。
8.*和++操作
问:以下的操作会输出什么?为什么?
- #include<stdio.h>
- int main(void)
- {
- char *ptr = "Linux";
- printf("\n [%c] \n",*ptr++);
- printf("\n [%c] \n",*ptr);
- return 0;
- }
答:输出结果应该是这样:
- [L]
- [i]
由于“++”和“*”的优先权一样,所以“*ptr++”相当于“*(ptr++)”。即应该先运行ptr++,然后才是*ptr,所以操作结果是“L”。第二个结果是“i”。
9.问:改动代码片段(或者仅仅读代码)
问:以下的代码段有错,你能指出来吗?
- #include<stdio.h>
- int main(void)
- {
- char *ptr = "Linux";
- *ptr = 'T';
- printf("\n [%s] \n", ptr);
- return 0;
- }
答:这是由于,通过*ptr = ‘T’,会改变内存中代码段(仅仅读代码)“Linux”的第一个字母。这个操作是无效的,因此会造成seg-fault或者崩溃。
10.会改变自己名字的进程
问:你能写出一个在执行时改变自己进程名的程序吗?
答:參见以下这段代码:
- #include<stdio.h>
- int main(int argc, char *argv[])
- {
- int i = 0;
- char buff[100];
- memset(buff,0,sizeof(buff));
- strncpy(buff, argv[0], sizeof(buff));
- memset(argv[0],0,strlen(buff));
- strncpy(argv[0], "NewName", 7);
- // Simulate a wait. Check the process
- // name at this point.
- for(;i<0xffffffff;i++);
- return 0;
- }
11.返回本地变量的地址
问:以下代码有问题吗?假设有,该怎么改动?
- #include<stdio.h>
- int* inc(int val)
- {
- int a = val;
- a++;
- return &a;
- }
- int main(void)
- {
- int a = 10;
- int *val = inc(a);
- printf("\n Incremented value is equal to [%d] \n", *val);
- return 0;
- }
答:虽然上面的程序有时候能够正常执行,可是在“inc()”中存在严重的漏洞。这个函数返回本地变量的地址。由于本地变量的生命周期就是“inc()”的生命周期,所以在inc结束后,使用本地变量会发生不好的结果。这能够通过将main()中变量“a”的地址来避免,这样以后还能够改动这个地址存储的值。
12.处理printf()的參数
问:以下代码会输出什么?
- #include<stdio.h>
- int main(void)
- {
- int a = 10, b = 20, c = 30;
- printf("\n %d..%d..%d \n", a+b+c, (b = b*2), (c = c*2));
- return 0;
- }
答:输出结果是:
- 110..40..60
这是由于C语言里函数的參数默认是从右往左处理的,输出时是从左往右。
经典C面试题的更多相关文章
- 那晚征服的一道js经典的面试题
今天朋友共享了一道js中经典的面试题,需求是这样的 给定你任意一个字符串,让你写出一个算法,求算出该字符串中出现次数最多的一个字符,并将其结果输出 刚拿到这道题的第一感觉便是定义一个count计时器, ...
- 解析js中作用域、闭包——从一道经典的面试题开始
如何理解js中的作用域,闭包,私有变量,this对象概念呢? 就从一道经典的面试题开始吧! 题目:创建10个<a>标签,点击时候弹出相应的序号 先思考一下,再打开看看 //先思考一下你会怎 ...
- Spring经典高频面试题,原来是长这个样子
Spring经典高频面试题,原来是长这个样子 2019年08月23日 15:01:32 博文视点 阅读数 719 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文 ...
- 100+经典Java面试题及答案解析
面向对象编程(OOP) Java是一个支持并发.基于类和面向对象的计算机编程语言.下面列出了面向对象软件开发的优点: 代码开发模块化,更易维护和修改. 代码复用. 增强代码的可靠性和灵活性. 增加代码 ...
- 经典Java面试题收集(二)
经典的Java面试题(第二部分),这部分主要是与Java Web和Web Service相关的面试题. 96.阐述Servlet和CGI的区别? 答:Servlet与CGI的区别在于Servlet处于 ...
- 超全面!1.5w字总结50个Java经典基础面试题(已根据知识点分类)
大家好,我是fancy. 在面试中将基础问题回答好就是成功的一半. 我总结了50道经典的Java基础面试题,里面包含面试要回答的知识重点,并且我根据知识类型进行了分类,可以说非常全面了. 小伙伴们点赞 ...
- 【转】 71道经典Android面试题和答案,重要知识点都包含了
,,面试题1. 下列哪些语句关于内存回收的说明是正确的? (b ) A. 程序员必须创建一个线程来释放内存 B.内存回收程序负责释放无用内存 C.内存回收程序允许程序员直接释放内存 ...
- 71道经典Android面试题和答案
,,面试题1. 下列哪些语句关于内存回收的说明是正确的? (b ) A. 程序员必须创建一个线程来释放内存 B.内存回收程序负责释放无用内存 C.内存回收程序允许程序员直接释放内存 ...
- 【BAT经典算法面试题系列】求和为n的连续正整数
马上就要到9月份了,意味着一年一度的秋招就要开始了,相信不论是正在实习的童鞋还是马上就要找工作的童鞋,BAT无疑是国内的"明星企业",是每个学计算机的小伙伴们心之向往的企业,但是呢 ...
随机推荐
- android-'Using 1.7 requires compiling with Android 4.4 (KitKat); currently using API 8'
解决的方案是将jdk1.7制定的版本定制为jdk.6.即 在eclipse中,右键项目->Properties->Java Compiler->enable "projec ...
- CRT detected that the application wrote to memory after end of heap buffer.
很多人的解释都不一样, 我碰到的问题是,开辟的内存空间小于操作的内存空间.也就是说,我free的内存越界了. 这是我开辟链表结构体内存的代码: PNODE Create() { int len; / ...
- _Obj* __STL_VOLATILE* __my_free_list
今天在读<STL源码剖析>空间配置器第二级时看到了这句,有点不解,于是查阅后知: obj后面是个指针 STL_VOLATILE也应该是个类型定义的吧,程序中应该有define来对它定义.所 ...
- MPICH2在两台Ubuntu上安装(用mpd做进程管理)
本文在经过大量的实验终于不负众望成功的在两台Ubuntu 12.04上部署MPI的一个小型集群,MPICH2所用版本为mpich2-1.4.1,下载地址:http://www.mcs.anl.gov/ ...
- undefined 和 null 的异同
在javascript中,undefined和Null是两个比较特殊的值.但有时候在判断时就有点迷糊.依个人浅见,整理如下: 1.数据类型 众多周知,在javascript中存在五种基本类型,即und ...
- 试用ubuntu-12.04.3-desktop-amd64(二)
首先说明,采用主机+虚拟机+ubuntu的形式,更具体的则为Win7-64bit + VMWare + ubuntu-12.04.3-desktop-amd64 进入ubuntu后首先考虑到的就是怎么 ...
- VBox UUID already exists 问题处理
问题说明: 在win7系统下使用vbox时,有时候需要多台相同操作系统和开发环境的虚拟电脑时,如果重复安装,会比较麻烦.那么可以在vbox中创建一个新的虚拟电脑B,但不创建虚拟硬盘,然后拷贝虚拟电脑A ...
- (转载)图解Linux系统的系统架构
我以下图为基础,说明Linux的架构(architecture).(该图参考<Advanced Programming in Unix Environment>) 最内层是硬件,最外层是用 ...
- Bootstrap_排版_列表
一.基本列表 <h5>普通列表</h5> <ul> <li>列表项目</li> <li>列表项目</li> < ...
- SASS type-of 函数
今儿写个type-of,算是备忘录吧. 1.number type-of(0) // number type-of(1px) // number 2.string type-of(a) // stri ...