C语言——操作符(总结)

算术操作符  
   +       -         *            /                  %

   加       减       乘           除(取商)       除(取余)                                
   1:.   使用/(取商操作符)时,一般是这样的
#include
int main()
{
  int a = 3/5;
  printf("%d\n",a);
  return 0;
}
//结果:0
若想求出有小数点后的数,则必须满足数据,数字,打印类型的准确。如:
#include

int main()

{

  double a = 6.0/5.0;//两个数字至少有一个得是浮点数

//当两数均是整形时,无论数据类型是int还是double都取整数即1

 printf("%lf\n",a);//注意这里不是%d

 return 0;

}

结果:1.200000
   2.%  取模操作符  取余数。其两个操作数只能是整形
#include
int main()
{
  int  a = 6%4;
  printf("%d\n",a);
  return 0;
}
移位操作符     
<<                           >>

 左移操作符                   右移操作符             

C语言——操作符(总结)_第1张图片

(展示二进制后面的)a 0010          b  1000

图中<<的意思是把a的二进制位 向左移动两为位

C语言——操作符(总结)_第2张图片

a = 1010         b = 0010

总结:   左移操作符:左边丢弃几位,右边补几个0

          右移操作符:

                算术右移 :     将右边丢弃的放到左边 

                逻辑右移  :   右边丢弃几位,左边补几个0  

(对有符号数使用算术右移,对于无符号数,必须是逻辑右移)  

拓展:

(计算机存储都是以二进制补码的形式存放的)

正整数的原码,反码和补码相同

负整数的补码是将它的原码非符号位取反再加一

整数的二进制表示形式,其实有三种:原码,反码,补码

原码:直接根据数值写出的二进制序列

反码(对于负数):将原码的符号位(二进制的首位)不变,其它位按位取反,  当符号位是1时表示负号,0表示正数号                        

补码(对于负数):反码加1



如将负数-1存放在内存中,存放的是二进制的反码

-1: 原码:10000000000000000000000000000001

       反码:11111111111111111111111111111110  

        补码:   11111111111111111111111111111111    注意:对于移位操作符,不要移动负数位,这个是标准未定义的    例如:

int num = 10;
num>>-1;//是错误的
                


位操作符        
   &                |                   ^            
 按位与              按位或               按位异或         
              (他们的操作数必须是整数)                        
 
  

#include
int main()
{
  int a = 3;
  int b = 5;
  //   & 按(二进制)位与
  int c = a & b;
  //按位与就是上下对应的二进制位,对应的位中只要有0则新的数的二进制为0,同时为1才为1  
  //3:00000000000000000000000000000011
  //5:00000000000000000000000000000101
  //c = 1:00000000000000000000000000000001
  
  //  |  按(二进制)位或  
  int d = a | b;
  //按位或就是对应的位中只要有1则就是1,当两个都是0时才为0
  //3:00000000000000000000000000000011
  //5:00000000000000000000000000000101
  //d = 7:00000000000000000000000000000111
  
  //  |  按(二进制)位异或  
  int d = a ^ b;
  //对应的位相同时为0,相异为1
  //3:00000000000000000000000000000011
  //5:00000000000000000000000000000101
  //e = 6:00000000000000000000000000000110
}
            
                                                                       



赋值操作符

可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值

=
int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;//薪水
salary = 20000.0;//使用赋值操作符赋值

赋值操作符可以连续使用,比如:
int a = 10;
int x = 0;
int y = 20;
a = x = y+1;//进行连续赋值

这样的代码感觉怎么样?
那同样的语义,你看看:
x = y+1;
a = x;//这样的写法更加清晰且易于调试。
2.复合赋值符

+=    -=     *=       /=    %=      >>=    <<=      &=      |=       ^=

int a = 10;
a = 100;
a += 100//等于a = a+100

a = a>>3//等于a >>= 3
注意: = 是赋值  ,   ==是判断相等



