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

相关推荐
手握风云-几秒前
数据结构(Java版)第二期:包装类和泛型
java·开发语言·数据结构
喵叔哟20 分钟前
重构代码中引入外部方法和引入本地扩展的区别
java·开发语言·重构
尘浮生26 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
hopetomorrow40 分钟前
学习路之PHP--使用GROUP BY 发生错误 SELECT list is not in GROUP BY clause .......... 解决
开发语言·学习·php
小牛itbull1 小时前
ReactPress vs VuePress vs WordPress
开发语言·javascript·reactpress
请叫我欧皇i1 小时前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
闲暇部落1 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
GIS瞧葩菜1 小时前
局部修改3dtiles子模型的位置。
开发语言·javascript·ecmascript
chnming19871 小时前
STL关联式容器之set
开发语言·c++
带多刺的玫瑰1 小时前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法