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

背景:


阅读新闻

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

[日期:2015-03-15]

来源:Linux社区

作者:xiaomanon

[字体:大 中 小]

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

1 gets()方法

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

1 #include

2

3 int main(void)

4 {

5 char buff[10];

6 memset(buff, 0, sizeof(九度快排系统 https://www.190seo.combuff));

7 gets(buff);

8 printf("%s\n", buff);

9

10 return 0;

11 }

A:这个不显眼的问题就是使用了gets()方法,其函数原型如下:

char* gets(char *s);

此方法接受一个字符数组参数,但是却没有检查此数组是否有足够的空间来拷贝数据。gets()函数是不安全的,不推荐使用,一般情况下编译器也会给出警告提示:the `gets' function is dangerous and should not be used。gets()不检查预留存储区是否能够容纳实际输入的数据。多出来的字符简单的溢出到相邻的存储区,可能会导致错误。

所以,这里我们一般用fgets()方法更好,函数原型如下:

char* fgets(char *s, int n, FILE *stream);

一般使用fgets()函数,都是读取文件当中的n-1个字符到s中,其实,此函数还有一个很好的用处就是从标准输入流中读取字符串,而且不用担心输入的字符个数超出了字符数组的大小而导致溢出的问题!要怎样做呢?如下:

char str[10];

fgets(str, siezof(str), stdin);

值得注意的是:谨记fgets()只读取n-1个字符。所以,fgets()读取到换行符、文件尾或读完n-1个字符便会进行返回。

2 strcpy()方法

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

1 #include

2 #include

3 int main(int argc, char *argv[])

4 {

5 int flag=0;

6 char passwd[10];

7

8 memset(passwd, 0, sizeof(passwd));

9 strcpy(passwd, argv[1]);

10

11 if (0==strcmp("LinuxGeek", passwd)){

12 flag=1;

13 }

14 if (flag){

15 printf("\n Password cracked \n");

16 }else{

17 printf("\n Incorrect password \n");

18 }

19

20 return 0;

21 }

说明:该程序通过在运行时携带一个密码参数,然后程序会将用户输入的密码参数值与真实的密码比较,如果两者相等就输出cracked信息,否则输出incorrect提示。

3 main()函数的返回类型

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

#include

#include

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返回类型可以返回程序运行的状态值,尤其是当这段程序作为其他应用的附属程序时这个状态值将更加重要。

mainret.c:3:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]

void main(void)

^

4 内存泄漏

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

#include

#include

int main(void)

{

char *ptr=(char*)malloc(10);

if (NULL==ptr){

printf("\n Malloc failed \n");

return -1;

}else{

//Do some processing

}

return 0;

}

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

5 free()方法

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

1 #include

2 #include

3 #include

4 int main(int argc, char *argv[])

5 {

6 char *ptr=(char *)malloc(10);

7

8 if (NULL==ptr){

9 return -1;

10 }

11 if (argc==1){

12 printf("\n Usage: add a string \n");

13 }else {

14 memset(ptr, 0, 10);

15 strncpy(ptr, argv[1], 9);

16 while (*ptr !='z'){

17 if (*ptr==' ') break;

18 else ptr++;

19 }

20 if (*ptr=='z'){

21 printf("\n String contains 'z' \n");

22 //Do some more processing

23 }

24 free(ptr);

25 }

26

27 return 0;

28 }

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

注意:调用free()方法释放内存时,参数必须要么是NULL,要么是先前从malloc/calloc或者realloc返回的地址,不能将一次动态申请的内存的部分释放。

6 atexit()和_exit()

Q:以下代码中的atexit()方法并没有被调用,直到为什么吗?

#include

#include

void func(void)

{

printf("\n Clean up function called \n");

}

int main(void)

{

int i=0;

atexit(func);

for (; i < 0xFFFF; i++);

_exit(0);

}

A:这是因为使用了 _exit() 方法。此方法并没有调用清除数据相关的方法,比如 atexit()等。exit和_exit都是用来正常终止一个进程的,主要区别是_exit会立刻进入内核,而exit先执行一些清除工作(包括执行各种终止处理程序,关闭所有标准I/O等,一旦关闭了IO,例如printf等函数就不会输出任何东西了),然后才进入内核。这两个函数会对父子进程有一定的影响,当用vfork创建子进程时,子进程会先在父进程的地址空间运行(这跟fork不一样),如果子进程调用了exit就会把父进程的IO给关掉。

7 void*与C结构体

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

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

int func(void *ptr)

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

8 *与++运算符

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

#include

int main(void)

{

char *ptr="Linux";

printf("\n [%c] \n", *ptr++);

printf("\n [%c] \n", *ptr);

return 0;

}

A:程序的输出结果如下:

[L]

[i]

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

9 Making changes in code segment

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

1 #include

2 int main(void)

3 {

4 char *ptr="Linux";

5 *ptr='T';

6 printf("\n [%s] \n", ptr);

7

8 return 0;

9 }

A:这是因为字符串常量“Linux”是以只读的形式存储的,而通过*ptr='T'语句,此代码尝试更改只读内存存储的字符串内容,此操作当然行不通,所以才会导致崩溃。

10 Process that changes its own name

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

A:以下的代码可以:

1 #include

2 #include

3

4 int main(int argc, char *argv[])

5 {

6 int i=0;

7 char buff[100];

8

9 memset(buff, 0, sizeof(buff));

10 strncpy(buff, argv[0], sizeof(buff));

11

12 memset(argv[0], 0, strlen(buff));

13 strncpy(argv[0], "NewName", 7);

14 //Simulate a wait. Check the process name at this point

15 for (; i < 0xFFFFFFFF; i++);

16

17 return 0;

18 }

可以通过下面的方法测试

$ gcc chname.c -o chname

$ http://www.linuxidc.com/Linux/2015-03/chname &

[1] 4677

$ ps 4677

PID TTY STAT TIME COMMAND

4677 pts/11 R 0:08 NewName

11 局部变量的返回地址

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

1 #include

2 int* inc(int val)

3 {

4 int a=val;

5 a++;

6 return &a;

7 }

8

9 int main(void)

10 {

11 int a=10;

12 int *val=inc(a);

13 printf("\n Increamented value is equal to [%d] \n", *val);

14

15 return 0;

16 }

A:虽然上面的代码有时运行会很好,但是在方法 inc() 中有很严重的隐患,因为它返回了局部变的地址。当inc()方法执行后,再次使用局部变量的地址就会造成不可估量的结果。解决之道就是传递变量a的地址给main()。PS:我觉得最后一句的说法有问题。

12 处理printf()参数

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

#include

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:程序的输出如下:

110..40..60

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

本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-03/115021.htm

linux

C语言中的程序终止函数

C#函数式编程之序列

相关资讯

C语言

C语言中switch...case语句中break (今 08:31)

从汇编来看C语言 (12/28/2016 10:11:34)

嵌入式开发中常见3个的C语言技巧 (11/22/2016 11:28:35)

C语言的基本概念 (02月26日)

浅谈单片机中C语言与汇编语言的转 (12/27/2016 10:25:56)

在C语言中*p++与(*p)++的区别 (10/30/2016 18:11:58)

本文评论

查看全部评论 (0)

表情: 表情

姓名:

匿名

字数

同意评论声明

评论声明

尊重网上道德,遵守中华人民共和国的各项有关法律法规

承担一切因您的行为而直接或间接导致的民事或刑事法律责任

本站管理人员有权保留或删除其管辖留言中的任意内容

本站有权在网站内转载或引用您的评论

参与本评论即表明您已经阅读并接受上述条款

最新资讯

C语言中switch...case语句中break的重要性

Yelp是如何实现每天运行数百万个测试的

Android系统的使用量全面超过Windows

Elastic Stack发布新版本支持机器学习

Web服务器之争:Nginx达到33.3%,而Apache

Facebook Live的扩展之道

红帽RHEL7.0版RHCE考试历程笔记

Oracle实例crash,报错信息ORA-00600、ORA-

Oracle出现ORA-01033和ORA-00600异常解决方

Oracle报错ORA-00600 [4400]产生原因及解决

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容