5.单目操作符
单目操作符介绍
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
5.1 !操作符实例
#include<stdio.h>
int main()
{
//C语言中0表示假,非0表示真
int flag = 5;
if (flag)
{
printf("haha\n");
}
if (!flag)
{
printf("hehe\n");
}
printf("%d\n", !flag);
printf("%d\n",flag);
return 0;
}
C语言中0表示假,非0表示真
5.2 _Bool类型
这里提一下布尔类型,没必要赋值浮点数,负数等待,布尔类型就是为了不让胡乱赋值造的。
//布尔类型是用来表示真假的类型
#include<stdio.h>
#include<stdbool.h>
int main()
{
_Bool flag = true;//true,false
if (flag)
{
printf("hehe\n");
}
else
{
printf("hahaha\n");
}
}
5.3 ++、--操作符
++a//先++,后使用
a++//先使用,后++
--//相同道理
5.4 ()强制转换操作符
int main()
{
int a= (int)3.14;//强制类型转换,只拿整数部分,小数不要了
printf("%d", a);
}
//少用
int main()
{
srand((unsigned int)time());//需要一个time函数的返回值作为参数,但time()函数的返回值是time_t,srand又需要unsigned int类型。
}
5.5 unsigned int 问题:
int main() { unsigned int num = -10; printf("%u\n", num); int num1 = -10; printf("%d\n", num1); return 0; }
理解: unsigned int无符号位将本来数据的最高位符号位变成了有效位,那么数据就变大了。
5.6 &、*操作符
int main()
{
int a = 10;
printf("%p\n", &a);
int* pa = &a;
char ch = 'w';
char* pc = &ch;
//printf("%p\n", &ch);
char arr[10] = { 0 };
char* p2 = arr;
char* p3 = &arr[0];
char* p = "abcdef";
printf("%p\n", p);
printf("%c\n", *p);//打印的是a
return 0;
}
void test1(int *arr, int sz) { int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]);//*(arr+i),arr是首元素地址+i跳过i个整型 } } int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int sz = sizeof(arr) / sizeof(arr[0]); test1(arr, sz); return 0; }
从int*pa=&a来看,pa是指针变量,类型是int*,&a是取出a在内存空间中开辟的地址,*是解引用操作符,通过a的地址找到a,可以改变a的值。
而arr是首元素地址,+i跳过i个整型。
5.7 sizeof
函数调用的时候,要写()但是sizeof后边的括号可以省略,说明sizeof不是函数
sizeof既是操作符,也是关键字,可以求变量(类型)所占空间的大小
#include<stdio.h> int main(){ int a = 10; short s = 5; printf("%d\n", sizeof(s = a + 3)); printf("%d\n", s); return 0; }
上图说明sizeof内部的表达式是不计算的。
#include<stdio.h> int main() { int a = 10; printf("%d\n", sizeof(a)); printf("%d\n", sizeof a);//ok printf("%d\n", sizeof(int));//但是不能写出sizeof int int arr[10] = {0}; printf("%d\n", sizeof arr);//ok printf("%d\n", sizeof(arr));//ok printf("%d\n", sizeof(int[10]));//ok return 0; }
注意:不可写成sizeof 类型 ,不加()是不行的
5.8 sizeof与数组
#include<stdio.h> void test1(int arr[])//数组传参,形参可以写成数组,也可以写出指针 { //即使写成数组,本质上也是指针 printf("%zd\n", sizeof(arr)); } void test2(char ch[]) { printf("%zd\n", sizeof(ch)); } int main() { int arr[10] = { 0 }; char ch[10] = { 0 }; printf("%zd\n", sizeof(arr));//计算的数组大小 printf("%zd\n", sizeof(ch));//计算的数组大小 test1(arr); test2(ch); return 0; }
5.9 ~按位取反操作符:
~按位取反
00000000000000000000000000000000
11111111111111111111111111111111 - 补码是全1
int main() { int a = 0; printf("%d\n", ~a);//? return 0; }
#include<stdio.h> int main() { int a = 9; //00000000000000000000000000001001 //00000000000000000000000000010000 1<<4 //00000000000000000000000000011001 // //把a的二进制中第5位改成1 a |= (1<<4); printf("%d\n", a); //把a的二进制中的第5位改回来,变成0 //00000000000000000000000000011001 //11111111111111111111111111101111 //00000000000000000000000000001001 a &= (~(1 << 4)); printf("%d\n", a);//9 return 0; }
6.关系操作符
>
>=
<
<=
!= 用于测试“不相等”
== 用于测试“相等”
7.逻辑操作符
&& 逻辑与
|| 逻辑或
&(按位与)和|(按位或)是针对2进制来说的,而上述两个是针对真假来说的。
1&2----->0
1&&2---->1
1|2----->3
1||2---->1
&&逻辑与
//短路 int main() { int i = 0, a = 0, b = 2,c=3, d = 4; i = a++ && ++b && d++; printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d); return 0; }
&&左边为假,右边无需计算(自左向右, 只要有一个操作数为假,后面不用算了)。
|| 逻辑或
int main() { int i = 0, a =0, b = 2, c = 3, d = 4; i = a++ || ++b || d++; printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d); return 0; }
|| 左边为真,右边无需计算(自左向右, 只要有一个操作数为真,后面不用算了)。。
8.条件操作符
exp1 ? exp2 : exp3
真返回条件2,假返回条件3
#include<stdio.h> int main() { int a = 10; int b = 20; int m = 0; m= (a > b ? a : b); printf("%d\n", m); b = (a > 5 ? 3 : -3); printf("%d\n", b); return 0; }
9.逗号表达式
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
int main() { int a = 1; int b = 2; int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式,返回最后一个值,但前面的会影响后面的变量 printf("%d", c); }
逗号表达式,返回最后一个值,但前面的会影响后面的变量
10.下标引用、函数调用和结构成员
1. [ ] 下标引用操作符 ,操作数:一个数组名 + 一个索引值
2. ( ) 函数调用操作符 接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
int main()
{
int arr[10] = { 1,2,3,4,5,6 };
printf("%d\n", arr[4]);//下标引用操作符,操作数是arr,10;
int len = strlen("abcdef");//函数调用操作符,操作数是strlen,"abcdef"
return 0;
}
3. 访问一个结构的成员
. 结构体.成员名
-> 结构体指针->成员名
结构体-自定义类型(聚合类型),把简单的类型集合在一起
生活中有些对象要被描述的话,不能简单的使用单个内置类型(char int short long 、 long long 、 float、 double)
例如:
书:书名,作者,出版社,定价
学生:名字,年龄,学号.....
struct Book { char name[20]; char author[30]; int price; }; void print1(struct Book *b) { printf("《%s》%s %d\n", b->name, b->author, b->price); printf("《%s》%s %d\n", (*b).name, (*b).author, (*b).price); } int main() { struct Book b1 = { "单人破b","niko",60 }; struct Book b2 = { "全体白给","simple",80 }; //结构体变量.成员名 printf("《%s》 %s %d\n", b1.name, b1.author, b1.price); printf("《%s》 %s %d\n", b2.name, b2.author, b2.price); print1(&b1); //print1(&b1); return 0; }
#include<stdio.h> struct 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 *stu) { stu->age = 18; } int main() { struct Stu stu; struct Stu* pStu = &stu; stu.age = 20; set_age1(stu); printf("%d\n", stu.age); set_age2(&stu); printf("%d\n", stu.age); // set_age2(stu); }
这是结构体指针,第一个是传值调用,第二个是传址调用。