转自:http://www.admin10000.com/document/913.html

1,gets() 方法

  Q:以下代码有个被隐藏住的问题,你能找到它吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
#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;
}

  A:这个不显眼的问题就是使用了 gets() 方法。此方法接受一个string类型参数,但是却没有检测此数值是否 有足够的空间来拷贝数据。所以这里我们一般用 fgets() 方法将来的更好。

2,strcpy() 方法

  Q:密码防护是很基本的功能,看看能否搞定下面这段代码?

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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;
}

3,main() 方法的返回类型

  Q:请问下面这段代码能否通过编译?如果能的话,那么这段代码中隐含什么问题吗?

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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;
}

  A:答案是代码能通过编译,但是会留下针对main()方法的返回类型的警告。main()方法的真正返回类型应该为'int'而非'void'。这是因为'int'返回类型能够让程序返回状态值。尤其是当这段程序作为其他应用的附属程序时这个状态值将更加重要。

4,内存泄露

  Q:请问以下代码有内存泄露吗?

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#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;
}

  A:好,虽然上面的代码没有对指针 ptr 进行内存释放,但实际上即使是程序结束也不会造成内存泄露,因为当程序结束时所有一开始被占据的内存就全部清空了。但如果上面这段代码是在 while 循环里面那将会造成严重的问题。

  Note: 如果你需要了解更多关于内存泄露的问题以及如何使用工具检测内存泄露,你可以参考这篇文章 Valgrind

5,free() 方法

  Q:以下代码当用户输入'freeze'时会奔溃,而如果输入'zebra'则运行正常,这是为什么?

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#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;
}

  A:问题的根源是因为代码在while循环中改变了 ptr 指针的地址。当输入为'zebra'时,while循环甚至在执行 第一遍前就结束了,所以free()释放的内存地址就是一开始malloc()分配的地址。但是当输入'freeze'时, ptr记录的地址在while循环中被更改,因为将会是错误的地址传递到free()方法中引起崩溃。

6,atexit with _exit

  Q:在以下代码,atexit()方法并没有被调用,你知道为什么吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#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);
}

  A:这是因为使用了 _exit() 方法。此方法并没有调用清除数据相关的方法,比如 atexit()等。

7,void* 与 C 结构体

  Q:能否设计一个方法接受任意类型的参数然后返回整数?同时是否有办法传递多个这样的参数?

  A:一个能接受任意类型参数的方法像下面这个样子:

 
1
int func(void *ptr)

  如果需要传递多个参数,那么我们可以传递一个包含这些参数的结构体

8,* 与 ++ 操作符

  Q:以下代码将输出什么?为什么?

 
1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
   
int main(void)
{
    char *ptr = "Linux";
    printf("\n [%c] \n",*ptr++);
    printf("\n [%c] \n",*ptr);
   
    return 0;
}

  A:以上的输出将是:

 
1
2
3
[L] 
   
[i]

  因为++与 * 的优先级一样,所以 *ptr++ 将会从右向左操作。按照这个逻辑,ptr++ 会先执行然后执行*ptr。所以第一个结果是'L'。也因为 ++ 被执行了,所以下一个printf() 结果是'i'。

9,Making changes in Code segment

  Q:以下代码运行时一定会崩溃,你能说出原因吗?

 
1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
   
int main(void)
{
    char *ptr = "Linux";
    *ptr = 'T';
   
    printf("\n [%s] \n", ptr);
   
    return 0;
}

  A:这是因为,通过 *ptr = 'T',此行代码尝试更改只读内存存储的字符串'Linux'。此操作当然行不通所以才会造成崩溃。

10,Process that changes its own name

  Q:你能否写一个程序在它运行时修改它的名称?

  A:以下代码可以完成

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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,局部变量的返回地址

  Q:下面的代码有问题吗?如果有,如何修改?

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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;
}

  A:虽然上面的代码有时运行会很好,但是在方法 inc() 中有很严重的隐患。当inc()方法执行后,再次使用局部变量的地址就会造成不可估量的结果。解决之道就是传递变量a的地址给main()。

12,处理 printf() 参数

  Q:以下代码输出请问是什么?

 
1
2
3
4
5
6
7
8
9
10
#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;
}

  A:输出将是

 
1
110..40..60

  这是因为参数都是从右向左处理的,然后打印出来却是从左向右。

英文原文:c-interview-questions

