10. 操作符
现阶段只需简单了解,后续会有详细介绍
10.1 算术操作符
算术操作符 |
+ |
- |
* |
/ |
% |
这里主要介绍一下/和%的用法
#include <stdio.h> int main() { printf("%d\n", 8 / 2);//4 printf("%d\n", 7 / 2);//3(7 / 2=3...1) printf("%lf\n", 7.0 / 2);//3.5 /两端至少有一个数是小数时除出来才是小数 printf("%.2lf\n", 7.0 / 2);//3.50 return 0; }
注: %f是打印float类型;%lf是打印double类型
#include <stdio.h> int main() { printf("%d\n", 8 % 2);//0(8/2=4...0) % - 取模/取余 return 0; }
10.2 移位操作符
移位操作符 | 名称 |
>> | 右移位操作符 |
<< | 左移位操作符 |
int main() { int a = 1;//int类型是4个字节 = 32bit 00000000000000000000000000000001 a >> 1;//00000000000000000000000000000001整体向右移一个二进制位 a << 1;//00000000000000000000000000000001整体向左移一个二进制位 return 0; }
10.3 位操作符
位操作符(位:二进制位) | 名称 |
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
10.4 赋值操作符
赋值操作符 |
= |
+= |
-= |
*= |
/= |
&= |
|= |
^= |
>>= |
<<= |
int main() { int a = 0; a = 10; a = a + 5; a += 5;//这两种写法是一个效果 a = a - 3; a -= 3;//这两种写法是一个效果 a *= 3; a /= 3; return 0; }
10.5 单目操作符
单目操作符 | 名称 |
! | 逻辑反操作 |
- | 负值 |
+ | 正值 |
& | 取地址 |
sizeof | 操作数的类型长度(以字节为单位) |
~ | 对一个数的二进制按位取反 |
-- | 前置、后置-- |
++ | 前置、后置++ |
* | 间接访问操作符(解引用操作符) |
(类型) | 强制类型转换 |
注:
(i) "+"是一个操作符,"2+3"中2为左操作数,3为右操作数,因此+是双目操作符,由此可知只有一个操作数的操作符就是单目操作符
(ii) C语言中0表示假,非0表示真(非0:1、5、-1……)
逻辑反操作、取地址:
//!叫做逻辑反操作,它只关注真假(把真变为假,把假变为真) #include <stdio.h> int main() { int a = 0; scanf("%d", &a);//5 0 scanf函数中的&就是取地址 printf("%d\n", a);//5 0 printf("%d\n", !a);//0 1(假变为真时,语法规定输出的是1) return 0; }
用法举例:
负值、正值:
#include <stdio.h> int main() { int a = -10; int b = -a; printf("%d\n", b);//10 int c = +a; printf("%d\n", c);//-10 return 0; }
sizeof:
//sizeof是操作符,不是函数,计算的结果单位是字节 #include <stdio.h> int main() { int a = 10; printf("%d\n", sizeof(a));//4 printf("%d\n", sizeof a );//4 这里不加()也可以,而函数必须加(),所以sizeof不是函数,是操作符!!! printf("%d\n", sizeof(int)); printf("%d\n", sizeof int );//这样写是错误的 return 0; }
数组中元素个数的计算就可以用到sizeof:
#include <stdio.h> int main() { int arr[10] = { 0 }; printf("%d\n", sizeof(arr));//40,计算的是数组的总大小,单位是字节 printf("%d\n", sizeof(arr[0]));//4 printf("%d\n", sizeof(arr) / sizeof(arr[0]));//40 / 4 = 10 //因此数组中元素个数的计算如下 int sz = sizeof(arr) / sizeof(arr[0]); return 0; }
是否还记得strlen呢,它和sizeof又有什么区别呢:
#include <stdio.h> #include <string.h> int main() { char arr1[] = "abc";//a b c \0 char arr2[] = { 'a', 'b', 'c' };//a b c printf("%d\n", strlen(arr1));//3 printf("%d\n", strlen(arr2));//随机值 printf("%d\n", sizeof(arr1));//4 sizeof只关注这个数据占据内存空间的大小,不关注内存中放的是什么 printf("%d\n", sizeof(arr2));//3 return 0; }
总结: strlen是库函数,是求字符串长度的,关注的是字符串中是否有\0 ,统计\0之前出现的字符个数;sizeof是操作符,只关注占据了多大的内存空间,不关注内存中存放的数据,返回值的单位是字节
前置、后置++;前置、后置--:
#include <stdio.h> int main() { int a = 10; int b = ++a;//前置++,先++,后使用(a=a+1,b=a;) printf("a=%d b=%d\n", a, b);//11 11 int b = a++;//后置++,先使用,后++(b=a,a=a+1;) printf("a=%d b=%d\n", a, b);//11 10 int b = --a;//(a=a-1,b=a;) printf("a=%d b=%d\n", a, b);//9 9 int b = a--;(b=a,a=a-1;) printf("a=%d b=%d\n", a, b);//9 10 return 0; }
注: 以下是一个错位的代码,在不同的编译器上有不同的结果
#include <stdio.h> int main() { int a = 1; int b = (++a) + (++a) + (++a); printf("b=%d\n", b); return 0; }
强制类型转换:
#include <stdio.h> int main() { //int double int a = (int)3.14; printf("%d\n", a);//3 return 0; }
10.6 关系操作符
关系操作符 | 名称 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
!= | 用于测试“不相等” |
== | 用于测试“相等” |
10.7 逻辑操作符
逻辑操作符 | 名称 |
&& | 逻辑与(并且,只关注真假) |
|| | 逻辑或(或者,只关注真假) |
逻辑与:
用法举例:
逻辑或:
用法举例:
注: if()后不用加“;”
10.8 条件操作符
条件操作符(三目操作符) |
exp1 ? exp2 : exp3 |
#include <stdio.h> int main() { int a = 3; int b = 7; int m = 0; m = (a > b ? a : b);//如果a>b,那么a,否则b(以下写法效果和它相同) //if (a > b) // m = a; //else // m = b; printf("m=%d\n", m);//m=7 return 0; }
附:
exp1 | exp2 | exp3 |
真 | √ | |
假 | √ |
10.9 逗号表达式
逗号表达式 |
exp1, exp2, exp3, …expN |
#include <stdio.h> int main() { int a = 3; int b = 0; int c = 4; int d = (a = b - 3, b = a + c, c = a - b, a = c + 3); //a=-3 b=1 c=-4 a=-1 printf("%d\n", d);//-1 return 0; }
注: 逗号表达式会从左到右依次计算,但是整个表达式的结果是最后一个表达式的结果。
10.10 下标引用、函数调用和结构成员
下标引用 | 函数调用 | 结构成员 |
[ ] | ( ) | . |
-> |
下标引用:
#include <stdio.h> int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; printf("%d\n", arr[7]);//8;[]就是下标引用操作符,arr,7是[]的两个操作数 //2 + 3;2,3是+的两个操作数 return 0; }
函数调用:
• 1 • 2 • 3 • 4 • 5 • 6 • 7 • 8 • 9 • 10 • 11 • 12 • 13
结构成员:
“.”、" ->"是结构体中使用的,后期介绍
11. 常见关键字
C语言提供了丰富的关键字,这些关键字都是语言本身预先设定好的,用户自己是不能创造关键字的。
循环 | 分支 | 类型 | 自定义类型 | |
break(停止) | switch | char | enum(枚举) | extern(声明外部符号的) |
continue(继续) | case | short | struct(结构体) | register(寄存器关键字) |
do while | break | int | union(联合体/共用体) | return(函数中返回) |
for | default(默认选项) | long | volatile(这个关键字后面再讲) | |
while | if…else… | long long | auto(自动变量) | |
goto | float | |||
double | ||||
const | ||||
sizeof | ||||
static | ||||
signed(有符号的) | ||||
unsigned(无符号的) | ||||
typedef(类型重定义) | ||||
void(无类型/空类型,用于函数返回值、参数这些地方) |
11.1 auto
int main() { auto int a = 10;//所有的局部变量都是自动变量,所以auto一般就省略不写。局部变量a进入它的作用域自动创建,出它的作用域自动销毁 return 0; }
11.2 unsigned
int main() { unsigned int num = -10;//现阶段只要知道是怎么写的就可以了,具体输出后结果是什么以后会进行讲解 return 0; }
11.3 typedef
typedef unsigned int unit;//给unsigned int重新取了一个名字叫做unit,unit = unsigned int int main() { unsigned int num1 = 10; unit num2 = 20; return 0; }
拓展:
//数据结构 typedef struct Node { int data; struct Node* next; }Node; //这一段代码的意思为给 //struct Node //{ // int data; // struct Node* next; //} //重新取了一个名字叫做Node //现在只要大致能看懂就行,后期会深入讲解
11.4 register
int main() { register int num = 10;//register 起一个建议的作用,并不是写了register就一定会放到寄存器里,还是取决于编译器的,编译器如果发现这一变量被频繁大量使用,那么这个变量的值就可能被放到寄存器中,如果编译器觉得没必要把它放到寄存器中,那它就不会被放进去。即使不写register,现在的编译器只要觉得有必要把它放到寄存器中,编译器就会把它放到寄存器中 return 0; }
附:
11.5 static
在C语言中,static是用来修饰变量和函数的,其分为以下三种:
- 修饰局部变量-称为静态局部变量
- 修饰全局变量-称为静态全局变量
- 修饰函数-称为静态函数
修饰局部变量:
首先看一下不加static,代码运行之后的结果:
代码具体是如何运行的呢?
再来看一下加上static,代码运行之后的结果:
代码具体是如何运行的呢?
总结: static修饰局部变量的时候改变了变量的存储类型,普通的局部变量是存储在栈区的,被static修饰的变量是存储在静态区的,存储在静态区的变量,出了作用域不会销毁,依然存在,所以静态变量的生命周期就是程序的生命周期,程序结束的时候,静态变量才回收空间。(静态变量的生命周期变长了,作用域不变)
附:
修饰全局变量:
首先看一下不加static,代码运行之后的结果:
再来看一下加上static,代码运行之后的结果:
由图可知,这个代码是错误的,g_val是无法输出的
修饰函数:
首先看一下不加static,代码运行之后的结果:
注: int Add(int x, int y)后面不要加“;”
再来看一下加上static,代码运行之后的结果:
由图可知,这个代码是错误的,sum是无法输出的
其余关键字会在后期碰到时进行讲解!