Ⅰ關(guān)系操作符
- 在 C 語(yǔ)言中,使用關(guān)系操作符來(lái)判斷兩個(gè)數(shù)之間的大小關(guān)系。
- 關(guān)系運(yùn)算符都是雙目運(yùn)算符,其結(jié)合性均為從左到右。
- 關(guān)系運(yùn)算符的優(yōu)先級(jí)低于算術(shù)運(yùn)算符,高于賦值運(yùn)算符。
Ⅱ 邏輯操作符
- 邏輯運(yùn)算符獲得的是一個(gè)邏輯值,邏輯值只有 “ 真 ” 或 “ 假 ”兩種狀態(tài)。
運(yùn)算符 | 含義 | 優(yōu)先級(jí) | 舉例 | 說(shuō)明 |
---|---|---|---|---|
! | 邏輯反 | 高 | !a | 如果 a 為真,則 !a 為假;如果 a 為假,則 !a 為真。 |
&& | 邏輯與 | 中 | a && b | 只有 a 和 b 同時(shí)為真,結(jié)果才為真;a 和 b 只要有一個(gè)是假的,則結(jié)果為假。 |
|| | 邏輯或 | 低 | a || b | 只要 a 或 b 中有一個(gè)為真,則結(jié)果為真;a 和 b 同時(shí)為假,結(jié)果采薇假。 |
⒈操作符介紹
1. “ ! ” 邏輯反
- 邏輯反操作符在單目操作符那塊講過(guò)了,這里就不過(guò)多贅述。
2. “ && ” 邏輯與
- 全真則真。
- 只有 a 和 b 同時(shí)為真,整個(gè)表達(dá)式的結(jié)果才為真。
3. “ || ” 邏輯或
- 全假則假。
- a “ 或 ” b ,兩個(gè)只要有一個(gè)是真的,表達(dá)式結(jié)果則為真,a 和 b 全是假的表達(dá)式結(jié)果才是假的。
⒉短路求值
- 短路求職又稱最小化求值,是一種邏輯運(yùn)算符的求值策略。
- 只有當(dāng)?shù)谝粋€(gè)運(yùn)算數(shù)的值無(wú)法確定邏輯運(yùn)算的結(jié)果時(shí),才對(duì)第二個(gè)運(yùn)算數(shù)進(jìn)行求值。
先說(shuō)結(jié)論
- &&:左邊為假,右邊就不計(jì)算了。
- | | :左邊為真,右邊就不計(jì)算了。
舉個(gè)栗子
- 下面代碼 a b c d 的結(jié)果分別是多少?
#include <stdio.h>
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;
}~~刪除線格式~~
- 對(duì) a 采用的是后置++,所以是先拿 a = 0 的值進(jìn)行邏輯運(yùn)算,而邏輯與一旦看到這個(gè) 0 后面不管有再多的表達(dá)式都不會(huì)去運(yùn)算了,因?yàn)榈谝粋€(gè)都是 0 了,整個(gè)表達(dá)式的結(jié)果肯定是 0。
- 然后再對(duì) a 進(jìn)行 +1。
再看個(gè)栗子
- 下面代碼的 a b c d 的結(jié)果分別是多少?
#include <stdio.h>
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;
}
- 第一個(gè)運(yùn)算數(shù)是 a++,先拿 a = 0 去進(jìn)行邏輯或判斷,無(wú)法確定邏輯運(yùn)算的結(jié)果,對(duì)第二個(gè)運(yùn)算數(shù) ++b 進(jìn)行值。
- ++b 是前置 ++,b 的值變?yōu)?3 ,則第二個(gè)邏輯或的左邊為真,根據(jù)短路求值的原則,右邊的 d++ 無(wú)須再進(jìn)行計(jì)算。
Ⅲ 條件操作符
- 有一個(gè)操作數(shù)的操作符稱為單目操作符,有兩個(gè)操作數(shù)的操作符稱為雙目操作符,C 語(yǔ)言中還有唯一的一個(gè)有三個(gè)操作數(shù)的三目操作符,它的作用是提供一種簡(jiǎn)寫的方式來(lái)表示 if-else 語(yǔ)句。
- 這個(gè)三目操作符的語(yǔ)法格式為:
表達(dá)式1 ? 表達(dá)式2 : 表達(dá)式3;
-
表達(dá)式 1 是條件表達(dá)式,如果結(jié)果為真,則返回表達(dá)式 2;如果為假,則返回表達(dá)式 3。
-
例如:求兩個(gè)數(shù)中得較大值。
if(a > b)
{
max = a;
}
else
{
max = b;
}
- 可以簡(jiǎn)寫成:
max = a > b ? a : b;
//a > b 嗎?,大于則返回 a,否則返回 b
Ⅳ 逗號(hào)表達(dá)式
語(yǔ)法格式
表達(dá)式1, 表達(dá)式2, 表達(dá)式3, …,表達(dá)式N
逗號(hào)表達(dá)式的運(yùn)算過(guò)程
- 從左往右逐個(gè)計(jì)算表達(dá)式。逗號(hào)表達(dá)式作為一個(gè)整體,它的值為最后一個(gè)表達(dá)式(即表達(dá)式n)的值。
舉個(gè)栗子
再舉個(gè)栗子
a = (b = 3, (c = b + 4) + 5)
- 先將變量 b 賦值為 3,然后變量 c 賦值為 b + 4 的和,也就是 7,接下來(lái)把 c 的值加上 5,賦值給變量 a,得到變量 a 的值就是 12。
- 逗號(hào)運(yùn)算符的優(yōu)先級(jí)是最低的,雖然 c = b + 4 用優(yōu)先級(jí)最高的小括號(hào)運(yùn)算符括起來(lái),但只要在逗號(hào)表達(dá)式內(nèi),都應(yīng)該從左到右依次執(zhí)行每個(gè)表達(dá)式。
逗號(hào)表達(dá)式注意事項(xiàng)
- 在 C 語(yǔ)言中看到逗號(hào),不一定就是逗號(hào)表達(dá)式,因?yàn)?mark>在有些時(shí)候,逗號(hào)僅僅是被用作分隔符而已。
- int a, b, c;
- scanf(“%d %d %d”,&a, &b, &c);
- 這里的逗號(hào)都是作為分隔符使用,而不是運(yùn)算符。
Ⅴ 下標(biāo)引用、函數(shù)調(diào)用和結(jié)構(gòu)成員
⒈[ ] 下標(biāo)引用操作符
- 操作數(shù):一個(gè)數(shù)組名 + 一個(gè)索引值。
int arr[10];//創(chuàng)建數(shù)組
arr[9] = 10;//實(shí)用下標(biāo)引用操作符。
- 的兩個(gè)操作數(shù)是arr和9。
⒉( ) 函數(shù)調(diào)用操作符
接收一個(gè)或者多個(gè)操作數(shù)
- 第一個(gè)操作數(shù)是函數(shù)名;
- 剩余的操作數(shù)就是傳遞給函數(shù)的參數(shù)。
//函數(shù)定義
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 10;
int b = 20;
//函數(shù)調(diào)用
int c = Add(a, b);//這里的小括號(hào) () 就是函數(shù)調(diào)用操作符
// () 的操作數(shù)為:Add,a,b
return 0;
}
- 函數(shù)調(diào)用的操作數(shù)至少有一個(gè)(函數(shù)名),可以沒(méi)有參數(shù)。
⒊結(jié)構(gòu)體成員訪問(wèn)操作符
操作符 | 語(yǔ)法格式 |
---|---|
. | 結(jié)構(gòu)體 . 成員名 |
-> | 結(jié)構(gòu)體指針 -> 成員名 |
1. “ . ” 操作符
#include <stdio.h>
//創(chuàng)建結(jié)構(gòu)體類型
struct student
{
char name[10];
int age;
};
int main()
{
//根據(jù)定義的結(jié)構(gòu)體類型創(chuàng)建結(jié)構(gòu)體變量并初始化
struct student s1 = { "張三",18 };
//訪問(wèn)結(jié)構(gòu)體成員(結(jié)構(gòu)體變量 . 成員變量)
printf("名字:%s 年齡:%d\n", s1.name, s1.age);
return 0;
}
2. “ -> ” 操作符
#include <stdio.h>
//創(chuàng)建結(jié)構(gòu)體
struct student
{
char name[10];
int age;
};
int main()
{
struct student s2 = { "張三",18 };
//創(chuàng)建結(jié)構(gòu)體指針變量 讓其指向s2
struct student* ps = &s2;
// 用結(jié)構(gòu)體指針訪問(wèn)成員(->)
printf("名字:%s 年齡:%d\n", ps->name, ps->age);
return 0;
}
Ⅵ 表達(dá)式求值
表達(dá)式的定義
- 用操作符和括號(hào)將操作數(shù)連接起來(lái)的式子,稱為表達(dá)式。
- 下面是幾個(gè)表達(dá)式的例子:
- 1 + 1
- 'a' + 'b'
- a + b
- a + 'b' + pow(a,b) * 3 / 4 + 5
- 表達(dá)式可以很簡(jiǎn)單(像1+1),也可以很復(fù)雜(像a + ‘b’ + pow(a,b) * 3 / 4 + 5)。那么涉及復(fù)雜的表達(dá)式,就需要討論計(jì)算的夏侯順序問(wèn)題了。
表達(dá)式的求值順序
- 表達(dá)式求值的順序一部分是由操作符的優(yōu)先級(jí)和結(jié)合性決定。
- 優(yōu)先級(jí):2 + 6 / 3,這里的優(yōu)先級(jí)就是先算除法再算加法。
- 結(jié)合性:b = 2 + 3 + 4,優(yōu)先級(jí)相同時(shí),一個(gè)表達(dá)式中該先算誰(shuí)就看結(jié)合性了,+ 號(hào)的結(jié)合性是從左到右,也就是說(shuō)先算 2 + 3 再算 5 + 4。
- 有了優(yōu)先級(jí)和結(jié)合性之后就能大概確定表達(dá)式的計(jì)算路徑。
- 同樣 ,有些表達(dá)式的操作數(shù)在求值的過(guò)程中可能需要轉(zhuǎn)換為其他類型。
⒈隱式類型轉(zhuǎn)換(整型提升)
- C 的整型算術(shù)運(yùn)算總是至少以默認(rèn)整型類型的精度來(lái)進(jìn)行的。
- 為了獲得這個(gè)精度,表達(dá)式中的字符和短整型操作數(shù)在使用之前被轉(zhuǎn)換為普通整型,這種轉(zhuǎn)換稱為整型提升。
- 只要是放在表達(dá)式中的字符和短整型,在使用時(shí)就會(huì)進(jìn)行整型提升。
整型提升的意義
- 表達(dá)式的整型運(yùn)算要在 CPU 的相應(yīng)運(yùn)算器件內(nèi)執(zhí)行,CPU 內(nèi)整型運(yùn)算器(ALU)的操作數(shù)的字節(jié)長(zhǎng)度一般就是 int 的字節(jié)長(zhǎng)度,同時(shí)也是 CPU 的通用寄存器的長(zhǎng)度。
- 因此,即使兩個(gè) char 類型的相加,在 CPU 執(zhí)行時(shí)實(shí)際上也要先轉(zhuǎn)換為 CPU 內(nèi)整型操作數(shù)的標(biāo)準(zhǔn)長(zhǎng)度。
- 通用 CPU 是難以直接實(shí)現(xiàn)兩個(gè) 8 比特字節(jié)直接相加運(yùn)算(雖然機(jī)器指令中可能有這種字節(jié)相加指令)。
- 所以,表達(dá)式中各種長(zhǎng)度可能小于int長(zhǎng)度的整型值,都必須先轉(zhuǎn)換為 int 或 unsigned int,然后才能送入 CPU 去執(zhí)行運(yùn)算。
為啥下面代碼的結(jié)果會(huì)是 -125?
- a 和 b 是 char 類型的數(shù)據(jù),在運(yùn)算之前默認(rèn)將它們轉(zhuǎn)換成整型然后再參與運(yùn)算。
- 又因?yàn)?a 和 b 是 char 達(dá)不到整型的大小(4字節(jié)),所以會(huì)將 a 和 b 進(jìn)行整型提升。
- 加法運(yùn)算完成之后,結(jié)果將被截?cái)?,然后再存?chǔ)于 a 中。
如何進(jìn)行整型提升?
整形提升是按照變量的數(shù)據(jù)類型的符號(hào)位來(lái)提升的
- 負(fù)數(shù)的整型提升,字有點(diǎn)多,講解放到代碼框里。
char c1 = -1;//-1 是整數(shù),32 個(gè)比特位
- -1 的補(bǔ)碼是 1111 1111 1111 1111 1111 1111 1111 1111
- 將結(jié)果往 c1 存的時(shí)候因?yàn)?c1 是 char 放不下這么多比特位,于是就發(fā)生了截?cái)?- 將最后 8 個(gè)比特位截了下來(lái)放到變量 c1 里面去,c1 里存的是 1111 1111
- 現(xiàn)在要對(duì) c1 進(jìn)行整型提升,c1 的類型是 char ,意味著 c1 是個(gè)有符號(hào) char,
- 所以會(huì)將在 c1 中存儲(chǔ)的二進(jìn)制序列 1111 1111 里最高位的那個(gè) 1 解讀為符號(hào)位
- 符號(hào)位是 1 表示它是負(fù)數(shù),對(duì) c1 進(jìn)行整型提升就會(huì)在高位補(bǔ)原符號(hào)位的 1
- 提升之后的結(jié)果為 1111 1111 1111 1111 1111 1111 1111 1111 1111
- 正數(shù)的整型提升
char c2 = 1;
- 變量c2的二進(jìn)制位(補(bǔ)碼)中只有8個(gè)比特位:0000 0001
- 因?yàn)?char 為有符號(hào)的 char,最高位又是個(gè) 0
- 所以整形提升的時(shí)候,高位補(bǔ)充符號(hào)位,即為 0
- 提升之后的結(jié)果是:0000 0000 0000 0000 0000 0000 0000 0001
解析之前的代碼
- 將 5 的二進(jìn)制補(bǔ)碼最后 8 位截?cái)啵缓筚x給 a;
- a 里存放的補(bǔ)碼為 0000 0101
- 將 126 的二進(jìn)制補(bǔ)碼最后 8 截?cái)啵缓筚x給 b;
- b 里存放的補(bǔ)碼為 0111 1110
- 現(xiàn)在要將 a 和 b 里存的補(bǔ)碼進(jìn)行相加,但是 a 和 b 達(dá)不到整型,所以進(jìn)行整型提升
- a 符號(hào)位為 0,整型提升高位補(bǔ) 0,結(jié)果為 0000 0000 0000 0000 0000 0000 0000 0101
- b 符號(hào)為為 0,整型提升高位補(bǔ) 0,結(jié)果為 0000 0000 0000 0000 0000 0000 0111 1110
- 現(xiàn)再將 a 和 b 提升后的結(jié)果相加,結(jié)果為 0000 0000 0000 0000 0000 0000 1000 0011
- 將結(jié)果賦給 c,c 是 char 存不下這么多比特位,進(jìn)行截?cái)?,?1000 0011 賦給 c
- 因?yàn)橐蛴?c,所以對(duì) c 進(jìn)行整型提升,去看 c 的類型,C 是 char ,說(shuō)明最高位的 1 為符號(hào)為符號(hào)位,高位補(bǔ) 1
- c 的補(bǔ)碼為 1111 1111 1111 1111 1111 1111 1000 0011
- 將結(jié)果轉(zhuǎn)成原碼然后進(jìn)行打??;
- c 的原碼為 1000 0000 0000 0000 0000 0000 0111 1101
- 所以 -125 就是這么來(lái)的
整型提升的例子
//實(shí)例1
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if (0xb6 == a)
{
printf("a");
}
if (0xb600 == b)
{
printf("b");
}
if (0xb6000000 == c)
{
printf("c");
}
return 0;
}
c
- 實(shí)例 1 中的 a,b 因?yàn)楹团袛嗖僮骱徒Y(jié)合起來(lái)又達(dá)不到整形,所以都要進(jìn)行整形提升,但是 c 不需要整形提升;
- a,b 整形提升之后變成了負(fù)數(shù),所以表達(dá)式 a == 0xb6,b == 0xb600 的結(jié)果是假;
- 但是 c 不發(fā)生整形提升,則表達(dá)式 c == 0xb6000000 的結(jié)果是真。
//實(shí)例2
int main()
{
char c = 1;
printf("%u\n", sizeof(c));
printf("%u\n", sizeof(+c));
printf("%u\n", sizeof(-c));
return 0;
}
- 實(shí)例2中的 c 只要參與表達(dá)式運(yùn)算,就會(huì)發(fā)生整形提升,表達(dá)式 +c 就會(huì)發(fā)生提升,所以 sizeof(+c) 是 4 個(gè)字
節(jié); - 表達(dá)式 -c 也會(huì)發(fā)生整形提升,所以 sizeof(-c) 是 4 個(gè)字節(jié);
- 但是 sizeof( c ) 中的 c 并沒(méi)有參與計(jì)算,無(wú)法整型提升,所以就是 1 個(gè)字節(jié)。
⒉算術(shù)轉(zhuǎn)換
算術(shù)轉(zhuǎn)換定義
- 大小小于整型的類型在計(jì)算的時(shí)候要進(jìn)行整型提升,而大于整型的類型在計(jì)算時(shí)也會(huì)進(jìn)行轉(zhuǎn)換,這種轉(zhuǎn)換稱之為算術(shù)轉(zhuǎn)換。
- 如果某個(gè)操作符的各個(gè)操作數(shù)屬于不同的類型,那么除非其中一個(gè)操作數(shù)轉(zhuǎn)換為另一個(gè)操作數(shù)的類型,否則操作就無(wú)法進(jìn)行,下面的層次體系稱為尋常算術(shù)轉(zhuǎn)換。
- long double
- double
- float
- unsigned long int
- long int
- unsigned int
- int
- 如果某個(gè)操作數(shù)的類型在上面這個(gè)列表中排名較低,那么首先要轉(zhuǎn)換成另外一個(gè)操作數(shù)的類型后執(zhí)行運(yùn)算。
- 例如:一個(gè) float 類型的數(shù)據(jù)和一個(gè) int 類型的數(shù)據(jù)遇到的時(shí)候,會(huì)將 int 類型的數(shù)據(jù)轉(zhuǎn)換為 float 類型。
合理進(jìn)行算術(shù)轉(zhuǎn)換
- 算術(shù)轉(zhuǎn)換需要合理進(jìn)行,不然就會(huì)有一些潛在的問(wèn)題。
float f = 3.14;
int num = f;//隱式轉(zhuǎn)換,會(huì)有精度丟失
⒊操作符的屬性
復(fù)雜表達(dá)式的求值有三個(gè)影響的因素
- 操作符的優(yōu)先級(jí)。
- 操作符的結(jié)合性。
- 是否控制求值順序。
- 兩個(gè)相鄰的操作符先執(zhí)行哪個(gè),取決于他們的優(yōu)先級(jí)。如果兩者的優(yōu)先級(jí)相同,取決于他們的結(jié)合性。
運(yùn)算符的優(yōu)先級(jí)和結(jié)合性表文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-568337.html
- 操作符的優(yōu)先級(jí)自上而下,從高到低。
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-568337.html
到了這里,關(guān)于【C語(yǔ)言初階(16)】操作符2的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!