国庆笔记04运算符和表达式

发布于 2024-10-07  997 次阅读


运算符有以下几种:

算术运算符自增自减运算符关系运算符逻辑运算符条件运算符赋值运算符逗号运算符

算术运算符

+和-,即正号运算符和负号运算符,属于单目运算符,它们的优先级是2,高于二元运算符高,但低于括号和指数运算符

在C语言中,优先级高的运算符先执行

值得注意的是,正负号运算符(+-)的结合性自右向左,这主要是因为它们属于一元运算符这意味着它们只作用于单个操作数,并且它们通常出现在操作数的前面。例如,在负号运算中,-a 只对 a 进行取负操作。这也避免了+-a的出现让编译器身心交瘁的局面,由于一元运算符自右往左运算,最后的结果也只会是-a,同时,对于表达式 - -a,按照右结合性,它被解析为 -( -a ),表示两次取负,而不是 (-)-a,这就避免了语法混淆,更具有合理性。

再就是除法运算符,它主要是在整数和浮点数运算中需要被特别注意

两个整数进行除法时,结果仍然是整数,且小数部分会被截断。这意味着结果将总是整数,int result = 5 / 2; // result == 2

只要有浮点数参与除法运算,结果便是浮点数,且保留小数部分。这意味着float result = 5.0 / 2; // result == 2.5

所以,如果你想得到浮点结果,确保至少有一个操作数是浮点数。否则,结果会是整数


