专栏首页程序猿声【C/C++教程】关于C/C++那些坑爹的破事儿,你被坑了吗?

【C/C++教程】关于C/C++那些坑爹的破事儿,你被坑了吗?

开始之前,突然想到一个笑话。有个小伙子去面试的时候,技术没问题了,但是面试官故意各种刁难。最后在小伙子心灰意冷的时候,面试官蛋蛋一笑。“小伙子,你看你这么多问题都不会。摆明的技术不过关啊,不如先在公司里学习一段时间吧,月薪就给你2000怎样?” 卧槽,感情这tm都是坑我的啊?只能说,老哥,社会啊。所以说,基础知识不过关,被坑是常事呀~~~

那么,今天,就带大家看看C/C++里面究竟有多少不为人知的秘(keng)密(die)吧。可以测试一下,不看答案,自己能get到多少。

1

printf也风骚型

在此之前,先看一段简单得不能再简单的代码:

哎,这还不简单嘛?无非就是自增嘛,

第一个a输出1,第二个++a 输出2,

第三个a++用的原来的值再自增所以输出2。

蛋是!!!

一丝Q死迷???

自增没有错,坑就坑在,函数参数的入栈顺序是

从右往左

从右往左

从右往左

重要的事情说三遍,这就很好解释了。

先是a++,将a=1入栈,再自增。

而后++a,此时将a=3入栈,

最后输出自然是3 3 1。

2

编译器也偷懒型

Talk is cheap。Show me the code.

So,猜猜下面的代码输出结果是?

哎,这么简单的玩意儿,不是小瞧我胖虎嘛?

两个自增,绝逼是两个2啊。

呃,咱们run一下吧。

心里瞬间万头草泥马在奔腾啊

别急!

听老衲慢慢道来

在此之前,先复习一下&&和||运算符,

&&就是两个表达式为真最终结果才为真,

||是两个中只要有一个为真那么结果就为真。

于是乎,关于a++&&++a.

由于a初始为0,a++后自增,先把值拿来用了在让a+1。

所以整个表达式可以看作是0&&2,

但是编译器坑爹啊,他读到0,然后发现,这是一个&&操作。

有一个都是假了那最后结果肯定也是假的,

没必要做后面的运算了。

所以,++a那一句编译器并不会再去理会,

最终的结果是,a只自增了一次。

对于||操作,道理也是一样的。

当他发现||左边的表达式为真(非0)时,

后面的编译器不在理会。这点大家记住。

3

当switch没有了break

switch case语句是一个很神奇的东西,

我也是近来才了解原来他还有这种操作。

在写switch case语句的时候,

我们被要求每一条语句都写上break。

但是实际开发中,

往往会有那么几个人由于疏漏忘了写break子句导致莫名的结果错误。

下面我们来看看没有了break的

switch语句

是有多风骚

嗯,这次就不再用++来玩大家了

运行结果:

之前我一直以为,就算没有break

后面的语句也只会在符合条件的情况下

才会执行。

然而,是我想错了。

上网查了一下,switch语句设计的初衷

就有着一种贯穿的思想

说白了 就是,符合某个case分支以后

如果没有break

那么后面的case 子句无论如何都会执行

所以,你如果只想执行一个条件

别忘了在每个分支后面写上break

4

关于声明和定义,你知多少

下面代码是在C平台上运行的。C++不允许这么干了。

那么,你觉得下面的代码C编译器会报错吗?

答案是不会!

再看:这个会报错吗?

答案,YES!

这就很扎心了,两段代码,位置不一样,还出错了???

嗯,这里就要讲讲声明和定义的区别了。

第一个程序int a是写在全局变量区的,

那么对于全局变量,

声明+赋值=定义

也就是之前无论我们int a多少次

只要没有赋值,

那么编译器就会默认我们这是一条声明。

声明嘛,你想声明多少次都行。

如果都是声明没有赋值,那么编译器就会默认

最后一条声明为定义。

说白了就是,

声明可以有多个,但是定义只能有一个

而第二个程序就不同了,

