C语言经典错误总结(一)

注:本文是结合《C陷阱和缺陷》所写!

一.=和==

我们都知道在C语言中**=** 表示赋值操作符,**==**表示比较,那么你知道为啥单等号为=,双等号为比较吗?

这里扩展下:因为在C语言中赋值操作符相对于比较符号较常出现,因此字符较少的符号=就被赋予了更常用的含义---赋值操作。

但是这样的便利却带来了一个非常常见错误,赋值操作符和比较运算错用!

看案例:

cs 复制代码
#include <stdio.h>
int main()
{
	char c;
    scanf("%c",&c);
	while (c = ' ' || c == '\t' || c == '\n')
	{
		printf("hello\n");
	}
	return 0;
}

你猜猜结果为啥呢?

结果为无限循环,原因就是因为将第一个==错写成了=,导致出现下述情况:

||优先级大于=优先级(逻辑运算符优先级大于赋值运算符优先级),所以该式子:c = ' ' || c == '\t' || c == '\n'是将 ' ' || c == '\t' || c == '\n'表达式结果赋值给c,然后判断是否为真,是真就继续下循环,因此出现无限循环的情况。

在为大家写一种两者区分写的特殊情况:

cs 复制代码
#include <stdio.h>
int main()
{
	int x;
	int y;
	if (x = y)
	{
		;
	}
	return 0;
}
//目的是将y的值赋值给x,并判断新值是否为0

如果我们完成上述目的直接这样写,可能你所在的编译器不会报错,但实际这种代码是非常不可取的,我们可以这样写:

cs 复制代码
#include <stdio.h>
int main()
{
	int x;
	int y;
	if ((x=y)!=0)
	{
		;
	}
	return 0;
}

这样可以目的一目了然,也可以防止自己误判!

总结:

因此在写C语言代码用到=和==时,一定要问自己一句,到底要干什么!!!

二.词法分析之"贪心法"

我们知道C语言符号分为单字符符号和多字符符号,那么你知道计算机是如何判断连续的字符是哪种符号吗?比如:a+++++b如何区分呢?

C语言定义了一个符号规则:

每个符号应该包含尽可能多的字符!

简单理解就是编译器分解符号的方法是:从左向右一个字符一个字符的读入,如果该字符能够组成一个已存在的符号或一个符号的部分,就继续读取下一个字符,重复该操作直到读入的字符组成的字符串不再可能组成一个有意义的符号停止,该策略就为"贪心法"。

在这里补充一个知识:除字符串和字符常量,符号的中间不能镶嵌空白(空格符,制表符和换行符)

看案例:

cs 复制代码
#include <stdio.h>
int main()
{
	int a = 3;
	int b = 3;
	int c = 0;
	c = a---b;
	printf("a---b=%d\n", c);
	a = 3; b = 3;
	c = a -- - b;
	printf("a -- - b=%d\n", c);
	a = 3; b = 3;
	c = a - -- b;
	printf("a - -- b=%d\n", c);
}

你能得出三个printf的结果吗?(联系上面的贪心法规则)

结果如下:

解释:

我们可以将上面的代码看成这样:

cs 复制代码
#include <stdio.h>
int main()
{
	int a = 3;
	int b = 3;
	int c = 0;
	//c = a---b;
    c=(a--)-b;
	printf("a---b=%d\n", c);
	a = 3; b = 3;
	//c = a -- - b;
    c=(a--)-b;//忽略空格
	printf("a -- - b=%d\n", c);
	a = 3; b = 3;
	//c = a - -- b;
    c=a-(--b);
	printf("a - -- b=%d\n", c);
}

从而得到结果!

关于符号的准二义性还有这些:

cs 复制代码
y=x/*p;
y=x/(*p);

本意是将x除以指针p指向的值,再把所得的商赋值给y,结果写成了第一行的代码,显然,问题大了,在编译器中看到/*就会被认为代码注释的开始,直到找到*/结束,所以我们因该写成第二行。

这里我们再回到开头这题:

cs 复制代码
a+++++b;
//可以理解为((a++)++)+b;

三.对标准输入输出printf和scanf理解

我们直接看案例:

cs 复制代码
#include <stdio.h>
int main()
{
	int i = 3;
	printf("%d,%d\n", i++, i++);
}

结果为:

为啥呢?不应该是 3,4吗?

在这里我们必须知道标准输入输出规则:printf从右向左输出,scanf从左向右输入

因此我们是先算后面一个i++,在算前一个i++,结果为:4,3

学会了吗?

再看一个代码:

cs 复制代码
#include <stdio.h>
int main()
{
	printf("%d", printf("%d", printf("43")));
	return 0;
}

结果为:

这是因为printf也有返回值,返回值是输出的字符数~!

最后,希望大家C语言学习犯错越来越少,加油!!!

相关推荐
wuminyu18 小时前
JVM规范学习总结:解释器与JIT编译器如何处理JVM字节码
java·linux·c语言·jvm·c++
小徐不徐说19 小时前
序列化与反序列化:把 C++ 对象可靠地保存下来
开发语言·数据库·c++·php
ragnwang19 小时前
Notes: Python pybind11 import C++ module
开发语言·c++·python
Wang's Blog19 小时前
Java 项目实战: 交友项目 - 搜索附近的功能概述和分析
java·开发语言·交友
骑着蜗牛撵大象32719 小时前
大模型 Agent 的沙箱护栏:gVisor 隔离、出口白名单与审计闭环
java·开发语言·jvm·安全·agent沙箱·gvisor·microvm
Dxy123931021620 小时前
JS DES 加密详解
开发语言·javascript·arcgis
充值内卷20 小时前
我给桌面加了个鱼缸:C++ 写后端,WebView2 里养一座 Three.js 小岛
开发语言·javascript·c++
云和数据.ChenGuang21 小时前
深入解析 Python 的 dir():从用法到 CPython 源码实现
开发语言·人工智能·python·langchain
nice_lcj52021 小时前
深入理解 Java 反射:从 Class 对象到方法调用(含性能实测 + 迷你 IOC 实战 + 面试考点)
java·开发语言·后端·面试
樱花树下的数学喵1 天前
手写简易 STL string|C++ 字符串底层实现
开发语言·c++