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

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

1.printf也风骚型


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


微信图片_20220420183935.png


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

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

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

蛋是!!!


微信图片_20220420184011.png


一丝Q死迷???

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


从右往左

从右往左

从右往左


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

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

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

最后输出自然是3 3 1。


2.编译器也偷懒型


Talk is cheap。Show me the code.


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


微信图片_20220420184124.png


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

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

呃,咱们run一下吧。


微信图片_20220420184131.png


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

别急!


听老衲慢慢道来

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

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

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

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

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

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

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

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

没必要做后面的运算了。

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

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

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

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

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


3.当switch没有了break


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

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

在写switch case语句的时候,

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

但是实际开发中,

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

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

switch语句

是有多风骚

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


微信图片_20220420184304.jpg


运行结果:


微信图片_20220420184333.jpg


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

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

才会执行。

然而,是我想错了。

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

就有着一种贯穿的思想

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

如果没有break

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

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

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


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


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

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


微信图片_20220420184444.png


答案是不会!


再看:这个会报错吗?


微信图片_20220420184452.png


答案,YES!

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

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

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

那么对于全局变量,

声明+赋值=定义

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

只要没有赋值,

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

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

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

最后一条声明为定义。

说白了就是,

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

而第二个程序就不同了,

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

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

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


5.static原来是这样


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

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

先看代码:

可以预测一下输出结果嘛


微信图片_20220420184702.jpg

微信图片_20220420184706.png


将变量声明为static以后,

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

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

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

也是唯一的一次初始化

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

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


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

static int num = 10

这条语句不会在执行。

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

6.printf继续风骚型


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

先看代码:

输出多少?


微信图片_20220420184753.png

微信图片_20220420184757.png


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

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

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

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

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

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

-1的补码就是32个1。

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

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


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


相关文章
|
1月前
|
存储 网络协议 Ubuntu
【C++网络编程】Socket基础:网络通讯程序入门级教程
【C++网络编程】Socket基础:网络通讯程序入门级教程
55 7
|
1月前
|
编译器 开发工具 C++
Dev-C++详细安装教程及中文设置(附带安装包链接)
Dev-C++详细安装教程及中文设置(附带安装包链接)
78 0
|
2月前
|
程序员 API 数据库
【Cmake工程 库相关教程 】深入理解CMake工程C/C++ 库管理技巧
【Cmake工程 库相关教程 】深入理解CMake工程C/C++ 库管理技巧
71 1
|
2月前
|
存储 并行计算 前端开发
【C++ 函数 基础教程 第五篇】C++深度解析:函数包裹与异步计算的艺术(二)
【C++ 函数 基础教程 第五篇】C++深度解析:函数包裹与异步计算的艺术
42 1
|
2月前
|
数据安全/隐私保护 C++ 容器
【C++ 函数 基础教程 第五篇】C++深度解析:函数包裹与异步计算的艺术(一)
【C++ 函数 基础教程 第五篇】C++深度解析:函数包裹与异步计算的艺术
53 0
|
2月前
|
设计模式 算法 C++
【C++ 泛型编程 进阶篇】C++元模板编程与设计模式的结合应用教程(二)
【C++ 泛型编程 进阶篇】C++元模板编程与设计模式的结合应用教程
30 0
|
2月前
|
Java 程序员 Maven
【C/C++ CommonAPI入门篇】深入浅出:CommonAPI C++ D-Bus Tools 完全使用教程指南
【C/C++ CommonAPI入门篇】深入浅出:CommonAPI C++ D-Bus Tools 完全使用教程指南
71 0
|
1月前
|
编译器 C语言 C++
VSCode上搭建C/C++开发环境(vscode配置c/c++环境)Windows系统---保姆级教程
VSCode上搭建C/C++开发环境(vscode配置c/c++环境)Windows系统---保姆级教程
|
1月前
|
存储 编译器 程序员
【C++入门篇】保姆级教程篇【中】
【C++入门篇】保姆级教程篇【中】
|
1月前
|
安全 编译器 程序员
【C++入门篇】保姆级教程篇【上】
【C++入门篇】保姆级教程篇【上】