目录
接下来我们来看看不同的操作符吧。
算数运算符
操作符的作用就是执行某些特定的运算功能,比如 "+ - * / %"但有一些特别的点需要注意,我们看除法操作。
int a = 5/2; printf("%d",a);//输出2
为什么是2呢,难道是因为整形向下取整了吗?再试一下用浮点数输出
float a = 5/2; printf("%f",a);//结果为2
看来不是的,问题出在作除数和被除数的2和5,那是因为在C语言中,要想在整数除法中得到浮点类型的数,至少要有一个浮点型的操作数,使其被识别成小数运算。
float a = 5.0/2;//float a = 5.0/2.0也可以 printf("%f",a);//结果为2.500000
取模操作符又该如何运用呢?你只要记住取模操作符的结果为余数就行了,而余数一定是整数,那么这样就限定了在"%"两边的操作数必须是整数,否则就会出错。
int remain = 5%2; printf("%d",remain);//结果为1
移位操作符
">>" "<<"
后续会详细介绍这些对二进制位操作的运算符,简单来说就是使整形的二进制位向左或向右进行移动。
对二进制位向右移动1位的结果
位操作符
"&" "|" "^"
赋值操作符
赋值操作符就是 "="这个符号,这不是数学的等于号吗,其实这是对C语言的误会,在C语言中,等号是"==",像下面这样在等号后面加上其他一些操作符时,也是赋值的过程。
int a = 0;
a += 5;//等价于a=a+5
类似这样一个原理,但不能在初始化变量的时候用。
单目操作符
顾名思义,单目操作符是对单个操作数进行操作,比如+5就是5,-5就是负数5的意思。
前面提到过C语言中0表示真,非0表示假,那么用"!"可以使真假发生替换。!0就变成了真。
而正负号就不用说了,+号可以省略也是人尽皆知的事。
这里扩展一下sizeof ,sizeof可以计算括号内表达式所占多少字节。
看到其中线索了吗,第一个sizeof没有加括号,这样写是被支持的,而如果计算一些关键字变量的大小时,括号就不能被省略。
tip:从侧面说明了sizeof是操作符而不是函数。
sizeof在求数组元素个数的时候,也有妙用,利用数组中元素个数总大小除以一个元素所占的大小,就能得到数组元素个数,这样在我们实现一些有关数组的编程题时就变得更加灵活。
前置与后置++或--区别
其实从图中我们可以得知,不管是前置还是后置++,都是两个完整的表达式 ,知道谁先谁后就可以了,前置先++后使用,后置先使用后++,不必在此过多纠结。
强制类型转换
int a = 3.14;
我们看这一段错误代码,在将浮点类型的数值赋给整形时,会提示可能会出现精度缺失,这是必然的,而强制类型转换就能使其”转危为安“。
int a = (int)3.14; int number = (int)pow(2,3);//pow为求x的n次方函数,其默认返回double类型
关系操作符
这个也不多做赘述,常用来表示判断。如果你要判断两个数是否相等,就要注意两个易错点。
int a = 1;
if(a=1)//错误,j将1赋给了a,使其恒为真
if(a==1)//正确
其次就是字符串之间的比较不能用算数比较符比较,我们使用strcmp函数进行比较。现在不做介绍。
if(strcmp("abc","abc")==0)//如果相等,返回0
{
printf("相等");
}
逻辑操作符
”&&“ ”||" //逻辑与和逻辑或
逻辑操作符的关注点在于真假,我们知道真为0,假为非0,这就说明了它们在执行操作后所得到的是一个关于真假的值。我们规定逻辑操作符中真为1,假为0。
条件操作符
条件操作符就是三目操作符,因为它的操作数是3个,接下来我们用它来改进下列代码。
/*int a=0,b=0; if(a>b) { b=3; } else b=5;*/ //用三目操作符,?表判断,满足值为冒号前的数,否则为后面的数 a>b? (b=3):(b=5); //也可以这样写 b= (a>b? 3:5);
像这样非此即彼的判断可以使用三目操作符,请灵活应用。
逗号表达式
exp1 , exp2 , exp3 ,...; 像这样的称为逗号表达式。他有几个重要的特点
1.表达式从左向右计算
2.整个表达式的值为最后一个表达式的结果。
3.使用逗号表达式不仅仅是为了求整个表达式的值,通常分别求各个表达式的值。
我们依次看括号里面的式子,第一个并没有改变a的值,只是单纯加了1,第二个意为a=a+2,让a加了2,最后一个式子结果为0+2得b的值为2,意为b =(b=2 ),结果是2,是不是有点明白了?接下来我们去掉括号试试,看结果会不会变化。
咦?怎么结果变成3了?这个问题涉及一个运算优先顺序问题,逗号表达式在实际运用上并不常见,它的运算优先级是最低的,也就是说我们先执行了 b = a+1这一步操作,在运算时最好加上括号,使其最先参与运算。
有的人可能会疑问,在我们定义变量时,也遇到了类似的情况
int a=0,b=0,c,d;
这里的逗号只是充当了定义变量的一个分隔符而已。
下标引用,函数调用,结构成员
下标引用[]
int arr[1] ={0};
前面说过下标能够表示数组的长度以及访问数组元素的位置,它也是属于我们的操作符这个范畴的,在使用时甚至可以将里面的表达式与数组名对调,结果依然是正确的,这说明了它就是个操作符。
函数调用()
对于一个写好的函数,我们通过 函数名(实参,实参)对这个函数体进行调用,操作数为函数名和括号里的实际参数。注意它的括号一定不能去掉。
结构成员 " . " " -> " (之后会说)
关键字
常见关键字
1.关键字是可以直接使用的,对常见的关键字要有了解。
2. 变量名不能是关键字。
- auto是修饰局部变量的关键字,意为“自动”。我们几乎见不到是因为它可以省略,每个局部变量在自动创建后都会在结束后自动销毁。所以局部变量是由auto修饰的。
int main() { auto int a =0; return 0; }
- const有常属性,修饰变量、指针
- extern 用来声明外部符号
- register 寄存器关键字
- sizeof 操作符关键字
- 自定义类型:enum struct union
- static 静态的
- return 函数的返回
- unsigned(无符号)/signed(有符号)
- register寄存器关键字(建议把变量放到寄存器)(extend)
- typedef类型重定义
typedef可以将一些复杂和长的类型简化成自己想要的名字,然后就可以用自定义后的类型。
typedef unsigned int = size_t; size_t a = 10;
- void 空类型
- 循环结构:break continue while do for
- 分支结构:if else goto switch case break default(默认)
static关键字
1.修饰局部变量
- 普通的局部变量在栈区创建,进入局部范围,变量创建,出了局部范围被销毁。
- 当static修饰局部变量时,局部变量是在静态区开辟空间的,这时的局部变量出了作用域不销毁,下次进入还是上次遗留的数据。
可以从反汇编代码中看到static修饰的这段代码中并没有对应的汇编代码,说明了它并没有在栈区开辟内存空间。
这段代码就很好理解了,static使 其生命周期延长为整个工程结束。
2.修饰全局变量
全局变量具有外部链接属性的,当全局变量被static修饰,外部链接属性就变成了内部链接属性,其他源文件就没办法通过链接找到这个变量。
static修饰的全局变量只能在自己内部的.c文件使用。
tip:在有的编译器下全局变量或函数不加extern也能被其他源文件链接。
3.修饰函数
函数具有外部链接属性,被static修饰后,外部链接属性变成了内部链接属性。这时函数只能在自己内部的.c文件使用。
tip:链接属性分为三类:
- 外部链接属性
- 内部链接属性
- 无链接属性(局部变量没有链接属性。)