一、算术运算符
|
运算符 |
功能说明 |
举例 |
|
+ |
加法,一目取正 |
a+b |
|
- |
减法,一目取负 |
a-b |
|
* |
乘法 |
a*b |
|
/ |
除法 |
a/b |
|
% |
取模(求余) |
a%b |
|
++ |
自加1 |
a++, ++b |
|
-- |
自减1 |
a--, --b |
-
注意点
- 减号也是负号,比如 -a 是取变量 a 的相反数(a = -a(取正负号,0还是0))
- 取模运算要求左右两边操作数必须是整型数据。
- 自加和自减运算不仅可以对整型操作,也可以对浮点数、指针操作。
- 自加和自减的原理说明:
- i++是先使用 i 的值,再i+1;++i是先 i+1 ,再使用 i 的值
底层原理 (目前可以不看):
- i++和++i都是带有返回值的函数
- i++返回的是一个常量值
- ++i返回的是i的引用/指针
二、关系运算符
|
运算符 |
功能 |
举例 |
说明 |
|
> |
大于 |
a > b |
判断a是否大于b |
|
>= |
大于或等于 |
a >= 5 |
判断a是否大于或等于5 |
|
小于 |
3 < x |
判断3是否小于x | |
|
小于或等于 |
x |
判断x是否小于或等于y+1 | |
|
== |
等于 |
(x+1) == 0 |
判断x+1是否等于0 |
|
!= |
不等于 |
c != ‘\0’ |
判断c是否不等于’\0’ |
关注点
-
- 关系运算符用于判断运算符两边的表达式是否满足给定的大小条件。
-
- 由关系运算符组成的表达式称为关系表达式,其值为布尔型(即TRUE和FALSE)。
- 判断是否相等是双等号==,而不是一个等号(是赋值号)。
-
示例代码
-
#include <stdio.h> int main(int argc, char const *argv[]) { // (1)、数学表达式(人的看法)和关系运算符表达式(机器的看方法)的区别 /* 数学表示式(人的看法): 100<x<200: x的取值范围为100到200 关系运算符表达式(机器的看方法): 100<x: 判断是否为真,为真返回true(非0:1), 为假返回false(0) 再用(1或者0)与200相比较,所以此式子永远为真 */ int x = 80; if (100<x<200) // 不管x为多少,都会一直为真(因为1或者0永远小于200,所以为真) { printf("执行这个语句1\n"); } // 正确的写法: if (x>100 && x<200) // x>100:假 x<200:真 , { printf("执行这个语句2\n"); } else { printf("执行这个语句3\n"); } // (2)、判断是否相等(==),而不是一个等号(=:赋值号) int num1 = 200; // 正确的写法: if ( num1 == 300) { printf("执行这个语句4\n"); } else { printf("执行这个语句5\n"); } // 错误的写法: if ( num1 = 100) // 赋值语句一直为真,所以会一直执行 { printf("执行这个语句6\n"); } else { printf("执行这个语句7\n"); } return 0; }三、逻辑运算符
|
运算符 |
功能说明 |
举例 |
|
! |
逻辑反 |
!(x==0) |
|
&& |
逻辑与 |
x>0 && x |
|
|| |
逻辑或 |
y10 |
-
运算规则
- 逻辑反:将逻辑真、假翻转,即真变假,假变真。
- 逻辑与:将两个关系表达式串联起来,当且仅当左右两个表达式都为真时,结果为真。
- 逻辑或:将两个关系表达式并联起来,当且仅当左右两个表达式都为假时,结果为假。

-
特殊规则
- 在逻辑与运算中,如果左边表达式的值为假,那么右边表达式将不被执行。
- 在逻辑或运算中,如果左边表达式的值为真,那么右边表达式将不被执行。

