12个有趣的C语言问答
转自: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 |
这是因为参数都是从右向左处理的,然后打印出来却是从左向右。
12个有趣的C语言问答的更多相关文章
- 12个有趣的C语言问答(详解)
本文参照博文<12个有趣的C语言问答>,在原文的基础上增加来对应的知识点的详细介绍. 1 gets()方法 Q:下面的代码有一个被隐藏的问题,你能找到它吗? #include <st ...
- 《12个有趣的C语言问答》(4)
C语言面试问答——<12个有趣的C语言问答>评析(4) 前文链接:http://www.cnblogs.com/pmer/p/3324063.html 8,Making changes i ...
- 《12个有趣的C语言问答》评析2
<12个有趣的C语言问答>评析(2) 前文链接:http://www.cnblogs.com/pmer/p/3313913.html (没存盘,遭遇过热保护.至少4个问答的评论白写了.默哀 ...
- 12个滑稽的C语言面试问答——《12个有趣的C语言问答》评析(5)
前文链接:http://www.cnblogs.com/pmer/archive/2013/09/17/3327262.html A,局部变量的返回地址 Q:下面的代码有问题吗?如果有,如何修改? # ...
- 12个有趣的c语言面试题
1.gets()函数 问:请找出下面代码里的问题: #include int main(void) { char buff[10]; memset(buff,0,sizeof(buff)); gets ...
- 12个有趣的C语言面试题
摘要:12个C语言面试题,涉及指针.进程.运算.结构体.函数.内存,看看你能做出几个! 1.gets()函数 问:请找出下面代码里的问题: #include<stdio.h> int ma ...
- Ubuntu 12.04上安装R语言
Ubuntu 12.04上安装R语言 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ R的安装 sudo gedit /etc/apt/sources. ...
- 12个有趣的c面试题目
1.gets()函数 问:请找出以下代码里的问题: #include<stdio.h> int main(void) { char buff[10]; memset ...
- 一个有趣的C语言问题
这个问题是知乎上的一个问题,看了以后觉得比较有意思.代码短到只有十多行,但是这么短的代码却输出了很奇怪的结果.很多人回答的时候都是站在理论的角度上说明代码的问题,但是实际的问题还是没有说明其中的问题. ...
随机推荐
- 《2019面向对象程序设计(java)课程学习进度条
周次 (阅读/编写)代码行数 发布博客量/评论他人博客数量 课余学习时间(小时) 学习收获最大的程序 阅读或编译让我 第一周 20/5 1/0 4 编译九九乘法表 第二周 100/10 2/0 5 第 ...
- day8_7.8 文件操作
一.文件模式 1.在文件的操作中,也有很多补充 的模式可使用 1.r+,可读可写模式,在此模式中,操作权限时可读可写,这里的写与write模式不一样的是,不再清空文件内容,写的内容添加到文件的后面,而 ...
- 18-numpy笔记-莫烦pandas-6-plot显示
代码 import pandas as pd import numpy as np import matplotlib.pyplot as plt data = pd.Series(np.random ...
- [CODEVS4632][BZOJ4326]运输计划
题目描述 Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P ...
- 调试经验分享-让自己的电脑充当WI-Fi模块,用来抓取连接Wi-Fi模块APP上的通信数据
需求 手头有了厂家的APP和Wi-Fi模块 在已经知道APP是通过TCP连接Wi-Fi模块(8266), 同时也知道了连接的端口号的 情况下如何知道厂家的APP发送给Wi-Fi模块的数据 打开自己的笔 ...
- 2.GO-可变参数函数、匿名函数和函数变量
2.1.可变参数函数 可变参数指参数的个数可以是任意个 可变参数必须在参数列表最后的位置,在参数名和类型之间添加三个点表示可变参数函数 声明函数时,在函数体把可变参数当作切片使用即可 package ...
- CSP2019 树的重心 题解
本题当然可以通过大力讨论每棵子树的size的大小关系,然后用各种数据结构暴力维护.但是我更倾向于用一种更为性质的做法. 首先讲一下我在考场上想到的做法(没写).就是考虑换根,在换根的过程中计算每一条边 ...
- it's over | 2019 CSP-S 第二轮认证(超长预警)
也许应该从Day -1(2019年11月14日周四)开始说起? 卑微的我们在学长的怂恿下终于...停课了(哇我们太菜了,只停一天半的课有个卵用 早读后我带头去办公室请假,飞哥很大方地答应了,同时免了我 ...
- nginx 目录自动加斜线”/”
默认配置当你访问http://abc.example.com/dir 时不会加”/” 常见做法 if (-d $request_filename){ rewrite ^/(.*)([^/])$ ht ...
- (九)golang--标识符的命名规则
标识符的概念: (1)各种变量.方法等命名时使用的字符序列被称为标识符: (2)凡是可以自己起名字的都可以叫标识符: 标识符的命名规则: (1)由26个英文字母大小写,0-9,_组成 (2)数字不可以 ...