1. 程式人生 > 其它 >C語言-操作符與表示式

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;
}

  1. 除了 % 操作符之外,其他的幾個操作符可以作用於整數和浮點數。
  2. 對於 / 操作符,如果兩個運算元都為整數,執行整數除法。而只要有浮點數執行的就是浮點數除法。
  3. %操作符的兩個運算元必須為整數,返回的是整除之後的餘數。

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;
}


注意: 一定要保證只有唯一的一個運算順序,不然程式碼就是錯誤的。

結尾

為夢想顛簸的人有很多,不差你一個,但如果你能堅持到最後,那你就是唯一。半山腰太擠了,總得去山頂看看。