单目操作符

**

!      逻辑反操作<可以理解为否定,不的意思>

-      负值

+      正值

&      取地址

sizeof    操作数的类型长度(以字节为单位)

~      对一个数的二进制按位取反(包括符号位)

--      前置、后置--

++      前置、后置++

*      间接访问操作符(解引用操作符)

(类型)    强制类型转换

***

 !


//!
#include
int main()
{
    int flag = 5;//flag为真,非0为真
    printf("%d\n",!flag);//!将真的改成假的了,所以为0
    return 0;
}
//结果:0
***

//sizeof
#include
int main()
{
  int a = 10;
  int arr[10] = {0};
  printf("%d\n",sizeof(arr));//计算数组的大小,结果:40
  printf("%d\n",sizeof(int [10]));//40,除了数组名剩下的都是类型
  printf("%d\n".sizeof(a));//计算a空间所占的大小,单位是字节
  printf("%d\n".sizeof(int));//也可以直接计算类型
  printf("%d\n".sizeof a);//计算字符大小时小括号可以省略,但是类型不能省
  //所以sizeof是一个操作符,不是一个函数,函数的括号必须带
}

#include
int main()
{
  short a = 10;
  int s = 5;
  printf("%d\n",sizeof(s)); //4
  printf("%d\n",sizeof(a));//2
  printf("%d\n",sizeof(a = s + 2));//结果仍然是2,因为sizeof中的表达式是不参与运算的

  return 0;
}

#include 
void test1(int arr[])
{
   printf("%d\n", sizeof(arr));//(2)//这里是指针,因为传过来的是地址要拿指针接收 在32为机器下 字节为4
}
void test2(char ch[])
{
   printf("%d\n", sizeof(ch));//(4)//同理,虽是char型,但是为指针变量在32上为4,64上为8
}
int main()
{
   int arr[10] = {0};
   char ch[10] = {0};
   printf("%d\n", sizeof(arr));//(1)       40
   printf("%d\n", sizeof(ch));//(3)        10
   test1(arr);
   test2(ch);
   return 0;
 }
***
//~
~对于正数是将原码全部按位取反(包括符号位)。对于负数是将其的补码全部按位取反(包括符号位)


int main()
{
    int a = -1;
    //原码:10000000000000000000000000000001
    //反码:11111111111111111111111111111110
    //补码:11111111111111111111111111111111
    //~ 按(二进制补码)位取反(包括符号位)
    //原补码:11111111111111111111111111111111
    //后补码:00000000000000000000000000000000
    int b = ~a;
    printf("%d\n",b);//结果:0
    return 0;
}
***

//++和--运算符 :       前置++和--      后置++和--



#include 
int main()
{
    int a = 10;
    int x = ++a;//先增加a,后使用a
    int y = --a;//先减小a,后使用a

    int x = a++;//先使用a,再增加a
    int y = a--;//先使用a,再减小a
    return 0;
 }

#include
int main()
{

  int a = 1;
  int b = (++a) + (++a) + (++a);//结果:由于编译器系统的不同坑能有2种结果12/10
  printf("%d\n",b);
  return 0;

}
***

* 间接访问操作符(解引用操作符)
&    取地址(注意a & b中&是按位与,&a中&是取地址符)
#include
int main()
{
  int a = 10;
  printf("%p\n",&a);//取a的地址,并打印地址
  int* pa = &a;//这里*说明pa是指针变量,pa是用来存放地址的
  *pa = 20;//*  间接访问操作符(解引用操作符),将a的值变成了20
  printf("%d\n",a);
  return 0;
}
(类型)    强制类型转换
int main()
{
  int a = (int)3.14;
  return 0;
}

 

关系操作符

>
>=
<
<=
!=   用于测试“不相等”
==   用于测试“相等”

注意:比较两个字符串相等不能使用==

