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语言学习犯错越来越少,加油!!!

相关推荐
烧冻鸡翅QAQ7 分钟前
从0开始的游戏编程——开发前的编程语言准备(JAVAScript)
开发语言·javascript·游戏
saber_andlibert11 分钟前
【C++转GO】文件操作+协程和管道
开发语言·c++·golang
Halo_tjn24 分钟前
Java IO流实现文件操作知识点
java·开发语言·windows·算法
FL162386312930 分钟前
VTK源码编译时候选qt5路径
开发语言·qt
Felven30 分钟前
C. Maximum Median
c语言·开发语言·算法
Wang's Blog1 小时前
Lua: 基于协程的生产者-消费者模型实现
开发语言·lua
jamesge20101 小时前
限流之漏桶算法
java·开发语言·算法
Dargon2881 小时前
Simulink的SIL软件在环测试
开发语言·matlab·simulink·mbd软件开发
csbysj20201 小时前
SVG 椭圆详解
开发语言
oioihoii2 小时前
C++数据竞争与无锁编程
java·开发语言·c++