C语言-操作符与表达式
C语言入门之操作符与表达式
前言
本篇文章主要包括各种操作符的介绍与表达式求值,欢迎各位小伙伴与我一起学习。
一、操作符
分类
- 算术操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目运算符
- 关系操作符
- 逻辑操作符
- 条件运算符
- 逗号运算符
- 下标访问,函数调用和结构体员
1.算术操作符
+ 加 - 减 * 乘 / 除 % 取余
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 5/2;
printf("%d",a);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
float a = 5.0/2;
printf("%lf",a);
return 0;
}
- 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
- 对于 / 操作符,如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
- %操作符的两个操作数必须为整数,返回的是整除之后的余数。
2.移位操作符
<< 左移操作符
>> 右移操作符
左移操作符规则
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 5;
int b = a<<1;
printf("%d",b);
return 0;
}

规则:左边丢弃,右边补0
警告:对于位运算符,不要移动负数位,这个是标准未定义的。
例:
int num=10;
num>> -1 ;
右移操作符规则
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 16;
// >> 右移操作符
//移动的是二进制位
//00000000000000000000000000010000
//32个bit位
int b = a>>1;
printf("%d",b);
return 0;
}
右移操作符:
1.算术右移:
右边丢弃,左边补原符号位(我们见到的基本上都是算术右移)
2.逻辑右移:
右边丢弃,左边补0
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = -1;
//存储到内存的是补码
//1000000000000000000000000000001
//第一位是符号位,1表示负数,0表示正数
int b = a>>1;
printf("%d",b);
return 0;
}
整数的二进制表示形式有三种(正数的反码和补码与原码一样)
原码:直接根据数值写出的二进制序列
反码:原码的符号位不变,其他位按位取反就是反码
补码:反码+1
例:
-1的原反补:
原码:1000000 00000000 00000000 00000001
反码:1111111 11111111 11111111 11111110
补码:1111111 11111111 11111111 11111111
3.位操作符
按位与操作符:&
按位或操作符: |
按位异或操作符: ^
都是用补码进行计算,如果是负数,要先找出它的补码进行计算:a-b=a的补码+(-b)的补码
按位与:有一个为0,结果就为0,两个都为1,结果才为1.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 3;
int b = 5;
int c = a&b;
printf("%d",c);
return 0;
}
按位或 :有一个为1,结果就为1,两个都为0,结果才为0.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 3;
int b = 5;
int c = a|b;
printf("%d",c);
return 0;
}
按位异或 :相同为0,相异为1.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 3;
int b = 5;
int c = a^b;
printf("%d",c);
return 0;
}
不创建临时变量(第三个变量),交换两个数:
1.加减法
缺点:可能会溢出,不可取
a = a + b;
b = a - b;
a = a - b;
2.乘除法
缺点:可能会溢出,不可取
a = a * b;
b = a / b;
a = a / b;
3.异或法
不会溢出
a = a ^ b;
b = a ^ b;
a = a ^ b;
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 2;
int b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a: %d \n", a);
printf("b: %d \n", b);
return 0;
}
//第一次:010^101=111
//第二次:111^101=010
//第三次:111^010=101
4.赋值操作符
赋值操作符就是你的变量已经有一个值了,但是你不满意,你就可以使用它把一个新的值赋值给它,其实就是把右边的值赋值到左边,放进变量里进行存储。
赋值操作符是一个等号,而判断操作符是两个等号。
复合操作符:
+= -= ^= *= %= >>= <<= &= |= ^=
5.单目运算符
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度
~ 对一个数的二进制按位取反
-- 前置,后置--
++ 前置,后置++
* 间接访问操作符
(类型) 强制转换类型
取地址:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 5;
int* p = &a;
*p = 10;
printf("%p\n", &a);
printf("*pa: %d\n", *pa);
printf("a: %d\n", a);
return 0;
}
sizeof 计算的是变量所占内存空间的大小:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 10;
char c = 'r';
char* p = &c;
int arr[10] = { 0 };
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(c));
printf("%d\n",sizeof(p));
printf("%d\n",sizeof(arr));
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
short s = 0;
int a = 10;
printf("%d\n",sizeof(s = a + 5));
//算的是s的大小,s是short型,占两个字节
//sizeof里的表达式不进行运算
printf("%d\n",s);
return 0;
}
++ 的使用:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 10;
int b = 10;
printf("%d\n",++a);
printf("%d\n",b++);
printf("%d\n",b);
return 0;
}
强制类型转换:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = (float)3.14;
//将float类型强制转换成int类型
printf("%d\n",a);
return 0;
}
sizeof与数组:
#include <stdio.h>
#include <stdlib.h>
void test1(int arr[])
{
printf("%d\n",sizeof(arr));
}
void test2(char ch[])
{
printf("%d\n",sizeof(ch));
}
int main()
{
int arr[10] = { 0 };
char ch[10] = { 0 };
printf("%d\n",sizeof(arr));
printf("%d\n",sizeof(ch));
test1(arr);
test1(ch);
return 0;
}
6.关系操作符
> , >=
< , <=
!= 不等于
== 判断两个数是否相等
= 赋值
7.逻辑操作符
逻辑与 &&
逻辑或 ||
&&:如果逻辑与左边的条件为假的话,后面就不用算了
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0;
int b = 2;
int c = 3;
int d = 4;
int i = 0;
i = a++ && ++b && d++;
printf(" a = %d\n b = %d\n c = %d\n d = %d\n", a, b, c,d);
return 0;
}
||:如果逻辑或左边的条件为真的话,后面就不用算了
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0;
int b = 2;
int c = 3;
int d = 4;
int i = 0;
i = a++ || ++b || d++;
printf(" a = %d\n b = %d\n c = %d\n d = %d\n", a, b, c,d);
return 0;
}
8.条件运算符
exp1 ? exp2 : exp3
三目操作符: x > n ? 1 : 0
这里的意思是x大于n吗?true返回1,否则为0
9.逗号运算符
逗号表达式,就是用逗号隔开的多个表达式,从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 1;
int b = 2;
int c = (a > b,a = b + 1,a,b = a + 1);
printf("%d\n",c);
}
10.下标访问,函数调用和结构成员
1. [ ]下标引用操作符,操作数:一个数组名 + 一个索引值
2. 函数调用操作符( ),一个函数callFunc( )
3. 结构成员访问操作符分两种 . 和 ->
1.下标访问:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
printf("%d\n",arr[9]);
return 0;
}
2.函数调用:
#include <stdio.h>
#include <stdlib.h>
int get_max(int x,int y)
{
if(x > y)
return x;
else
return y;
}
int main()
{
int a,b;
int max = 0;
scanf_s("%d%d",&a,&b);
max = get_max(a,b);
//调用函数的时候的()就是函数调用操作符
//操作数有三个,函数名get_max,参数a和b
printf("%d\n",max);
return 0;
}
3.访问一个结构体的成员:
#include <stdio.h>
#include <stdlib.h>
struct str
{
char name[20];
char id[20];
int age;
};
int main()
{
struct str s = {"uzi", "006", 18};
printf("Name: %s\n", s.name);
printf("Id : %s\n", s.id);
printf("Age: %d\n", s.age);
return 0;
}
它本身就向内存申请了一部分空间,你也可以用指针来写
#include <stdio.h>
#include <stdlib.h>
struct str
{
char name[20];
char id[20];
int age;
};
int main()
{
struct str s = {"uzi", "006", 18};
struct str* ps = &s;
printf("%s\n", (*ps).name);
//也可以这样写:printf("%s\n", ps->name);
return 0;
}
二、表达式求值
表达式求值的顺序一部分是由操作符的优先级和结合性决定的,
同样,有些表达式的操作数在求值时的过程中可能需要转换为其它类型。
隐式类型转换
C的整型算术运算符总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
如何进行整体提升?
整型提升是按照数据类型的符号位来提升的。
整形提升规则:有符号数,高位补符号位 ; 无符号数,高位补0.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char a = 3;
//000000000000000000000011
//它取值时取的是它的高位:00000011 -a
char b = 127;
//000000000000000001111111
//高位:01111111 -b
char c = a + b;
//000000000000000000000011 -a
//000000000000000001111111 -b
//000000000000000010000010 -c
//a和b在这之前已经发生整型提升
printf("%d\n",c)
//高位:10000010 -c
//111111111111111110000010 -补码
//111111111111111110000001 -反码
//100000000000000001111110 -原码
//-126
return 0;
}
算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。
下面的层次体系成为:寻常算术转化。
long double
double
float
unsugned long int
long int
unsigned int
int
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另一个操作数的类型后执行运算,并且是低的转换为高的。
注意:算数转换要合理,要不然会有一些潜在的问题
操作符的属性
复杂表达式的求值有三个影响的因素:
1.操作符的优先级
2.操作符的结合性
3.是否控制求值顺序
如果两个操作符相邻,先执行哪个取决于它们的优先级,如果优先级相同就取决于它们的结合性。
#include <stdio.h>
#include <stdlib.h>
int fun()
{
static int count = 1;
return ++count;
//2 3 4
}
int main()
{
int anwer;
anwer = fun() - fun()*fun();
printf("%d\n", anwer);
//这个代码是有问题的,你不知道它先调用的是谁
//有可能是2-3*4 又或者是4-2*3
return 0;
}
注意: 一定要保证只有唯一的一个运算顺序,不然代码就是错误的。
结尾
为梦想颠簸的人有很多,不差你一个,但如果你能坚持到最后,那你就是唯一。半山腰太挤了,总得去山顶看看。
C语言-操作符与表达式的更多相关文章
- LinQ实战学习笔记(三) 序列,查询操作符,查询表达式,表达式树
序列 延迟查询执行 查询操作符 查询表达式 表达式树 (一) 序列 先上一段代码, 这段代码使用扩展方法实现下面的要求: 取进程列表,进行过滤(取大于10M的进程) 列表进行排序(按内存占用) 只保留 ...
- 《Pointers On C》读书笔记(第五章 操作符和表达式)
1.C语言操作符优先级表 2.算术操作符中%(取模操作符)只适用于整型类型,其余几个操作符(+.-.*./)既适用于整型类型也适用于浮点类型.当/操作符的两个操作数都是整型时,它执行整除运算,其它情况 ...
- C语言操作符
C语言操作符的分类: 算术操作符 逻辑运算符 位操作符 赋值操作符 单目操作符 关系操作符 条件操作符 逗号表达式 数组下标引用 函数调用 结构体成员使用 大体上,C语言的操作符具体就这么些, ...
- c语言,中缀表达式转后缀表达式并计算
//c语言中缀表达式计算 #include <stdio.h> #include <stdlib.h> #include <string.h> #include & ...
- 《Visual C# 从入门到精通》第一章使用变量、操作符和表达式——读书笔记
前言: 这个笔记是我个人总结,主要是熟练自己查看<Visual C# 从入门到精通>(第8版)这本书时,懵然起总结的想法,只是总结一些知识点,在工作项目会用得上,但是对毫无C#语言基础的, ...
- C#6.0语言规范(七) 表达式
表达式是运算符和操作数的序列.本章定义了操作数和运算符的语法,求值顺序以及表达式的含义. 表达式分类 表达式分类为以下之一: 一个值.每个值都有一个关联的类型. 一个变量.每个变量都有一个关联的类型, ...
- C语言操作符学习总结
c语言中关于操作符部分的学习,可以主要分为两个部分:操作符和表达式. 这里首先是列举各种操作符,在C语言中,一般主要的操作符有这么几种:算数操作符,移位操作符,位操作符,赋值操作符,单目运算符,关系操 ...
- Java入门基础(变量、操作符与表达式)
Java入门基础 1. 第一个程序 2.变量(命名.运算.整数/小数/字符串.布尔类型) 3.操作符与表达式(算术/逻辑/关系/赋值/自增/类型转换操作符) HelloWorld! public cl ...
- 释放Android的函数式能量(I):Kotlin语言的Lambda表达式
原文标题:Unleash functional power on Android (I): Kotlin lambdas 原文链接:http://antonioleiva.com/operator-o ...
随机推荐
- MySQL-DB-封装-简易版
<?php class DB{ private $link; public function __construct($host,$user,$password,$dbname,$port) { ...
- ArcMap操作随记(9)
1.类似PS中功能的工具 [镜像要素].[比例].[延伸] 2.快速获得栅格统计参数 [获取栅格属性]工具 3.[编辑器][创建要素][构造工具] 可以右键,输入半径等参数 4.计算面的角度 [计算面 ...
- Java的jstack命令使用详解
jstack命令简介 jstack(Java Virtual Machine Stack Trace)是JDK提供的一个可以生成Java虚拟机当前时刻的线程快照信息的命令行工具.线程快照一般被称为th ...
- 高级IO模型之kqueue和epoll
目录 简介 block IO和nonblocking IO IO多路复用和select poll epoll kqueue epoll和kqueue的优势 简介 任何一个程序都离不开IO,有些是很明显 ...
- DDD 领域驱动设计之面向对象思想
面向对象 面向对象是一种对世界理解和抽象的方法.那么对象是什么呢? 对象是对世界的理解和抽象,世界又代称为万物.理解世界是比较复杂的,但是世界又是由事物组成的. 正是这样的一种关系,认识事物是极其重要 ...
- Objective-C 基础教程第七章,深入理解Xcode
目录 Object-C 基础教程第七章,深入理解Xcode 0x00 前言 0x01 创建工程界面 0x02 主程序界面 ①顶部 Top Test(测试) Profile(动态分析) Analyze( ...
- Linux下编译安装mysql数据库服务
以下是用putty工具远程登录到服务器,在命令行下面操作: Cmake工具下载地址:http://ftp.lfs-matrix.net/pub/blfs/conglomeration/cmake/ M ...
- Vue中import和require的对比
Vue中import和require的对比 一.前言 vue框架想必是我们前端朋友们必学的知识点,说它难也没有那么难,说简单也没有那么简单,主要技术就是那么几个,可是里面的细节很多,有些时候我们会 ...
- 22.1.7 master公式及O(NLogN)的排序
22.1.7 master公式及O(NLogN)的排序 1 master 公式 (1) 写公式 T(N) = a * T(N/b) + O(N^d); master公式用来求递归行为的时间复杂度,式中 ...
- Java基础(补充)
为什么 Java 中只有值传递? 开始之前,我们先来搞懂下面这两个概念: 形参&实参 值传递&引用传递 形参&实参 方法的定义可能会用到 参数(有参的方法),参数在程序语言中分 ...