由于int a 是写在局部变量区域,

对于局部变量来说,无论是否赋值都是定义

所以这里编译器会给出一个重定义的CE。

5

static原来是这样

关于static可以说的实在太多了,但是今天只说一点。

也是各位新手朋友经常犯的。

先看代码:

可以预测一下输出结果嘛

将变量声明为static以后,

该变量会放在全局静态区。

那么这个区域的变量有几个特点

会在程序刚开始运行时就完成初始化,

也是唯一的一次初始化

如果没有初始化,编译器默认初始化为0

于是乎,由于上述程序num只初始化了一次,

所以在后面的9次test()函数的调用中,

static int num = 10

这条语句不会在执行。

因此才会有上面的输出的输出结果

6

printf继续风骚型

关于printf的输出,也是面试官们经常拿来玩的一个埂,通过这个可以看出你对基础知识的把握程度。

先看代码:

输出多少?

看结果:

为什么会出现这个情况呢?

这是因为,printf输出的时候,

并不会去判断变量的类型,

他很听话,只会按照你给的格式控制符去内存中解析数据然后输出

比如整数在内存中是以补码的形式存在的。

(关于源码补码知识不在赘述,读者可自行上网了解)

-1的补码就是32个1。

那么32个1,按照有符号整数来解析就是-1

按照无符号来解析就是上面的结果。等等。

今天就先写到这吧,C/C++还有很多值得大家注意的地方,比如C的宏函数带来的运算级问题,结构体对齐等等,const和指针引发的一系列血案等等。咱们下次有空再聊。

END

本文分享自微信公众号 - 程序猿声(ProgramDream),作者:Rivals

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-12-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 转载 | Python AI 教学│k-means聚类算法及应用

    假如有这样一种情况,在一天你想去某个城市旅游,这个城市里你想去的有70个地方,现在你只有每一个地方的地址,这个地址列表很长,有70个位置。事先肯定要做好攻略,你...

    短短的路走走停停
  • 嘿胸第,暑假还在玩?快来和我一起刷题吧

    对任何一个自然数n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把(3n+1)砍掉一半。这样一直反复砍下去,最后一定在某一步得到n=1。卡拉兹在1950年...

    短短的路走走停停
  • 干货 | 数据结构与算法 - 什么是算法

    大家好呀, 我是小玮~今天给大家带来的是学习笔记之数据结构与算法--什么是算法。

    短短的路走走停停
  • 十年磨一剑!万字长文剖析华为方舟编译器的前世今生

    2017年5月的一个凌晨,华为某实验室里,方舟编译器上第一个Java程序“Hello, World”跑通了。

    新智元
  • vim 编辑器常用命令

    Vim是从vi发展出来的一个文本编辑器。其代码补完、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。linux 系统用户最喜欢的编辑器。

    六小登登
  • 聊一聊微信小程序包内容

    本文是对上次公众号发文《微信小程序逆向源码深度揭秘》 的扩展,着重探究小程序包的主要内容构成。

    薛定喵君
  • 使用VisualGDB开发Keil MDK-ARM项目

    本教程展示了如何使用VisualGDB使用Keil MDK-ARM编译器构建项目,使用VisualGDB智能感知包括CodeMap,并使用Visual Stud...

    小锋学长
  • 基于RBAC模型的权限系统设计(Github开源项目)

    计划在Team的Github开源项目里加入权限控制的业务功能。从而实现权限控制。在很多管理系统里都是有权限管理这些通用模块的,当然在企业项目里,权限控制是很繁杂...

    SmileNicky
  • MVC 通过Jquery获取视图中所有控件的值

    在使用MVC开发Web时,有需求要将页面所有控件及其值传递到客户端与预定义的界面字段配置进行匹配。

    aehyok
  • 队花的烦恼一

    ACM队的队花C小+经常抱怨:“C语言中的格式输出中有十六、十、八进制输出,然而却没有二进制输出,哎,真遗憾!谁能帮我写一个程序实现输入一个十进制数n,输出它的...

    书童小二

扫码关注云+社区

领取腾讯云代金券