逻辑操作符  (判断真假,真的结果是1,假是0)    

        &&                       ||  

      逻辑与(并且)          逻辑或 (或者)        

                   

#include
int main()
{
   int a = 2;
   int b = 0;
   if(a && b)//&&  意思是a,b都为真时进入,至少有一个为假时跳过
   {
     printf("hehe\n");
   }
   if(a || b)//||  只要有一个为真就为真,同时为假时才为假
   {
      printf("haha\n");
   }
   return 0;
}

并不会打印
打印haha



区分逻辑与(&&)      和     按位与(&)   1&2----->0   1&&2---->1

区分逻辑或(||)      和     按位或(|)   1|2----->3      1||2---->1

#include 
int main()
{
    int i = 0,a = 0,b = 2,c = 3,d = 4;
    i = a++ && ++b && d++;
    printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
    return 0; 
}
int main()
{
  int i = 0, a = 1, b = 2, c = 3, d = 4;
  i = a++||++b||d++;
  printf("i = %d\n a = %d\n b = %d\n c = %d\nd = %d\n", i .a, b, c, d);
  return 0;
}
//1 2 2 3 4//当a = 0时
int main()
{
  int i = 0, a = 0, b = 2, c = 3, d = 4;
  i = a++||++b||d++;
  printf("i = %d\n a = %d\n b = %d\n c = %d\nd = %d\n", i .a, b, c, d);
  return 0;
}
//1 1 3 3 4

 注意:

优先权平等下从左到有开始运算

逻辑与运算碰到错误直接结束,后面的运算就不再继续

逻辑或运算碰到正确直接结束,后面的运算就不再继续

(可以理解为从左到右运算时,逻辑与的话是遇到0即假时仅运算该运算符前的,后面的不在运算即原值。逻辑或同理)

条件操作符(三目操作符)

exp1 ? exp2 : exp3

exp1表示判断条件,exp2是exp1成立时的结果,exp3是不成立的结果
int main()
{
  int a = 3;
  int b = 0;
  /*
  if(a>5)
      b = -1;
  else
      b = 1;*/
   //可用条件操作符达成 
  b = (a>5 ? -1: 1) ; 
    
}


逗号表达式(就是用逗号隔开的多个表达式)

exp1, exp2, exp3, …expn

逗号表达式,从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
//逗号表达式使用灵活,可用在很多地方

int main()
{
   int a = 2;
   int b = 4;
   int c = 5;
   int d = (c = 3,a = b + 1,b = a + 3);
   printf("%d\n",d);
   return 0;
}
//结果:8

//逗号表达式也可用在if语句中
if (a =b + 1, c=a / 2, d > 0)

//又如这个中
 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[] = {1,2,(3,4),5};
  printf("%d\n",sizeof(arr));
  return 0;
}
//(3,4)中是逗号表达式取最后的数即4
//int arr[] = {1,2,4,5};
//4个整形数即4*4 = 16


下表引用,函数调用和结构成员

***

下表引用操作符     []

int arr[10];//创建数组
 arr[9] = 10;//实用下标引用操作符。
// [ ]的两个操作数是arr和9。

***

函数调用操作符        ()

#include 
void test1()
{
   printf("sasade");
}
test2(int x, int y)
{
    return x + y;
}
 int main()
 {
   test1();  //()为函数调用操作符,操作数为test1
   test2(a,b);//操作数为test2,a,b
   return 0;
 }


***

   .              结构体.成员名

   ->          结构体指针->成员名
#include
struct Book
{
   char name[20];
   char id[20];
   int price;
};//注意结构体后需要加“;”
int main()
{
 struct Book b = {"C语言",“021BV922”,55};
 struct Book * pb = &b;
 //为了找到结构体成员
 printf("书名: %s\n", pb->name);
 printf("书号: %s\n", pb->id);
 printf("价钱: %s\n", pb->price);
 
//printf("书名: %s\n", (*pb).name);
//printf("书号: %s\n", (*pb).id);
//printf("价钱: %s\n", (*pb).price);
 
// printf("书名: %s\n", b.name);
// printf("书号: %s\n", b.id);
// printf("价钱: %s\n", b.price);
 return 0;
}