自增自减运算符(已会,跳过


关系运算符(比较关系---记忆)

包含小于、小于或等于、大于、大于或等于、等于(==)、不等于(!=)

关系运算符用于比较运算符两边的表达式的大小关系,运算结果为逻辑值,如果是逻辑真,运算结果为非0值(具体来说,逻辑真通常默认表示为 1但实际上任何非零值都可以代表逻辑真),反之,如果是逻辑假,运算结果为0

还有个强制转换运算符,个人感觉没什么卵用


逻辑运算符

逻辑与&&:必须都真才认亲,不然屁都不是

逻辑或||:一个是真就行了

逻辑非!:和逻辑与、逻辑或的区别就是它是单目运算符且为右结合性(感觉右结合性比较少见,所以写一下)

逻辑非的特殊:当操作数为 (非零)时,结果为 (0);当操作数为 (0)时,结果为 (1)

所以!是个反骨仔,切记


条件运算符

条件运算符是三元运算符,三元运算符需要三个操作数。而且在编程语言中,最常见的三元运算符也就是条件运算符

条件运算符的格式为:表达式1 ?表达式2 :表达式3

eg:int max = (a > b) ? a : b;
//这个代码中如果a>b为真,那么max最终赋值结果为a,否则将赋值结果为b

赋值运算符

第一个就是=

然后是+=、-=与*=、/=

b += a;//b=b+a;
b -= a;//b=b-a;
b *= a;//b=b*a;
b /= a;//b=b/a;

逗号运算符

就是一个,

它会依次计算多个表达式,并返回最后一个表达式的结果,在循环多重赋值时使用,能够让代码更简洁

int x, y, z; x = (y = 2, z = 3, y + z); printf("%d\n", x); // 输出5,因为返回最后一个表达式y + z的结果

在这里,y 被赋值为2,z 被赋值为3,然后返回最后一个表达式 y + z 的值(5)并赋给 x

逗号运算符也常用于for循环的初始化和更新部分,帮助处理多个变量

for (int i = 0, j = 10; i < j; i++, j--) { printf("i=%d, j=%d\n", i, j); }

在这个循环中,i 从0增加到5,而 j 从10减少到5。逗号运算符让我们能够在循环中同时操作 ij 两个变量

值得注意的是,逗号运算符和逗号分隔符是两个概念。虽然两者都是一个,但是逗号分隔符是用于将多个变量、函数参数、数组元素等分隔开,不参与运算

eg:int a, b, c; // 使用逗号分隔符声明三个整型变量

逗号运算符是一种运算符,能够在一条语句中执行多个表达式,返回最后一个表达式的值,它是参与程序逻辑的运算符


表达式的含义以及组成:用运算符(和括号)将运算对象(也叫操作数)连接起来的、符合C语言语法规则、用于相关运算的式子,即称为C语言表达式。运算对象包括常量、变量、函数等

eg:a * b/c-1.5+'a'

和先乘除再加减一个道理,在计算表达式的值时,高优先级先进行运算,同时,你也可以借助小括号来改变运算的优先级

值得注意的是,当float与double类型之间进行混合运算,编译器会全部转换为double类型再来计算

当int和float或者double进行运算,会将int转换为float或者double进行运算

在混合运算中,C语言会自动进行类型转换以保持运算的类型一致性

当你用字符(char类型)进行运算时,实际上是在用其 ASCII 值进行运算

eg:char c = 'A'; // ASCII 值为 65
float f = 5.0;
float result = c + f; // 'A' 将被提升为 65,然后 result = 65 + 5.0 = 70.0

当 char 与其他数值类型(如 int 或 float)进行运算时,结果的类型会取决于参与运算的最宽类型(保大不保小)。比如,如果参与运算的其中一个数是浮点数(如 float),则结果将是浮点数,确保结果的精度未丢失

我感觉char类型不好用,因为正如上面所言,当你用字符进行运算时,实际上是在用其 ASCII 值进行运算。例如,char c = 'B'; 实际上代表的是整数 66。在进行运算时,不要忘记这点


其实,C语言是支持隐式类型转换,这种转换通常被称为“类型提升”或“自动类型转换

隐式类型转换的基本规则如下:

涉及不同类型的表达式时,C语言会自动将较小的类型转换为较大的类型,以避免数据丢失(其实编译器也蛮聪明的(づ ●─● )づ)

这种转换遵循一定的优先级规则

比如整型提升:在表达式中,所有 char 和 short 类型会被提升为 int(如果 int 能表示这些类型的值),否则将被提升为 unsigned int

//很离谱的是,如果真的提升为unsigned int,可能会导致意外的行为,因为无符号整型是不会有负号的,所以尤其是在涉及负数时,当处理无符号和有符号整型的操作时,最好明确考虑逻辑,避免意外结果

以下内容仅供扩展

详细阐述后半句:

有符号整型 通常可以表示正数和负数。例如,int 类型通常可以表示从 -2,147,483,648 到 2,147,483,647(对于32位系统)
无符号整型 只表示非负数,包括零,通常范围为 0 到 4,294,967,295

你可以理解为,无符号整型牺牲了负数来扩大了他的正数的容纳范围

所以在混合运算中,当你在表达式中同时使用了有符号和无符号整型时,编译器会优先考虑无符号类型。这是因为无符号类型的范围比有符号类型宽

//这是什么意思?就是你因为需要使用了unsigned int的同时int类型的数据也参与了混合运算,导致有符号整型被编译器自动转换为无符号整型,这就可能导致逻辑错误

那为什么无符号类型的范围比有符号类型宽?使用无符号类型你是取不到负数的啊,但是有符号类型却可以取到

gpt的回答是无符号类型的范围比有符号类型宽是因为无符号类型不需要存储负数,因此可以将所有位用于正数表示

当你使用无符号类型时,例如unsigned int,所有的位都用于描述增长的数值。这意味着在相同位数下,它可以表示高达两倍于有符号类型的最大值的正数值,但没有负数

#include <stdio.h>

int main() {
int i = -1; // 有符号整型
unsigned int u = 1; // 无符号整型

// 在表达式中,i 将被转换为 unsigned int
if (i < u) {
printf("i is less than u\n");
} else {
printf("i is not less than u\n"); // 输出
}

return 0;
}

其中,i<u本质也是一种运算

在这个示例中,i(int类型,值为 -1)与 u(unsigned int类型,值为 1)进行比较时,i 会被转换为 unsigned int 类型。尽管在表面上,-1 看起来小于 1,但在无符号整型的上下文中(不能理解为什么会这样),转换后的值将会变得非常大,因此,条件将是 false,所以输出else的内容

届ける言葉を今は育ててる
最后更新于 2024-11-05