12个有趣的C语言问答的更多相关文章

  1. 12个有趣的C语言问答(详解)

    本文参照博文<12个有趣的C语言问答>,在原文的基础上增加来对应的知识点的详细介绍. 1 gets()方法 Q:下面的代码有一个被隐藏的问题,你能找到它吗? #include <st ...

  2. 《12个有趣的C语言问答》(4)

    C语言面试问答——<12个有趣的C语言问答>评析(4) 前文链接:http://www.cnblogs.com/pmer/p/3324063.html 8,Making changes i ...

  3. 《12个有趣的C语言问答》评析2

    <12个有趣的C语言问答>评析(2) 前文链接:http://www.cnblogs.com/pmer/p/3313913.html (没存盘,遭遇过热保护.至少4个问答的评论白写了.默哀 ...

  4. 12个滑稽的C语言面试问答——《12个有趣的C语言问答》评析(5)

    前文链接:http://www.cnblogs.com/pmer/archive/2013/09/17/3327262.html A,局部变量的返回地址 Q:下面的代码有问题吗?如果有,如何修改? # ...

  5. 12个有趣的c语言面试题&nbsp;

    1.gets()函数 问:请找出下面代码里的问题: #include int main(void) { char buff[10]; memset(buff,0,sizeof(buff)); gets ...

  6. 12个有趣的C语言面试题

    摘要:12个C语言面试题,涉及指针.进程.运算.结构体.函数.内存,看看你能做出几个! 1.gets()函数 问:请找出下面代码里的问题: #include<stdio.h> int ma ...

  7. Ubuntu 12.04上安装R语言

    Ubuntu 12.04上安装R语言 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ R的安装 sudo gedit /etc/apt/sources. ...

  8. 12个有趣的c面试题目

    1.gets()函数 问:请找出以下代码里的问题: #include<stdio.h>  int main(void)  {      char buff[10];      memset ...

  9. 一个有趣的C语言问题

    这个问题是知乎上的一个问题,看了以后觉得比较有意思.代码短到只有十多行,但是这么短的代码却输出了很奇怪的结果.很多人回答的时候都是站在理论的角度上说明代码的问题,但是实际的问题还是没有说明其中的问题. ...

随机推荐

  1. [网络] 在浏览器输入URL回车之后发生了什么

    目录 一  前言 二  URL解析 三  DNS域名解析 1  IP 地址 2  什么是域名解析 3  浏览器如何通过域名去查询 URL 对应的 IP 呢 4  小结 四  建立连接 1  TCP三次 ...

  2. 201871010133-赵永军《面向对象程序设计(java)》第十六周学习总结

    201871010133-赵永军<面向对象程序设计(java)>第十六周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ ...

  3. CF1045B Space Isaac

    原题链接 DOWNLOAD AS PDF 题目大意 \(0\sim m-1\)的数被分成两个集合,你可以分别从两个集合中取一个数相加并对\(m\)取模,求一不能构造出的数. 题解 感觉如果\(\col ...

  4. xgboost:

    https://www.zybuluo.com/Dounm/note/1031900 GBDT算法详解 http://mlnote.com/2016/10/05/a-guide-to-xgboost- ...

  5. C++面向对象程序设计学习笔记(4)

    类与对象(2) string类 C++不仅向下兼容C的字符表示方法,也声明了一种更方便的字符串类型,即string类. 想要使用string类,必须包括头文件string,即要声明 #include& ...

  6. ESP8266 LUA脚本语言开发: 准备工作-为方便学习(统一使用本人编译的固件)

    前言 注:为了咱后期统一起来,所以统一使用我编译的LUA固件 一,固件打开了SmartConfig / AirKiss 配网功能 二,打开了SSL 三,其它模块化程序 刷空固件 一,为了保证固件是干净 ...

  7. Git的回滚

    Git常用命令: git add .   #进行提交 git commit -m v2 #v2版本 cat index.html #查看文件内容已经变化 git log #获取到提交信息 git re ...

  8. Spring Cloud Gateway 之 AddRequestHeader GatewayFilter Factory

    今天我们来学习下GatewayFilter Factory,中文解释就是过滤器工厂. 官方文档对GatewayFilter Factory的介绍: Route filters allow the mo ...

  9. 可以在shell脚本中使用哪些类型的变量?

    在shell脚本,我们可以使用两种类型的变量: 系统定义变量 用户定义变量 系统变量是由系统系统自己创建的.这些变量通常由大写字母组成,可以通过“set”命令查看. 用户变量由系统用户来生成和定义,变 ...

  10. 作业帮:给定一个整数数组,找出其中两个数相加等于目标值(去重set)

    题目描述 给定一个整数数组,找出其中两个数相加等于目标值 输入 [1,3,5,7,9,11] 10 输出 1,9 3,7 代码: import java.util.HashMap; import ja ...