文章目录作者介绍:友友们好我是沐曦希,可以叫我小沐
作者主页:沐曦希的个人博客主页.
作者的gitee:https://gitee.com/muxi-c-language.
零基础学习C语言系列:
https://blog.csdn.net/m0_68931081/category_11742786.html.
小沐和友友们一样喜欢编辑,天天敲代码來,沉迷学习,日渐消瘦。很荣幸能向大家分享我的所学,和大家一起进步,成为合格的卷王。✨如果文章有错误,欢迎在评论区✏️指正。那么开始今天的学习吧!
- 操作符
- 算术操作符
- 移位操作符
- ✨左移操作符
- ✨右移操作符
- 逻辑移位
- 算术移位
- 位操作符
- &--按位与
- |--按位或
- ^--按位异或
- 赋值操作符
- ✨复合赋值操作符
- 单目操作符
- ✨单目操作符介绍
- ✨sizeof 和 数组
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用、函数调用和结构成员
- ✨[ ] 下标引用操作符
- ✨( ) 函数调用操作符
- ✨访问一个结构的成员
- 写在最后
操作符
指令系统的每一条指令都有一个操作符,它表示该指令应进行什么性质的操作。不同的指令用操作符这个字段的不同编码来表示,每一种编码代表一种指令。
其中操作符分为:
算术操作符
- 算术操作符
2.移位操作符
3.位操作符
4.赋值操作符
5.单目操作符
6.关系操作符
7.逻辑操作符
8.条件操作符
9.逗号表达式
10.下标引用、函数调用和结构成员
+ - *(乘) /(除) %(取模)
注意:1.✏️除了% 操作符之外,其他的几个操作符可以作用于整数和浮点数。
#includeint main() { int a = 12; int x = 5; float b = 7.0; float c = -6.0; float d = b + c; float e = b - c; float f = b * c; float g = b / c; int ret = a % x; printf("d=%fne=%fnf=%fng=%fnret=%d", d, e, f, g, ret); return 0; }
2.✏️对于/ 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
#includeint main() { int a = 20; int b = 10; int c = 20.0; int d = 10.0; int x = a / b; float y = c / d; printf("x=%dny=%f", x, y); return 0; }
3.✏️% 操作符的两个操作数必须为整数。返回的是整除之后的余数。
#include移位操作符int main() { int a = 8; int b = 3; int c = a % b; printf("%d", c); return 0; }
移位操作符针对的是二进制,所以移动的是二进制,每次运算时,第一步需要转换成对应的二进制,再进行移位。
<< 左移操作符 >> 右移操作符 注:移位操作符的操作数只能是整数。✨左移操作符
移位规则:
左边抛弃、右边补0
#includeint main() { int num = 2; printf("num<<1=%d", num << 1); return 0; }
当num=-2时:
#includeint main() { int num = -2; printf("num<<1=%d", num << 1); return 0; }
左移一位相当于该数字乘于2,
右移操作符相对复杂一点。分为逻辑移位和算术移位。在转换成二进制时,二进制的第一个数字表示正负,即当第一个数字为0时,该数字为正,为1时,该数字为负
例如:
✏️小知识:整数的二进制表示有三种方式:原码,反码,补码。
正整数的原码,反码和补码相同。
负整数的原码,反码和补码不相同。
其中在存储时候,存储的是补码。
移位规则:
左边用0填充,右边丢弃
#include算术移位int main() { int num = -2; int a = num >> 1; printf("%d", a); return 0; }
移位规则:
左边用原该值的符号位填充,右边丢弃
#includeint main() { int num = -2; int a = num >> 1; printf("%d", a); return 0; }
小沐用的编译器支持的是算术右移。
警告⚠ :
对于移位运算符,不要移动负数位,这个是标准未定义的。(浮点数也不行)
例如:
int num = 10; num>>-1;//error
右移一位相当于除与2。
位操作符位操作符是二进制的运算,故与移位操作符一样,运算的第一步应讲操作数转换成二进制。位操作符只适用于整型。
位操作符有:
& //按位与 | //按位或 ^ //按位异或
注:他们的操作数必须是整数。
&–按位与运算规则:有零则为零,同为一才为一。✏️
0&0=0 1&0=0 1&1=0 0&1=0
例如:
#includeint main() { int a = 3; int b = -5; int c = a & b; printf("%d", c); return 0; }
运算规则:有1则为1,同为零才为零。✏️
1|1=1 1|0=1 0|0=1 0|1=1
例如:
#includeint main() { int a = 3; int b = -5; int c = a | b; printf("%d", c); return 0; }
运算规则:相同为0,不相同为1。✏️
1^0=1 0^1=1 0^0=0 1^1=0
例如:
#includeint main() { int a = 3; int b = -5; int c = a ^ b; printf("%d", c); return 0; }
练习:
不能创建临时变量(第三个变量),实现两个数的交换。
//代码一 #includeint main() { int a = 3; int b = 5; printf("交换前:a=%d,b=%dn", a, b); a = a + b; b = a - b; a = a - b; printf("交换后:a=%d,b=%dn",a, b); return 0; }
代码一容易溢出,当a和b都很大时,容易导致a=a+b溢出。
故:
//代码二 #includeint main() { int a = 10; int b = 20; a = a ^ b; b = a ^ b; a = a ^ b; printf("a = %d b = %dn", a, b); return 0; }
通过:
3^3=0 0^5=5 a^a=0 0^a=a 即3^3^5=0^5=5 3^5^3=5
则按位异或支持交换律。
在写代码时候可以通过赋值操作符给变量赋值,从而得到想要的结果。
int weight=120//初始化 weight=90//赋值//注:初始化和赋值不一样 int high=175//初始化 high=185///赋值 //赋值操作符可以连续使用,比如: int a = 10; int x = 0; int y = 20; a = x = y+1;//连续赋值 //先x=y+1=20+1=21,后a=x=21 //这样的代码感觉怎么样? //那同样的语义,你看看: x = y+1; a = x; //这样的写法是不是更加清晰爽朗而且易于调试。✨复合赋值操作符
复合赋值操作符的运算规则和前面的类似。
+= -= *= /= %= >>= <<= &= |= ^=
这些运算符都可以写成复合的效果。
int a+=5//a=a+5 int a-=5//a=a-5 int a*=5//a=a*5 int a/=5//a=a/5 int a%=5//a=a%5 int a>>=5//a=a>>5 int a<<=5//a=a<<5 int a&=5//a=a&5 int a|=5//a=a|5 int a^=5//a=a^5单目操作符
单目操作符只有一个操作数。
✨单目操作符介绍! 逻辑反操作 - 负值 + 正值 & 取地址 sizeof 操作数的类型长度(以字节为单位) ~ 对一个数的二进制按位取反 -- 前置、后置-- ++ 前置、后置++ * 间接访问操作符(解引用操作符) (类型) 强制类型转换
//! 逻辑反操作 #includeint main() { int flag = 1; if (!flag)//flag为假,进入if语句 { printf("是沐曦希呀n"); } if (flag)//flag为真,进入if语句 { printf("是小沐呀n"); } return 0; }
// -(负值) +(正值) //负负得正 正正得正 负正得负 #includeint main() { int a = -10; int b = +a; int c = -a; printf("b=%dnc=%dn", b, c); return 0; }
//&--取地址操作符 #includeint main() { int a = 0; printf("%pn", &a);//打印a的地址 return 0; }
//sizeof 操作数的类型长度(以字节为单位) #includeint main() { int a = 10; int n = sizeof(a);//计算的是a所占的内存的大小,单位是字节 printf("n=%dn", n); //szieof是一个单目操作符 //计算的是变量所占内存空间的大小 int set = sizeof(int); //计算类型所创建的变量所占据空间的大小,单位是字节 printf("set=%dn", set); int sz = sizeof a;//操作符可以省略变量的(),但是类型不能省去 printf("sz=%dn", sz); return 0; }
//~ 对一个数的二进制按位取反//即将0变成1,1变成0 #includeint main() { int a = 0; printf("%dn", ~a); return 0; }
#includeint main() { int a = 3; printf("%dn", ~a); return 0; }
//++ 前置、后置++ #includeint main() { int a = 3; int b = ++a;//前置++,先++,后使用//a=a+1,b=a int c = a++;//后置++,先使用,后++//c=a,a=a+1 printf("a=%d,b=%d,c=%d", a, b, c); return 0; }
//-- 前置、后置-- #includeint main() { int a = 3; int b = --a;//前置--,先--,后使用//a=a-1,b=a int c = a--;//后置--,先使用,后--//c=a,a=a-1 printf("a=%d,b=%d,c=%d", a, b, c); return 0; }
#includeint main() { int a = 10; printf("%dn", a--);//后置-- printf("%dn", a); int i = 0; for (i = 0; i < 3; i++) { printf("%d ", i); } printf("n"); for (i = 0; i < 3; ++i) { printf("%d ", i); }//在for语句中前置和后置无区别,只是前置效率高。 return 0; }
//* 间接访问操作符(解引用操作符)//通常与指针一起使用 #includeint main() { int a = 10; int* p = &a; *p = 20;//a=20 printf("a=%dn", a); printf("*p=%dn", *p); printf("p=%pn", p); return 0; }
//(类型) 强制类型转换//即强制将一种类型转换成另一种类型 #include✨sizeof 和 数组int main() { int a = (int)3.14; printf("%dn", a); return 0; }
初学C语言时,经常用到sizeof来求数组的大小和元素个数等。
需要区别strlen和sizeof。
sizeof是一个单目操作符,不是一个函数。
strlen是一个库函数,头文件为string.h,是用来求字符串的长度。
例如:
#include#include void test1(int arr[]) { printf("arr[]=%dn", sizeof(arr)); } void test2(char ch[]) { printf("ch[]=%dn", sizeof(ch)); } int main() { int arr[10] = { 0 }; char ch[10] = { 0 }; printf("arr[10]=%dn", sizeof(arr)); printf("ch[10]=%dn", sizeof(ch)); test1(arr); test2(ch); return 0; }
注意:1.指针变量不管所指的变量是什么类型,其大小都是4或者8个字节。✏️
当配置是x86时,大小为4个字节;配置为x64时,大小为8个字节。
2.数组作为参数传参时候,传的是数组的首元素的地址。
小知识:
//strcmp是用来比较字符串的内容 //strcpy是用来拷贝内容的 #include#include int main() { char arr[10] = { 0 }; char ch[5] = "abcd"; strcpy(arr, "母亲节快乐!"); printf("%dn", sizeof(ch)); printf("%dn", strlen(ch)); if (~strcmp(ch, "abc")) { printf("祝小沐的妈妈"); } printf("%sn", arr); return 0; }
strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1
str2,则返回正数。
strlen是用来求字符串的长度。
strlen遇到’ ’则停止并返回,只会计算‘ ’之前的元素个数。
sizeof可以求变量(类型)所占空间的大小。
> >= < <= != 用于测试“不相等” == 用于测试“相等”
这些关系运算符比较简单,但是我们要注意一些运算符使用时候的陷阱。
例如:在编程的过程中把==写成=,导致错误
#includeint main() { int a = 0; if (a = 1) { printf("hehen"); } if (a == 2) { printf("hahan"); } return 0; }
if("abc"=="abcdef")//这样写是比较两个字符串的首字符的地址
//比较字符串用strcmp
逻辑操作符
逻辑操作符只关注真假,真则返回1,假则返回0。
&& 逻辑与 || 逻辑或
区分 逻辑与(&&) 和 按位与(&)
区分 逻辑或(||) 和 按位或(|)
#includeint main() { printf("%dn", 1 & 2); printf("%dn", 1 && 2); printf("%dn", 1 | 2); printf("%dn", 1 || 2); return 0; }
//练习1 #includeint main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++;//后置++,因为a=0,即为假,故后面的++b和d++不会运行,只运行a=a+1 printf("a = %dn b = %dn c = %dnd = %dn", a, b, c, d); return 0; }
//练习2 #includeint main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++||++b||d++;//因为前置++b,b=3,故为真,即运行a++,++b和d++ printf("a = %dn b = %dn c = %dnd = %dn", a, b, c, d); return 0; }
&&–左边为假,即为假,则右边就不用计算了。
||–左边为真,即为真,则右边就不用计算了。
条件操作符也叫三目操作符
exp1 ? exp2 : exp3
//使用条件表达式实现找两个数中较大值。 #includeint main() { int a = 10; int b = 20; printf("%dn", a > b ? a : b); return 0; }
if (a > 5) b = 3; else b = -3; //转换成条件表达式 #include逗号表达式int main() { int b = 0; int a = 0; b = (a > 5 ? 3 : -3); return 0; }
exp1, exp2,exp3...expN
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
//c是多13
//代码2
if (a =b + 1, c=a / 2, d > 0)//if(d>0)
//代码3
a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
a = get_val();
count_val(a);
}
//如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{
//业务处理
}
下标引用、函数调用和结构成员
✨[ ] 下标引用操作符
操作数:一个数组名 + 一个索引值
#include✨( ) 函数调用操作符int main() { int arr[10] = { 0 }; arr[7] = 8;//[]是下标引用操作符(双目操作符:arr和7是操作数) 7[arr] = 9;//arr[7]-->*(arr+7)-->*(7+arr)-->7[arr]//arr是数组的首元素地址 //arr+7就是跳过7个元素,指向第8个元素。//*(arr+7)就是第8个元素 printf("%dn", arr[7]); printf("%dn", 7[arr]); return 0; }
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
#includevoid test1() { printf("hehen"); } void test2(const char* str) { printf("%sn", str); } int main() { test1(); //实用()作为函数调用操作符。//操作数只有一个,即为test1 test2("hello");//实用()作为函数调用操作符。//操作数有两个,test2和"hello"。 return 0; }
int c=Add(a,b);//()是函数调用操作符,操作数:Add,a,b //函数调用操作符()的操作数至少有一个,即为函数名✨访问一个结构的成员
. 结构体.成员名 -> 结构体指针->成员名
#includestruct Stu { char name[10]; int age; char sex[5]; double score; }; void set_age1(struct Stu stu) { stu.age = 18; } void set_age2(struct Stu* pStu) { pStu->age = 18;//结构成员访问 } int main() { struct Stu stu; struct Stu* pStu = &stu;//结构成员访问 stu.age = 20;//结构成员访问 set_age1(stu); pStu->age = 20;//结构成员访问 set_age2(pStu); return 0; }
#include写在最后#include struct Stu { char name[20]; int age; double score; }; void set_stu(struct Stu* ps) { //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 %lfn", ps->name, ps->age, ps->score); } int main() { struct Stu s = { 0 }; set_stu(&s); print_stu(&s); return 0; }
那么今天的学习就到这里了。友友们觉得不错的可以给个关注,点赞或者收藏哦!感谢各位友友们的支持。以下的代码希望各位大佬们自行检验哦,毕竟亲手操作让记忆更加深刻。
你的❤️点赞是我创作的动力的源泉
你的✨收藏是我奋斗的方向
你的关注是对我最大的支持
你的✏️评论是我前进的明灯
创作不易,希望大佬你支持一下小沐吧
下一期见了!