-
示例代码
#include <stdio.h>
#include <stdbool.h> // 布尔类型
#include <unistd.h> // 延时函数
int main(int argc, char const *argv[])
{
// // (1)、逻辑翻转(比如:标志位取反、led灯的闪烁)
// bool led = 1; // 非0为真:一般为1
// while (1)
// {
// led = !led; // led的值为真,遇到这句话,变为假,反之亦然
// if (led == true)
// {
// printf("led亮............\n");
// }
// else
// {
// printf("led灭............\n");
// }
// sleep(1); // 延时1s; usleep(1)微妙: 1s == 100 0000us
// }
// (2)、逻辑与和逻辑或
int num1 = 100;
int num2 = 200;
// 1、逻辑与
if ( (num1 == 100) && (num2 == 0) ) // &&的两边的表达式都为真,那么为真
{
printf("执行这个语句1\n");
}
else
{
printf("执行这个语句2\n");
}
// 注意:- 在逻辑与运算中,如果左边表达式的值为假,那么右边表达式将不被执行。
if ( (num1 == 99) && (num2 = 99) )
{
printf("执行这个语句3\n");
}
else
{
printf("执行这个语句4\n");
}
printf("num1 == %d\n", num1);
printf("num2 == %d\n", num2);
// 2、逻辑或
int num3 = 0;
int num4 = 0;
if ((num3 == 100) || (num4 == 0)) // ||的两边的表达式只要有一个为真,那么为真
{
printf("执行这个语句5\n");
}
else
{
printf("执行这个语句6\n");
}
// 注意:- 在逻辑或运算中,如果左边表达式的值为真,那么右边表达式将不被执行。
if ( (num3 == 0) || (num4 = 888))
{
printf("执行这个语句7\n");
}
else
{
printf("执行这个语句8\n");
}
printf("num3 == %d\n", num3);
printf("num4 == %d\n", num4);
// 题:
int m = 1;
int n = 1;
int a = 1;
int b = 1;
int c = 1;
int d = 1;
if ( (m=a>b) || (n=c>d)) // ||左边的式子为赋值为0,所以为假; 右边的式子还需计算,确定是否为真为假
// if ( (m=a>b) && (n=c>d)) // &&左边的式子为赋值为0,所以为假;右边的式子无需计算了
{
}
printf("m == %d\n", m);
printf("n == %d\n", n);
return 0;
}
四、位运算符
|
运算符 |
名称 |
举例 |
功能说明 |
|
~ |
位逻辑反 |
~a |
将变量 a 中的每一位取反 |
|
& |
位逻辑与 |
a & b |
将变量 a 和 b 逐位进行与操作(任何数与上0都为0) |
|
| |
位逻辑或 |
a | b |
将变量 a 和 b 逐位进行或操作(任何数或上1都为其1) |
|
^ |
位逻辑异或 |
a ^ b |
将变量 a 和 b 逐位进行异或操作(相同为0,不同为1) |
|
左移 |
a |
将变量 a 中的每一位向左移动4位 | |
|
>> |
右移 |
x >> 4 |
将变量 x 中的每一位向右移动4位 |
- 位运算符操作的对象是数据中的每一位
- 运算规则:
- 位逻辑反、位逻辑与、位逻辑或拥有与逻辑运算相似的规则和一样的真值表
- 异或运算:相同为0,不同为1
- 移位运算:移出去的不要,空出来的补零。移位运算都是针对无符号数的运算。
左移运算:int a;

右移运算

