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

前文链接:http://www.cnblogs.com/pmer/p/3324063.html

8,Making changes in Code segment 
Q:以下代码运行时一定会崩溃,你能说出原因吗?

#include<stdio.h>
 
int main(void)
{
    char *ptr = "Linux";
    *ptr = 'T';
 
    printf("\n [%s] \n", ptr);
 
    return 0;
}

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

Answer: This is because, through *ptr = ‘T’, the code is trying to change the first byte of the string ‘Linux’ kept in the code (or the read-only) segment in the memory. This operation is invalid and hence causes a seg-fault or a crash.

评:

  很难说这段代码一定崩溃(crash)或发生段错误(seg-fault)。
  在C标准中,修改String literal(The program attempts to modify a string literal)是一种UB(undefined behavior),即未定义行为。用通俗的话来讲,就是C语言没规定这样写有意义。这种情况下,什么事情都可能发生,无论发生什么,都是代码的错误,是程序员的责任。

  事实上,修改String literal可能导致各种结果,有些情况下也可能执行时并不产生崩溃或段错误。

  K&R认为修改String literal应该规定为unspecified behavior(不同于undefined behavior,unspecified behavior可能有多种结果,但代码本身不存在语义错误,而undefined behavior是没有语义),但标准委员会并没有采纳K&R的建议。

  对照一下原文,不难发现译文漏掉了in the code segment。

  但原文说string literal存于代码段或只读段,也是不正确的。这种说法没有依据。C语言并没有规定实现应该把string literal存放在什么地方,这是由实现自己安排的事情。

9,Process that changes its own name Q:你能否写一个程序在它运行时修改它的名称? (Can you write a program that changes its own name when run?)
A:以下代码可以完成 :
Answer: Following piece of code tries to do the required :

#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;
}

评:

  这个问答比较雷人。

  首先标题是要改变Process的名字,问题是Process有名字吗?

  但在Question中又说要在运行时改Program的名字。如果说Program有名字,那么就只可能是对应可执行文件的名字。可执行文件的名字和Process的名字是无法划等号的。

  Process通常是通过PCB(Process Control Block)管理,其标识的方法通常是id号,当然,PCB中也有所谓外部标识符。如果把PCB的外部标识符理解为Process的名字,虽然极为牵强,但舍此似乎也无法再有任何其他解释了。

  查了一下,某些语言中似乎有Process Name这个概念,也有相关的函数。但是C语言中没有这个概念。

  再看代码,无非是修改了一下argv[0]所指向的字符串而已。尽管argv[0]指向的字符串确实是程序的名称,但这种改变没有实际意义——下次启动程序还得用原来的名字,因为外存中可执行文件的名字并没有改变。

  代码中的注释部分又提到了Process Name,就这样一会Process Name,一会又是Program Name,题目的设计者自己明显概念不清。

  注释说在这里模拟等待,搞不清究竟要在这里等什么。怎么看都觉得是在装模作样。
  再来看代码风格。

int i = 0;
 //……
for(;i<0xffffffff;i++);

  把for语句分为两部分来写,风格乖张。

  把循环体部分的空语句写在行尾,也是一种恶习。对比一下下面的写法就知道了:

for ( i = 0 ; i < 0xffffffff ; i ++ )
   ;

  这条for语句本身的语义在一定也成问题。假如int类型的最大值为0x7fffffff,当i值达到int类型最大值之后,i再自加就溢出了。而溢出,是一种未定义行为。

  也就是说,这条语句说的很可能并不是让i值从0逐次加1一直变化到0xffffffff-1。代码作者心里想的究竟是什么,也许他自己都不知道。顺便说一下,int类型的最大值为0x7fffffff时,0xffffffff不是int类型,而是unsigned int类型。

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);

  这段代码,依然是很蠢。首先莫名其妙地把buff清0:

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

  实际上去掉这句没有任何问题。因为后面的

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

  还要再次填充\0。举个例子,下面代码段

char s[4];
strncpy( s , "1" , 4);
printf("%d %d %d %d\n",s[0],s[1],s[2],s[3]);

的输出,一定是

49 0 0 0

  这就说明,原来代码中memset()填充的0毫无意义,因为紧接着还要再填充一次。我不是说memset()没用,但到现在为止我看到的大多数memset()都是稀里糊涂地在做无用功,是在滥用memset()。再次说明了很多使用memset()的人根本不知道自己的代码究竟是在做什么。所谓对“大型商业程序,这是良好代码风格的习惯”云云,纯粹是胡扯。

  后面一句

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

不但没用,逻辑上也有点荒唐。应该

memset(argv[0],0,strlen(argv[0]));<br>

才合理。尽管我们知道,这里strlen(argv[0])和strlen(buff)的值是一样的。

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

  这一句属于不懂装懂、煞有介事。作者使用strncpy()希望不至于拷贝越界,但这里的7是"NewName"的长度,而不是argv[0]所指向字符串的长度。如果strlen(argv[0])小于7,显然还会发生越界。

  综上所述,这段代码不但不可能改变Program Name,连正确地修改命令行参数都谈不上,更不要说改变Process Name了。  

  所以,这个问答的“问”,是一个哗众取宠的伪问题。“答”则是生拉硬扯、胡编滥造的解答。

 
 
 
标签: C语言面试

