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

2021/6/6 1:24:10

本文主要是介绍【C/C++教程】关于C/C++那些坑爹的破事儿,你被坑了吗?,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=


1

printf也风骚型

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

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

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

蛋是!!!

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

一丝Q死迷???

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

从右往左

从右往左

从右往左

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

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

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

最后输出自然是3 3 1。

2

编译器也偷懒型

Talk is cheap。Show me the code.

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

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

呃,咱们run一下吧。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

别急!

听老衲慢慢道来

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

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

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

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

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

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

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

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

没必要做后面的运算了。

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

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

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

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

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


3

当switch没有了break

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

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

在写switch case语句的时候,

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

但是实际开发中,

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

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

switch语句

是有多风骚

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

运行结果:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

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

才会执行。

然而,是我想错了。

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

就有着一种贯穿的思想

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

如果没有break

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

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

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

4

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

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

答案是不会!


再看:这个会报错吗?

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

答案,YES!

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

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

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

那么对于全局变量,

声明+赋值=定义

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

只要没有赋值,

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

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

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

最后一条声明为定义。

说白了就是,

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

而第二个程序就不同了,

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

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

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


5

static原来是这样

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

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

先看代码:

可以预测一下输出结果嘛

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

将变量声明为static以后,

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

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

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

也是唯一的一次初始化

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

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

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

static int num = 10

这条语句不会在执行。

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


6

printf继续风骚型


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

先看代码:

输出多少?

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

看结果:


watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=


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

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

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

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

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

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

-1的补码就是32个1。

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

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


watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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




这篇关于【C/C++教程】关于C/C++那些坑爹的破事儿,你被坑了吗?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程