示例代码
#include <stdio.h>
int main(int argc, char const *argv[])
{ // 31 15 0
unsigned int num = 123456; // (高位)0000 0000 0000 0001 1110 0010 0100 0000(低位)
// 问题1:将num的第15位置为0, 其它位保持不变
num &=~(1<<15); // 等价于:num = num & (~(1<<20));
/*
解析:
1: 0000 0000 0000 0000 0000 0000 0000 0001
1<<15: 0000 0000 0000 0000 1000 0000 0000 0000
~(1<<15): 1111 1111 1111 1111 0111 1111 1111 1111
&
num(原来):0000 0000 0000 0001 1110 0010 0100 0000
=
num(现在):0000 0000 0000 0001 0110 0010 0100 0000
第15位这个位置变0了,其它位不变
*/
// 问题2:将num的第30位置为1, 其它位保持不变
num |=(1<<30); // 等价于:num = num | (1<<30);
/*
解析:
1: 0000 0000 0000 0000 0000 0000 0000 0001
1<<30: 0100 0000 0000 0000 0000 0000 0000 0000
|
num(原来):0000 0000 0000 0001 1110 0010 0100 0000
=
num(现在):0100 0000 0000 0001 1110 0010 0100 0000
第30位这个位置变1了,其它位不变
*/
// 问题3:将num的第10位取反, 其它位保持不变
num ^=(1<<10); // 等价于:num = num ^ (1<<10);
/*
解析:
1: 0000 0000 0000 0000 0000 0000 0000 0001
1<<10: 0000 0000 0000 0000 0000 0100 0000 0000
^
num(原来):0000 0000 0000 0001 1110 0010 0100 0000
=
num(现在):0000 0000 0000 0001 1110 0110 0100 0000
第10位这个位置被取反了,其它位不变
*/
// 问题4:判断num的第15位是否为1??
if ( num & (1<<15)) // 等价于:if( (num & (1<15) != 0 )
{
/* code */
}
/*
解析:
1: 0000 0000 0000 0000 0000 0000 0000 0001
1<<15: 0000 0000 0000 0000 1000 0000 0000 0000
&
num: 0000 0000 0000 0001 1110 0010 0100 0000 (num的第15位如果为1,那么num & (1<<15)的结果就为真,否则为加)
=
值: 0000 0000 0000 0000 1000 0000 0000 0000
*/
// 问题5:知道一个地址0xc000 0000,向该地址写数据(int)0x12345678?
/*
解析:
地址:0xc000 0000 (因为题目告诉我它是一个地址(如果题目没有明确说明,那么这个十六进制数是数据))
数据:(int)0x12345678
那我们怎么再代码中表示地址呢??指针
代码中直接写(int)0x12345678 : 表示数据
代码中直接写(int*)0xc000 0000 :表示地址(表示指针)
代码中,我想获取地址里面的内存: *(int*)0xc0000000(获取这个地址的内存(内存的范围是int型))
*/
// *(int*)0xc0000000 = (int)0x12345678; // 在linux应用层开发的时候:内存是由linux系统分配的,所以我们没有这个内存的所有权限、
// 在单片机开发中可以:这个地址一般是具体的寄存器地址(实际存在,且程序员可以区读取访问修改)
// int型的指针内存 = int型数据
// 问题6:读取地址0xc000 0000下的内容(假设这个地址指向的内存是int型类型的)
// printf("地址为0xc000 0000的内存里面的数据为 == %d\n", *(int*)0xc0000000);
return 0;
}
五、特殊运算符
-
赋值运算符
- 不能对常量赋值,只能对变量赋值
- 不能对数组赋值
-
- 可以连续赋值,顺序从右到左
-
示例代码
#include <stdio.h>
int main(int argc, char const *argv[])
{
// (1)、赋值运算符
// 1、- 不能对常量赋值,只能对变量赋值
int num1 = 100; // 可以,将常量100初始化给变量num1(初始化)
int num2 = 200; // 可以,将常量200初始化给变量num2(初始化)
// 100 = num1; // 不可以,常量不可被赋值(因为常量的内存区域在内存的常量区中(可读不可写))
// 200 = num2; // 不可以
num2 = 300; // 可以(赋值)
// (2)、不能对数组赋值
char buf[128] = "niweismyaozhuiwo,woyaojizhitangjiang"; // 可以,但这个不算赋值,这个是初始化
// buf = "wangwangzeihaohe"; // 不可以,直接赋值(因为buf是一个常量指针,buf不能移动,所以不能赋值)
// strcpy(buf, "woxiangqukankan"); // 可以,使用函数进行赋值操作(而不是直接=赋值操作)
// (3)、可以连续赋值,顺序从右到左
int num3;
num3=num2=num1=400;
printf("num1 == %d\n", num1);
printf("num2 == %d\n", num2);
printf("num3 == %d\n", num3);
return 0;
}
-
复合赋值符
- 当左右两边有相同的操作数时,采用复合赋值符不仅直观,且能提高运算效率
- 除了下述10个复合运算符之外,生造别的复合运算符是非法的
-
示例代码
// 加减乘除:
a += n; // 等价于 a = a+n;
a -= n; // 等价于 a = a-n;
a *= n; // 等价于 a = a*n;
a /= n; // 等价于 a = a/n;
// 求余:
a %= n; // 等价于 a = a%n;
// 位运算:
a &= n; // 等价于 a = a&n;
a |= n; // 等价于 a = a|n;
a ^= n; // 等价于 a = a^n;
a >>= n; // 等价于 a = a>>n;
a <<= n; // 等价于 a = a<<n;
六、条件运算符
- 唯一需要三个操作数的运算符(三目运算符)
- 语法:表达式1 ? 表达式2 : 表达式3
- 释义:当表达式1为真时,取表达式2,否则取表达式3
-
示例代码
#include <stdio.h>
#include <unistd.h>
#define ON 1
#define OFF 0
#define LED(X) X?printf("LED_ON!\n"):printf("LED_OFF!\n")
#define MAX(A,B) (A>B)?(A):(B)
int main(int argc, char const *argv[])
{
// // (1)、亮灭led的操作 (开发)
// while (1)
// {
// LED(ON);
// sleep(1); // 延时1s钟
// LED(OFF);
// sleep(1);
// }
// (2)、比较两个数的大小
// 1、宏定义
int max_num1 = MAX(100, 200);
printf("max_num1 == %d\n", max_num1);
// 2、直接调用
int a = 800;
int b = 200;
int max_num2 = a>b?a:b;
printf("max_num2 == %d\n", max_num2);
return 0;
}
七、sizeof运算符
- 含义:计算指定数据类型或者变量所占据内存的字节数
- 语法:sizeof(数据类型) 、sizeof(变量) ,计算变量、常量的字节数时圆括号可以省略(但是类型不可省略)
-
示例代码
#include <stdio.h> int main(int argc, char const *argv[]) { // (1)、sizeof计算类型的大小 printf("数据类型的大小\n"); printf("char size == %lu\n", sizeof(char)); printf("int size == %lu\n", sizeof(int)); printf("float size == %lu\n", sizeof(float)); printf("double size == %lu\n", sizeof(double)); // (2)、sizeof计算变量的大小 char ch = 'a'; int num = 100; float f1 = 3.14; double f2 = 6.18; printf("变量的大小\n"); printf("ch size == %lu\n", sizeof(ch)); printf("num size == %lu\n", sizeof(num)); printf("f1 size == %lu\n", sizeof(f1)); printf("f2 size == %lu\n", sizeof(f2)); // (3)、sizeof的括号可以省略 printf("\n"); printf("100 size == %lu\n", sizeof 100); // 可以,整型常量 printf("nihao size == %lu\n", sizeof "nihao"); // 可以,字符串常量 printf("ch size == %lu\n", sizeof ch); // 可以,字符变量 // printf("int size == %lu\n", sizeof int); // 不可以 // 笔试题、面试题 // 1、sizeof和strlen的区别??? /* sizeof是一个运算符,能够计算出变量的字节大小,对于字符串来说,sizeof会把字符串 最后的哪个'\0'字节也计算进去 strlen是一个C语言库里提供的一个字符串处理函数,只能计算字符串的长度,遇到'\0'就会结束 不会把'\0'也一并计算进去 */ // 2、以下为Linux下的32位C程序,请计算sizeof的值 char str[] = "hello"; // 字符串后面有一个结束标记符'' char *p = str; // 指针大小只看操作系统的位数,不看修饰的数据类型 int n = 10; // 请计算 (1) sizeof (str) = 6 (2) sizeof(p) = 4 (3) sizeof(n) = 4 // 3、sizeof计算字符常量的时候,会默认将其认为int数据来对待 printf("'a' size == %lu\n", sizeof 'a'); // 可以,字符常量 // 会将其当成int型数据来对待 printf("'a' size == %lu\n", sizeof ((char)'a')); // 可以,字符常量 return 0; } -
七、sizeof运算符
- 含义:计算指定数据类型或者变量所占据内存的字节数
- 语法:sizeof(数据类型) 、sizeof(变量) ,计算变量、常量的字节数时圆括号可以省略(但是类型不可省略)
-
示例代码
-
#include <stdio.h> int main(int argc, char const *argv[]) { // (1)、sizeof计算类型的大小 printf("数据类型的大小\n"); printf("char size == %lu\n", sizeof(char)); printf("int size == %lu\n", sizeof(int)); printf("float size == %lu\n", sizeof(float)); printf("double size == %lu\n", sizeof(double)); // (2)、sizeof计算变量的大小 char ch = 'a'; int num = 100; float f1 = 3.14; double f2 = 6.18; printf("变量的大小\n"); printf("ch size == %lu\n", sizeof(ch)); printf("num size == %lu\n", sizeof(num)); printf("f1 size == %lu\n", sizeof(f1)); printf("f2 size == %lu\n", sizeof(f2)); // (3)、sizeof的括号可以省略 printf("\n"); printf("100 size == %lu\n", sizeof 100); // 可以,整型常量 printf("nihao size == %lu\n", sizeof "nihao"); // 可以,字符串常量 printf("ch size == %lu\n", sizeof ch); // 可以,字符变量 // printf("int size == %lu\n", sizeof int); // 不可以 // 笔试题、面试题 // 1、sizeof和strlen的区别??? /* sizeof是一个运算符,能够计算出变量的字节大小,对于字符串来说,sizeof会把字符串 最后的哪个'\0'字节也计算进去 strlen是一个C语言库里提供的一个字符串处理函数,只能计算字符串的长度,遇到'\0'就会结束 不会把'\0'也一并计算进去 */ // 2、以下为Linux下的32位C程序,请计算sizeof的值 char str[] = "hello"; // 字符串后面有一个结束标记符'\0',sizeof计算时,也需要计算进去 char *p = str; // 指针大小只看操作系统的位数,不看修饰的数据类型 int n = 10; // 请计算 (1) sizeof (str) = 6 (2) sizeof(p) = 4 (3) sizeof(n) = 4 // 3、sizeof计算字符常量的时候,会默认将其认为int数据来对待 printf("'a' size == %lu\n", sizeof 'a'); // 可以,字符常量 // 会将其当成int型数据来对待 printf("'a' size == %lu\n", sizeof ((char)'a')); // 可以,字符常量 return 0; }八、return运算符
- 含义:退出某个函数(如果退出的是主函数main,那么整个程序也就退出了)
- 语法:必须出现在函数体内,可以带函数对应类型的数据
-
示例代码
-
#include <stdio.h> // 普通函数 // 比较两个整型数据的大小 int Max(int a, int b) { return a>b?a:b; // 返回的数据一定要是int型 } // 加 float Add(float a, float b) { return a+b; // 返回的数据一定要是float型 } // 减 float Substract(float a, float b) { return a-b; } // 乘 float Multiply(float a, float b) { return a*b; } // 除 float Divide(float a, float b) { return a/b; } // 取余 int Remainder(int a, int b) { return a%b; } // 主函数 int main(int argc, char const *argv[]) { printf("Max(100,200) == %d\n", Max(100,200)); printf("Add(100,200) == %f\n", Add(100,200)); printf("Substract(100,200) == %f\n", Substract(100,200)); printf("Multiply(100,200) == %f\n", Multiply(100,200)); printf("Divide(100,200) == %f\n", Divide(100,200)); printf("Remainder(10,3) == %d\n", Remainder(10,3)); return 0; }九、优先级和结合性
-
示例代码#include <stdio.h> int main(int argc, char const *argv[]) { // (1)、优先级的说明(比如:加减乘除) int a = 100; int b = 200; int c = 5; int d = 2; int num1 = a-d*b+a/c; // 原来的想法:a-d==》得数*b==>得数+a==》得数/c // 实际的执行:先执行d*b(得数1),再执行a/c(得数2), 再执行a-得数1+得数2 printf("num1 == %d\n", num1); // 应改为: int num2 = ((a-d)*b+a)/c; printf("num2 == %d\n", num2); // (2)、一般为了不产生歧义,以及为了更好的运算,所以你的表达式最好都加上()(因为()是除了[]优先级合结合性都是最高的) int m = 1; int n = 1; int a2 = 1; int b2 = 1; int c2 = 1; int d2 = 1; // 不推荐:if ( m= a2>b2 || n= c2>d2) // 原来的想法: 先求出||的左边的式子:m=a2>b2是否为真,如果不是再求出||右边的式子:n=c2>d2是否为真 // 推荐: if ( (m=a2>b2) || (n=c2>d2) ) { /* 实际的执行: 1、执行a2>b2(求出来:1或0) 2、执行c2>d2(求出来:1或0) 3、1或0(a2>b2) || n == 1或0 4、m=1或0=1或0 // 此处常量不能被赋值 */ } printf("m == %d\n", m); printf("n == %d\n", n); // (3)、普通的优先级合结合性 int n1,n2,n3=100,n4; // =赋值号优先于,号,先执行n3=100的操作 printf("n3 == %d\n", n3); // (4)、辨别复杂类型的方法 // 技巧1:先看变量名(函数名) // 技巧2:再看其优先级,看其和谁先结合,那么其本质就是什么 int p1; // int型p1 int p2[5]; // int型数组p2 int *p3; // int型指针p3 int **p4; // int型指针指针p4(二级指针) int *p5[5]; // int型指针数组p5 int (*p6)[5]; // int型数组指针p6 int (*p7[5])(int); // int型函数指针数组p7 return 0; }
6498

被折叠的 条评论
为什么被折叠?