《12个有趣的C语言问答》(4)的更多相关文章

  1. 《从零开始做一个MEAN全栈项目》(1)

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 在本系列的开篇,我打算讲一下全栈项目开发的优势,以及MEAN项目各个模块的概览. 为什么选择全栈开发? ...

  2. 《从零开始做一个MEAN全栈项目》(2)

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习.   上一节简单介绍了什么是MEAN全栈项目,这一节将简要介绍三个内容:(1)一个通用的MEAN项目的技 ...

  3. 《从零开始做一个MEAN全栈项目》(3)

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 上一篇文章给大家讲了一下本项目的开发计划,这一章将会开始着手搭建一个MEAN项目.千里之行,始于足下, ...

  4. 《从零开始做一个MEAN全栈项目》(4)

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 在上一篇中,我们讲了如何去构建第一个Express项目,总结起来就是使用两个核心工具,express和 ...

  5. 一个关于vue+mysql+express的全栈项目(一)

    最近学了mysql数据库,寻思着能不能构思一个小的全栈项目,思来想去,于是就有了下面的项目: 先上几张效果图吧       目前暂时前端只有这几个页面,后端开发方面,有登录,注册,完善用户信息,获取用 ...

  6. Vue、Nuxt服务端渲染,NodeJS全栈项目,面试小白的博客系统~~

    Holle,大家好,我是李白!! 一时兴起的开源项目,到这儿就告一段落了. 这是一个入门全栈之路的小项目,从设计.前端.后端.服务端,一路狂飙的学习,发量正在欣喜若狂~~ 接触过WordPress,H ...

  7. Vue、Node全栈项目~面向小白的博客系统~

    个人博客系统 前言 ❝ 代码质量问题轻点喷(去年才学的前端),有啥建议欢迎联系我,联系方式见最下方,感谢! 页面有啥bug也可以反馈给我,感谢! 这是一套包含前后端代码的个人博客系统,欢迎各位提出建议 ...

  8. SpringBoot 整合 Elastic Stack 最新版本(7.14.1)分布式日志解决方案,开源微服务全栈项目【有来商城】的日志落地实践

    一. 前言 日志对于一个程序的重要程度不用过多的言语修饰,本篇将以实战的方式讲述开源微服务全栈项目 有来商城 是如何整合当下主流日志解决方案 ELK +Filebeat . 话不多说,先看实现的效果图 ...

  9. 全栈项目|小书架|服务器端-NodeJS+Koa2实现首页图书列表接口

    通过上篇文章 全栈项目|小书架|微信小程序-首页水平轮播实现 我们实现了前端(小程序)效果图的展示,这篇文章来介绍服务器端的实现. 首页书籍信息 先来回顾一下首页书籍都有哪些信息: 从下面的图片可以看 ...

  10. 全栈项目|小书架|服务器开发-NodeJS 使用 JWT 实现登录认证

    通过这篇 全栈项目|小书架|服务器开发-JWT 详解 文章我们对JWT有了深入的了解,那么接下来介绍JWT如何在项目中使用. 安装 $ npm install jsonwebtoken 生成 Toke ...

随机推荐

  1. Python判断内网IP

    def ip_into_int(ip): # 先把 192.168.1.13 变成16进制的 c0.a8.01.0d ,再去了"."后转成10进制的 3232235789 即可. ...

  2. C#将Excel数据导入数据库(MySQL或Sql Server)

    最近一直很忙,很久没写博客了.今天给大家讲解一下如何用C#将Excel数据导入Excel,同时在文章最后附上如何用sqlserver和mysql工具导入数据. 导入过程大致分为两步: 1.将excel ...

  3. CSharp设计模式读书笔记(6):建造者模式(学习难度:★★★★☆,使用频率:★★☆☆☆)

    建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 模式角色与模式: 建造者模式可以将一个产品的内部表象与产品的生产过程分割开来, ...

  4. Java数据结构与算法(5) - ch05链表(LinkList)

    双端链表与传统链表非常相似,但是它有一个新增的特性:即对最后一个链节点的引用,就像对第一个连接点的引用一样.注意与双向链表进行区别.

  5. poj 2828 Buy Tickets(树状数组 | 线段树)

    题目链接:poj 2828 Buy Tickets 题目大意:给定N,表示有个人,给定每一个人站入的位置,以及这个人的权值,如今按队列的顺序输出每一个人的权值. 解题思路:第K大元素,非常巧妙,将人入 ...

  6. [Asp.net]站点地图SiteMap

    原文:[Asp.net]站点地图SiteMap 引言 在项目中发现使用站点地图的控件,之前没总结过这方面的东西,就写了一个demo测试了一下,这里记录一下,算是总结吧. Web.sitemap < ...

  7. .net EF 事物 订单流水号的生成 (一)

    首先需要 添加 System.Transactions 程序集 数据表: create table SalesOrder ( ID ,) primary key not null, OrderNo ) ...

  8. Spark入门级小玩

    ·背景 随着周边吐槽hadoop的声音渐渐多起来之后,spark也逐渐进入了大家的视野.之前,笔者有粗略的写过一篇spark的安装和性能比较[http://www.cnblogs.com/zacard ...

  9. PHP实例——输出安全的HTML代码

    原文:PHP实例--输出安全的HTML代码 //输出安全的htmlfunction h($text, $tags = null){ $text = trim($text); //完全过滤注释 $tex ...

  10. android如何判断服务是否正在运行状态

    如何检查后台服务(Android的Service类)是否正在运行?我希望我的Activity能够显示Service的状态,然后我可以打开或者关闭它. /** * 判断服务是否处于运行状态. * @pa ...