经典C语言面试题

这篇具有很好参考价值的文章主要介绍了经典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()函数

问:下面是一个简单的密码保护功能,你能在不知道密码的情况下将其破解吗?

#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”缓存输入随机密码的时候并没有提前检查 “passwd”的容量是否足够。所以,如果用户输入一个足够造成缓存溢出并且重写“flag”变量默认值所存在位置的内存的长“密码”,即使这个密码无 法通过验证,flag验证位也变成了非零,也就可以获得被保护的数据了。例如:

  1. $ ./psswd aaaaaaaaaaaaa 
  2. Password cracked 

虽然上面的密码并不正确,但我们仍然可以通过缓存溢出绕开密码安全保护。

要避免这样的问题,建议使用 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(整数)结果的函数吗?

答:如下:

  1. 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; 
} 

复制

答:输出结果是:文章来源地址https://www.toymoban.com/news/detail-487619.html

  1. 110..40..60 

到了这里,关于经典C语言面试题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言gets( )函数详解

    1.描述  char* gets( char* str)函数:从标准输入(stdin)读取字符串, 遇到空格不结束,直到遇到回车 ,将字符串存储到str指向的字符串。 2.gets( )和scanf( )的区别 gets(str)和scanf(\\\"%s\\\",str)作用类似,但又有所不同。主要区别在于: gets(str) :读到回车换行才结束读取, 遇到空格不结

    2024年02月04日
    浏览(59)
  • 2023最新C语言经典面试题汇总

    写出Bool、int、指针变量、float与“零值”比较的if语句 Bool型: if(flag)、if(!flag) int型: if(flag == 0)、if( flag!= 0) 指针变量: if(p == NULL)、if( p!= NULL) float型: const float EPSINON = 0.0001; if( (x = -EPSINON) (x = EPSINON)); 设置地址未为0x67a9的整型变量的值为0xaa66 要对绝对地址赋值,我们可以用

    2024年02月16日
    浏览(40)
  • C语言中链表经典面试题目

    🐶博主主页: @ᰔᩚ. 一怀明月ꦿ  ❤️‍🔥 专栏系列: 线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++ 🔥 座右铭: “不要等到什么都没有了,才下定决心去做” 🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀   目录 环

    2024年02月02日
    浏览(81)
  • 经典C语言题目程序题(函数篇)

    经典的C语言函数篇题目,看完你期末考试就没有问题了!快来一起看看吧!!! 目录 1.编写一个函数,可以算出 任意两个整数的和,并返回相应的结果 2. 编写一个函数可以求出任意三个整数之中的最大值,并返回其最大值 3.编写一个函数,可以实现给出算数运算的功能,

    2024年02月01日
    浏览(56)
  • 【C语言基础考研向】11 gets函数与puts函数及str系列字符串操作函数

    gets函数类似于scanf函数,用于读取标准输入.前面我们已经知道scanf函数在读取字符串时遇到空格就认为读取结束,所以当输入的字符串存在空格时,我们需要使用gets 函数进行读取. gets函数的格式如下: gets函数从STDIN (标准输入)读取字符并把它们加载到str(字符串)中,直到遇

    2024年01月22日
    浏览(55)
  • 递归究竟是什么?如何快速编写正确的递归代码? —— 力扣经典面试题详解

    下面是来自百度百科对递归算法的定义:  递归是一种算法设计技术,它允许一个函数在其定义或说明中有直接或间接调用自身的方法。  递归在数学和计算机科学中有着广泛的应用,它通过将复杂问题分解为规模较小、形式相同的子问题来求解。递归的基本原理包括:每

    2024年04月09日
    浏览(52)
  • C语言必背经典程序代码

    题目:打印出所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数   本身。例如:153是一个“水仙花数”,因为153=1的三次方+5的三次方+3的三次方。 使用函数封装,实现一个整型数组内数据的求和。 斐波那契数列(Fibonacci sequence),又称

    2023年04月20日
    浏览(43)
  • C语言经典游戏代码大全(珍藏版)

    发现很多朋友都想要一些小项目来练手,却找不到从哪里寻找,给大家整理了游戏项目开发源代码汇总。 END 源代码比较长只能先放上去这么多,还有更多的小项目 加一下我的c/c++编程资料交流Q群:214574728

    2024年02月11日
    浏览(39)
  • 【C语言】十大经典排序代码及GIF演示

    🔥🔥🔥专栏推荐:C语言基础语法🔥🔥🔥

    2024年02月02日
    浏览(32)
  • C语言(输入输出函数getchar,putchar、gets、puts,scanf,printf的功能以及用法)

    int getchar( void ); 返回值为int,所以需要用一个int变量来接收,不管输入几个字符,每次都只接收第一个字符,常与while和putchar配合使用。 从下面这张图可以看出,输入一个空格也会打印 当然,获取一个字符用得不多,每次都需要获取一串,所以我们可以配合while来使用。 用

    2024年02月02日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包