【C语言】C语言操作符的分类及应用【超详细讲解】
指令系统的每一条指令都有一个操作符,它表示该指令应进行什么样性质的操作,不同的指令用操作符这个字段的不同编码来表示,每个编码分别代表一种指令。这篇文章主要给大家介绍了关于C语言中操作符的相关资料,需要的朋友可以参考一下。
目录
算术操作符
移位操作符
位操作符
关于位操作符和移位操作符的应用示例:
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符,(三目操作符)
逗号表达式
下标引用操作符
函数调用操纵符
隐式类型转换
操作符的属性
操作符应用实例:
算术操作符
主要是 ( + - * / %) 五种算数操作符。
算术操作符是比较简单的操作符,包括加减乘除(+ - * /)取模(%),加减乘和数学中的加减乘一样,而两个数相除我们得到的是它们的商的整数部分,取模(%)得到的是它们的余数。
- + 加法
- - 减法
- * 乘法
- / 除法(取商) 7 / 2 = 3 ( …… 1) 1 / 2 --> 0
- % 取模操作符 :计算的的整除后的余数,操作数必须为整数 7 % 2 = 1;
- 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
- 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
- % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
- 当除数为小数时,int类型只会截取整数部分。 6 / 2.4 = 3 (系统看成 6 / 2 = 3)
移位操作符
移位操作符涉及到整数的原反补知识:http://t.csdn.cn/HflQh
- <<左移操作符:移动的是二进制
- >>右移操作符:移动的是二进制
int main()
{
int a = 7;
int b = a << 1;
printf("%d\n", a);//7 111
printf("%d\n", b);//14 1110
}
//a 内存中 0000 0000 0000 0000 0000 0000 0000 0111
//b 内存中a向左移动一位 左移操作,左边丢弃,右边补0
//b 内存中 0000 0000 0000 0000 0000 0000 0000 1110 (14)
// a自身不变,b复制了a的补码再做操作。
左移操作符<< 具体规则为:
内存中向左移动一位 左移操作,左边丢弃,右边补0。
//b = -7 << 1, a = -7
//a 1111 1111 1111 1111 1111 1111 1111 1001
//b 1111 1111 1111 1111 1111 1111 1111 0010(补码)
//b 1111 1111 1111 1111 1111 1111 1111 0001(反码)
//b 1000 0000 0000 0000 0000 0000 0000 1110(原码) -14
所以无论正负,左移1,就是乘2
右移操作符
算数移位:右边丢弃,左边补原符号位
逻辑移位:右边丢弃,左边补0
是逻辑右移还是算数右移取决于编译器
基本上见过的都是算术右移。
int main()
{int a = -7;int b = a >> 1;printf("a=%d\n", a); // -7printf("b=%d", b); // -4return 0;
}
//VS采用的是算术右移。
//对于移位运算符,不要移动负数位,也不能移动浮点数位,这是标准未定义的。
位操作符
- & - 按(2进制)位与
- | - 按(2进制)位或
- ^ - 按(2进制)位异或
int main()
{int a = 3; //补码 0000 0000 0000 0000 0000 0000 0000 0011int b = -5;//原码 1000 0000 0000 0000 0000 0000 0000 0101//补码 1111 1111 1111 1111 1111 1111 1111 1011int c1 = a & b; // & : 两个同时为1才是1,否则为0int c2 = a | b; // | : 只要有1就为1,两个为0才为0int c3 = a ^ b; // ^ : 相同为0,相异为1printf("c1=%d\n", c1); // 3printf("c2=%d\n", c2); // -5printf("c3=%d\n", c3); // -8return 0;
}
关于位操作符和移位操作符的应用示例:
例子1:
//不创建临时变量实现两个数的交换
//原本的方法1:(创建临时变量)
int main()
{int a = 3;int b = 5;int c = 0;c = a;a = b;b = c;return 0;
}
//不创建法2:
int main()
{int a = 3;int b = 5;int c = 0;a = a + b;b = a - b;a = a - b;return 0;
}
//因为整型的数有最大值,可能相加会溢出。
//从理论上讲是有问题的//不创建的法3
int main()
{int a = 3;int b = 5;int c = 0;a = a ^ b;b = a ^ b;a = a ^ b;return 0;
}
//在实际应用中,法1(创建临时变量)用得最广泛
//法3 只适用于 整型,处理速度较慢//两个相同的数字异或为00 ^ a = 0a ^ a = 03 ^ 3 ^ 5 = 53 ^ 5 ^ 3 = 5
//注意:异或操作符支持交换律
//所以: a = a ^ b; b = a ^ b; a = a ^ b; -->a = 3 ^ 5 b = 3 ^ 5 ^ 5 --> 3 a = 3 ^ 5 ^ 3 = 5;
// 而且这种算法不会溢出
// 很难想,但是像加法
例子2:
//编写代码要求实现:求一个整数储存在内存中的二进制中1的个数
// ----> 求补码的二进制中1的个数// int a = 3;
// 0000 0000 0000 0000 0000 0000 0000 0011
// 2 // a & 1
// 0000 0000 0000 0000 0000 0000 0000 0011
// 0000 0000 0000 0000 0000 0000 0000 0001
//& 后 为 0000 0000 0000 0000 0000 0000 0000 0001 可以判断最后一位的是0还是1
// 只需要右移操作 第二位就变成第一位了int main()
{int a = 7;int amount = 0;for (int i = 0; i < 32; i++){if ((a & 1 )== 1)amount++;a = a >> 1;}printf("%d", amount);return 0;
}
例子3:
//编程实现:两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?
//
//输入例子:
//
//1999 2299
//
//输出例子 : 7
#include<stdio.h>
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);int c = a ^ b;int count = 0;for (int i = 0; i < 32; i++){if ((c & 1) == 1)count++;c >>= 1;}printf("%d", count);return 0;
}
例子4:
//获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列
#include<stdio.h>
int main()
{ // 0000 0000 0000 0000 0000 0000 0000 0101 int a = 0; // 1000 0000 0000 0000 0000 0000 0000 0001 scanf_s("%d", &a);int num = 1 << 30;printf("Even digit:");if (a >= 0)printf("0 ");elseprintf("1 ");for (int i = 0; i < 15; i++){int b = (a & (num >> 1))/(num>>1);printf("%d ", b);num >>= 2;}num = 1 << 30;printf("\nOdd digit: ");for (int i = 0; i < 16; i++){int b = (a & num)/num;//b = Squ2(b);printf("%d ", b);num >>= 2;}return 0;
}
例子5:
//写一个函数返回参数二进制中 1 的个数。//比如: 15 0000 1111 4 个 1
int main()
{int a = 0;scanf_s("%d", &a);int count = 0;for (int i = 0; i < 32; i++){if ((a & 1) == 1)count++;a >>= 1;}printf("count = %d", count);return 0;
}
赋值操作符
- “ = ”
int main()
{int a = 3; //初始化a = 3; //赋值a = x = y + 1;//连续赋值,从右往左算 y+1的值赋给x x赋给a//不建议连续赋值,无法单步进行调试,可读性较差, 建议不要用这个。return 0;
}
复合赋值符号:
- +=
- -=
- *=
- /=
- %=
- >>=
- <<=
- &=
- |=
- ^=
单目操作符
- ! 逻辑反操作
int main() {int flag = 3;//如果flag 为真(非0),if成立,进入条件语句if(flag){ }//如果flag 为假(0),!flag为真,if成立,进入条件语句if (!flag){ }return 0; }
-负值
+正值
&取地址
int main(){int a = 30;printf("%p\n", &a); //取的是变量在内存中的起始地址int n = sizeof(a); //计算的是a所占内存的大小,单位是字节int * p = &a; //p 就是指针变量 存储地址return 0; }
sizeof ,注意:是一个操作符,不是函数。计算的是变量、数组所占内存空间的大小,而strlen 是库函数,是用来求字符串的长度。
“ ~ ” 二进制位取反,包括符号位
//eg. int main() {int a = 0;// 0000 0000 0000 0000 0000 0000 0000 0000 printf("%d\n", ~a);// 1111 1111 1111 1111 1111 1111 1111 1111 补码// 1111 1111 1111 1111 1111 1111 1111 1110 反码// 1000 0000 0000 0000 0000 0000 0000 0001 原码// -----> -1// 把其中几位变成1 可以这一位(1 << 几位) 或1 // 把其中几位变成0 可以 0 按位与上去,其余全为1(a & ~(1<<4) ) 就可以return 0; }
前置++ 先++ 后使用
后置++ 先使用,后++
* 取地址操作符
// 如 p 是存放 &a中a的地址,如果通过要通过p的地址找到a的地址,就是解引用p // *p --> 通过p里面的值找到 这个地址的所在的空间,就是 a
void test1(int arr[]) {printf("%d\n", sizeof(arr)); //打印了一个指针的大小 4个字节(x86)/8个字节(x64) } void test2(int ch[]) {printf("%d\n", sizeof(ch)); //打印了一个指针的大小 4个字节(x86)/8个字节(x64) } int main() {int arr[10] = { 0 };char ch[10] = { 0 };printf("%d\n", sizeof(arr)); //40printf("%d\n", sizeof(ch)); //10test1(arr);test2(ch);return 0; }
关系操作符
>
>=
<
<=
!=
==
注意:赋值与判断相等的区别
注意:
int main()
{if ("abc" == "abcdefg") //字符串这样比是在比较首字符的地址{ //需要用strcmp};return 0;
}
逻辑操作符
- &&逻辑与
- ||逻辑或
int main()
{int a = 3;int b = 5;int c = a && b;printf("%d\n", c);//1int d = 0;c = a && d; //有一个0就为0printf("%d\n", c);//0c = a || b; //只要有一个为真则为真printf("%d\n", c);//1c = a || d;//1printf("%d\n", c);//1c = 0 || d;// 两个为0才为0printf("%d\n", c);//0return 0;
}
请看以下两个例子:
int main()
{ int i = 0, a = 0, b = 2, c = 3, d = 4;//i = a++ && ++b && d++; //只有a++算了,因为先使用a为0 不用算了i = a++ || ++b || d++; // 0 || 要算第二个,如果第二个为真,不用算了printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);// &&1 2 3 4 ||:1 3 3 4return 0;
}
int main()
{int i = 0, a = 1, b = 2, c = 3, d = 4;i = a++ && ++b && d++; // 无论前后置都++了// i = a++||++b||d++; //1 为真 后面根本不用算了,算到为真就好了printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);// &&2 3 3 5 ||:1 2 3 5return 0;
}
可以得出结论:
- &&左边为假,右边不计算
- ||左边为真,右边不计算
条件操作符,(三目操作符)
表达式1?表达式2:表达式3
真 算 不算
假 不算 算
int main()
{int a = 3;int b = 0;int max = (a > b ? a : b);if (a > 3)b = 3;elseb = -3;b = (a > 3 ? 3 : -3);return 0;
}
逗号表达式
从左往右依次计算,整个表达式的结果是最后一个表达式的结果。
int main()
{int a = 3;int b = 5;int c = (a > b, a + b + 10, a, b = a + 1);//前面的计算不可以忽略return 0;
}
下标引用操作符
- [ ]
int main()
{int arr[10] = { 0 };arr[7] = 8; //[]为下标引用操作符 []操作数为 arr 和 7 return 0;
}
//arr[7] ---> *(arr+7) arr+7就是跳过7个元素,指向了第八个元素,就是第八个元素
// ---->*(7+arr) ---> 7[arr]
函数调用操纵符
- ( )
int Add(int x, int y)
{return x + y;
}
int main()
{int a = 10;int b = 20;int c = Add(a, b);//调用了,操作数为Add, a, b.return 0;
}
访问一个结构的成员
- . 结构体 . 成员名
- -> 结构体指针->成员名
struct Stu
{char name[20];int age;double score;
};
void set_stu(struct Stu*ps)
{// 不行,ss.name是一个地址,不能把字符串放到地址里。ss.name = "zhangsan";//strcpy((*ps).name, "zhangsan");//(*ps).age = 20;//(*ps).score = 100.0;strcpy(ps->name, "zhangsan");ps->age = 20;ps->score = 100.0;
}
void print_stu(struct Stu *ps)
{printf("%s %d %.1f\n", (*ps).name, (*ps).age, (*ps).score);
}int main()
{struct Stu s = { 0 };set_stu(&s);print_stu(&s);return 0;
}
//实参传给形参的时候,形参是实参的一份临时拷贝。
//当你把s传过去的时候,只传递的是实参的值,然后对形参进行改变
//我们应该传递s的地址过去
// 然后 *ps 找到s的地址 后面用 (*ps).name 找到成员name
// 也可以用 ps -> name 找到
//-> 拿到了结构体指针—>成员名 ->不需要解引用
//如果拿到了结构体对象用. 成员名 ps->age 等价于 (*ps).age
隐式类型转换
整型提升:C语言得整形算术运算总是至少以缺省整型类型的精度都来计算的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前都会变成整型。
整型提升的意义
表达式的整形运算要在CPU的相应运算期间内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,
在CPU执行时实际上也要先转换为CPU内整形操作数的标准长度。
通用CPU(general-purpose CPU)是难以直接实现两个8byte字节直接相加运算
(虽然机器指令中可能有这种直接相加指令)。
所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigend int
然后才能送入CPU中去执行。如何进行整型提升呢?
整型提升是按照变量的数据类型的符号位来提升的。
int main()
{char c = -1; //-1是整数,32个比特位//1000 0000 0000 0000 0000 0000 0000 0001//1111 1111 1111 1111 1111 1111 1111 1110//1111 1111 1111 1111 1111 1111 1111 1111 -> -1 的 补码//因为char类型只有一个字节,8比特位//1111 1111//把第一个看成是符号位,高位补充符号位。char d = 1;//0000 0000 0000 0000 0000 0000 0000 0001//0000 0001;//高位补符号位0//如果为无符号数,直接补0return 0;
}
int main()
{char a = 5;// 0000 0000 0000 0000 0000 0000 0000 0101// 0000 0101char b = 126;// 0000 0000 0000 0000 0000 0000 0111 1110// 0111 1110char c = a + b;//整型提升// 0000 0000 0000 0000 0000 0000 0000 0101// 0000 0000 0000 0000 0000 0000 0111 1110// 0000 0000 0000 0000 0000 0000 1000 0011//回退 八个比特位// 1000 0011printf("%d", c);//整型提升// 1111 1111 1111 1111 1111 1111 1000 0011// 1111 1111 1111 1111 1111 1111 1000 0010// 1000 0000 0000 0000 0000 0000 0111 1101// -125!!return 0;
}
// char -128 - 127
int main()
{char a = 0xb6;//整型提升了//可能会改变值,因为符号位可能为1short b = 0xb600;//整型提升了//可能会改变值,因为符号位可能为1int c = 0xb60000;return 0;
}
//放在表达式中,整型就会提升,比如 +c
int main()
{char c = 1;printf("%d", sizeof(c)); //1printf("%d", sizeof(+c)); //4printf("%d", sizeof(-c));//4return 0;
}
比如float 和 double 一起运算,会向上转换
int 和double 遇到了 ,int 会提升成double,
都是向上转换。
操作符的属性
复杂表达式的求值有三个影响因素
1.优先级:相邻操作符的优先级
2.结合性:相邻操作符优先级相同的时候,结合性说了算
L-R 从左向右 R-L 从右向左
3.是否控制求值顺序,如逻辑或,算到1就不用算了但是面对一些表达式
他们的顺序没法控制,有多种解释方法
c + --c
2 1
一定是先算右边的 --c
但是左边的 c 什么时候准备呢
如果c 等于2, 先--c 后准备c 则结果为2
如果 先准备c 后--c 则结果为3
a * b + c * d + e * f
#include <stdio.h>
int i;
int main()
{i--;if (i > sizeof(i)){printf(">\n");}else{printf("<\n");}return 0;
}
// 会输出>
操作符应用实例:
KiKi学习了循环,BoBo老师给他出了一系列打印图案的练习,该任务是打印用“*”组成的X形图案。
输入描述:
多组输入,一个整数(2~20),表示输出的行数,也表示组成“X”的反斜线和正斜线的长度。
输出描述:
针对每行输入,输出用“ * ”组成的X形图案。
//找到规律是关键,看作一条正斜杠和反斜杠
#include <stdio.h>
int main()
{int n = 0;while (scanf_s("%d", &n) != EOF){for (int i = 0; i < n; i++) //外循环为行{for (int j = 0; j < n; j++) //内循环为列{if (i == j || i + j == n - 1)//最关键的地方,正斜线为[i][i]处是*, 反斜杠为[i][n-1-j]处是*,一行打印1个或2个*printf("*");elseprintf(" ");}printf("\n"); //打印完一行,换行}}return 0;
}
描述
KiKi想获得某年某月有多少天,请帮他编程实现。输入年份和月份,计算这一年这个月有多少天。
输入描述:
多组输入,一行有两个整数,分别表示年份和月份,用空格分隔。
输出描述:
针对每组输入,输出为一行,一个整数,表示这一年这个月有多少天。
int is_leap_year(int x)
{if (x % 400 == 0)return 1;else if (x % 4 == 0 && x % 100 != 0)return 1;elsereturn 0;
}
int main()
{int year = 0;int month = 0;while (scanf_s("%d %d", &year, &month) != EOF){if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)printf("31");else if (month == 2){int ret = is_leap_year(year);printf("%d", ret == 1 ? 29 : 28);}elseprintf("30");}return 0;
}
KiKi想知道已经给出的三条边a,b,c能否构成三角形,如果能构成三角形,判断三角形的类型(等边三角形、等腰三角形或普通三角形)。
输入描述:
题目有多组输入数据,每一行输入三个a,b,c(0 < a, b, c < 1000),作为三角形的三个边,用空格分隔。
输出描述:
针对每组输入数据,输出占一行,如果能构成三角形,等边三角形则输出“Equilateral triangle!”,等腰三角形则输出“Isosceles triangle!”,其余的三角形则输出“Ordinary triangle!”,反之输出“Not a triangle!”。
#include<stdio.h>
int main()
{int a = 0;int b = 0;int c = 0;while (scanf_s("%d %d %d", &a, &b, &c) != EOF){if (a + b > c && a + c > b && b + c > a){if (a == b && b == c)printf("Equilateral triangle!\n");else if (a == b || b == c || a == c)printf("Isosceles triangle!\n");elseprintf("Ordinary triangle!\n");}elseprintf("Not a triangle!\n");}return 0;
}
【C语言】C语言操作符的分类及应用【超详细讲解】相关推荐
- C语言整型,浮点型数据储存的超详细讲解
数据类型 整型 浮点型(实型) 写在最后的话 我们都知道C语言有很多数据类型,如char ,int ,double 等等,本篇博客我们来梳理分类一下这些数据类型,首先我们可以将数据类型分为两类,整型和 ...
- 数据结构-带头节点的单链表(C语言)超详细讲解
前面我们学到线性表的顺序存储结构(顺序表),发现它有着明显的缺点:插入和删除元素时需要频繁的移动元素,运算效率低.必须按事先估计的最大元素个数申请连续的存储空间.存储空间估计大了,造成浪费空间:估计小 ...
- NLP之文本分类实战入门超详细教程
目录 前言 一.数据加载 1.加载包 2.读取数据 二.文本处理 1.去除无用字符 2.文本分词 3.去除停用词 4.去除低频词 5.划分训练集和测试集 三.把文本转换成向量的形式 1.把文本转换成t ...
- C语言基础大全(基于千锋教育超详细教程)
C语言基础 1.第一个c语言程序 #include <stdio.h> int main() {printf("hello world");return 0; } [外 ...
- 【C语言】用C语言实现最大公约数和最小公倍数【超详细讲解】
最大公约数: "最大公因数,也称最大公约数.最大公因子,指两个或多个整数共有约数中最大的一个.a,b的最大公约数记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最 ...
- r语言中mpg数据_零基础生信入门第一课——R语言数据清洗,超详细讲解,建议收藏!...
小伙伴们大家好!今天我要用一篇推文精要概括数据清洗中的最基本最关键的步骤,对于零基础的学员一定会有很大收获!数据清洗是完成一篇生信文章最基本但也是最终要的准备工作,如果不会数据清洗,就要错过很多优质数 ...
- C语言实现扫雷【超详细讲解】
目录 一.实现扫雷的基本思路 二.代码实现的具体步骤 三.完整代码 1.saolei.h部分 2.saolei.c部分 3.test.c部分 扫雷和三子棋有很多相似的地方,相信大家认真学习完三子棋再将 ...
- 超详细讲解C语言入门函数(一)
解析已经很详细了,可以说相当入门级别了,如果喜欢的话那就请支持一下,后续会继续更新~ 代码网上搜索,并加以更改,侵权请联系删除,谢谢~ 部分例子没有详细解释是因为前面的例子已经说过了 3×4矩阵求最大 ...
- C语言实现扫雷游戏(超详细讲解+全部源码)
电子信息 工科男 一点一点努力! 文章目录 前言 一.游戏介绍 二.游戏设计思路 二.具体步骤 1.创建test.c和game.c源文件以及 game.h头文件 2.创建菜单 3.创建雷盘 4.初始化 ...
最新文章
- android R文件丢失解决方法
- clearcase 创建副本
- JavaScript正则表达式详解(一)正则表达式入门
- Java中文问题详解
- c 语言 文本处理范例
- 3_1 StrategyMode.cpp 策略模式
- Spring Boot log4j2 configuration example
- JAMstack简介:现代Web的体系结构
- by group 累加中文字段_EF 求和 GroupBy多个字段
- 自动化调参NNI学习(三):使用python启动NNI框架调整随机森林(RandomForest)模型
- Android面向HTTP协议发送post请求
- 函数和常用模块【day06】:模块特殊变量(十四)
- 搜狗高速浏览器主页被篡改怎么办 搜狗浏览器中恢复被篡改主页的方法
- llq考试 圣诞欢乐赛 (第二发)
- 1024程序员节日背后的神秘面纱
- 关于对当前大学生的痛点分析
- MaximalRectangle
- css浏览器兼容性的问题
- 超级账本hyperledger fabric第五集:共识排序及源码阅读
- git bash返回上一级目录
热门文章
- c语言系统通常将一个判断为真,C语言程序设计学习-习题2
- 【记录】Tiff图像的前处理,median blur filter 及 linear stretch
- 蓝懿ios技术交流和心得分享 16.1.30
- grep(模式匹配器)详解
- 七大数据陷阱之技术过失(上):数据整理中的问题
- 1455 B - Jumps
- linux smit工具,Linux安全基础 SMIT入门
- ffmpeg使用bsf后码流从avcc格式变成annex-b造成硬解异常
- 华为时间管理之仁者见仁
- 在java中下列说法不正确的是,【单选题】关于java中的转义字符,下列说法不正确的是
A. 是制表位 B. 
可以实现换行 C. 可以在页面中显示双引号 D. \可以在页面实现注释...