C语言——操作符(总结)_第3张图片

表达式求值

表达式求值的顺序一部分是由操作符的优先级和综合性决定。有些表达式的操作数在求值的过程中可能需要转化为其他类型

一.隐式类型转换 

1.整形提升

整形提升:表达式中的字符和短整型操作数在使用之前被转换为普通整形(转换short,char型)

           //      无符号整形提升(unsigned char),高位补0

实例:

#include
int main()
{
  char a = 3;
  //3:00000000000000000000000000011
  //由于在char型下,只有8个比特位,从后往前截取得a: 00000011
  char b = 127;
  //127:00000000000000000000001111111
  //同上b:01111111
  //正数的原码反码补码相同
  char c = a + b;
  ///3:     00000000000000000000000000011
  //127:    00000000000000000000001111111
  //3+127 : 00000000000000000000010000010
  //c:10000010
  //c整形提升后:11111111111111111111111110000010,这是补码
  //c原码: 10000000000000000000001111110  ———— -126 
  printf("%d\n",c);//打印时得求出原码
  return 0;
}

  注意:内存中存的是补码,内存中数字计算的是补码

             printf("%d\n",c);//打印时得求出原码

  实例

int main()
{
   char a = 0xb6;
   short b = 0xb600;
   int c = 0xb60000000;
   
   if(a = 0xb6)//因为表达式中a是char类型,没达到一个整形大小,所以会整形提升
   {
     printf("a");//而当a整形提升后便不再是原来的值,所以不会打印
   }
   
   if(b = 0xb600)
   {
     printf("0xb600");//与上同理
   }
   
   if(c = 0xb60000000)
   {
     printf("0xb60000000");//由于c本来就是整形,不去提升
   }
   //仅打印c
   return 0;
}
//c
int main()
{
  char a = 1;
  printf("%u\n",suzeof(a));// 1   仅计算a的大小
  printf("%u\n",suzeof(+a));//4    +a表示参与运算,则需进行整形提升
  printf("%u\n",suzeof(-a));//4   同上
  return 0;
}

注意:c只要参与表达式运算就会发生整形提升

2.算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另外一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换

long double

double

float

unsigned long int

long int

unsigned int

int

如果某个操作数的类型在上表中排名较低,那么首先要转换为另外一个操作数的类型后,再执行运算。(向长/精度更高的的转换)

二.操作符属性

复杂操作符的求值有3个影响因素:

   1.操作符的优先级(执行的先后)

   2.操作符的结合性(运算的方向)

   3.是否控制求值顺序(有"&&","||","?:",","  四种)

两个相邻的操作符先执行哪个?

取决于他们的优先级,如果两者的优先级相同,取决于他们的结合性

优先级和结合性表:

(从上到下优先级逐渐降低)

(L-R表示结合性从左向右,R-L表示从右向左,N/A表示无结合性)

C语言——操作符(总结)_第4张图片

 

C语言——操作符(总结)_第5张图片

C语言——操作符(总结)_第6张图片

C语言——操作符(总结)_第7张图片

 

C语言——操作符(总结)_第8张图片

C语言——操作符(总结)_第9张图片

注意:

在我们掌握操作符的属性后,能处理大多数的情况,但是还有一部分表达式是没办法确定唯一计算顺序的

例如:当c = 3时  c + --c     //3+2 = 5  //2+2 = 4

操作符的优先级只能决定自减--的运算在+的运算的前面,但是不能决定+操作符的左操作数的获取在右操作数之前还是之后求值

(如果我们不能通过操作符确定为一的计算路径,这个表达式是有问题的)

————————————————————————

普热希提

你可能感兴趣的:(c语言,c语言,开发语言)