C 语言学习(2)---- C语言中的表达式求值

1. 表达式定义

C语言中的表达式是一种有值的语法结构,它由运算符(变量,常量,函数调用返回值)结合而成,每个表达式一定有一个值

常量表达式

比如 a,12,12.4 值就是变量或者常量本身的值,作为条件的时候,非零为真,零值为假

算术表达式

a+b c*d+a 12/3+d i++ --a  值就是表达式的结果

赋值表达式

a=12 a+=12 a = c = d  表示对 a 变量进行赋值

关系表达式

a > b 2 ==3 值可以认为是布尔值,由于C语言中没有bool 值,用整型值 0 和 1 表示

逻辑表达式

a && b c || d  !a 值可以认为是布尔值,由于C语言中没有bool 值,用整型值 0 和 1 表示

复合表达式

x = ( y = (a + b + a > 4), z=10) 依据运算符优先级和结合性得到结果

逗号表达式

(1,2,3,4,a)  从左到右依次求值,表达式的值是逗号最右边的值

有返回值的函数

有返回值的函数也是一个表达式

2. 表达式求值

整型提升

C语言的整数算术运算至少是以缺省的整型类型的精度进行的,为了获得这个精度,表达式中字符型和短整型在使用之前转换为普通整型,这种转换称为整型提升

char a,b,c;

a = b + c

b 和 c 的值被提升为普通整型,然后再执行加法运算,加法运算的结果被截短,然后再存储于 a 中

隐式类型转换

C语言在下面几种情况下进行隐式类型转换:

  1. 算术表达式中,低类型会转换为高类型
  2. 赋值表达式中,右侧表达式的值可以自动转换为左侧变量的类型,赋值给它
  3. 函数调用中参数传递时,系统隐式将实参转换为形参的类型后,赋值给形参
  4. 函数有返回值时,系统隐式将返回表达式类型转换为返回值类型,并赋值给调用函数

表达式求值中的自动类型转换

下面层次体系称为寻常算术转换:

 

转换规则:

  1. 如果某个操作数类型在上面列表中排名较低,那么首先将其转换为另一个操作数的类型然后再执行操作
  2. 转换按照数据长度增加的方向进行,以保证精度不降低,比如 int 型和 long 型运算时,先把int 类型转换为 long 型后再进行计算
  3. 若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型
  4. 所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算
  5. char 和 short 类型参与运算时,必须先转换为 int 类型(整形提升)

注意float 类型转换为整型值的时候,小数部分会被舍弃(并不进行四舍五入

static void _floatconvert() {
	float m = 3.14f;
	int n = m;
	printf("the value of n = %d \n", n);
}

3. 操作符的属性

​​​​​​复杂表达式的求值顺序是由三个因素决定的,操作符的优先级,操作符的结合性以及操作符是否控制执行顺序。

两个相邻的操作符哪个先执行取决于它们的优先级,如果两者优先级相同,那么执行顺序由它们的结合性决定

简单来说,结合性就是一串操作符是从到右依次执行还是从右到左依次执行

  • 初级运算符总共有四个下标访问操作符[ ],括号操作符(),访问结构成员 .,访问结构指针成员 ->,
  •  算术运算符先乘除后加减
  • 关系运算符中先大小后相等(关系运算符中 > < >= <= 的优先级高于 == 和 ! =
  • 位运算分为四个等级,取反(等级最高是单目运算符),与,异或,或
  • 逻辑运算符分为三个等级,逻辑非(等级最高是单目运算符),逻辑与,逻辑或

运算符中只有三类是从右到左,其余都是从左到右

赋值,条件(?:)和单目运算符 这三类运算符的结合方式是从右到左,其余都是从左到右

常见的优先级问题:

  •  结构体成员访问运算符的优先级高于间接访问 *p.f 等同于*(p.f),使用访问结构体成员运算符

p -> f 可以避免这个问题

  • 下标访问运算符优先级高于间接访问 int *ap[ ],表示的是一个指针数组
  • 函数调用优先级高于间接访问,int *p(),表示返回值是指针的函数 p
  • == 和 != 优先级高于位操作  value & value != 2 等同于value & (value != 2)
  • == 和 != 优先级高于赋值运算符,c = getchar() != EOF 等同于 c = (getchar() != EOF)
  • 算术运算符优先级高于位移运算符,msb << 4 + lsb 等同于msb << (4 + lsb)
  • 逗号运算符的优先级最低
  • 间接访问运算符优先级高于算术运算符,*p + 1 表示的是 间接访问 p 的值加1,*(p + 1)表示的是访问 p 指向元素连续内存的下一个元素
void _testOperatorPriority() {

	int array[] = { 10, 20, 30, 40 };
	int *p = array;

	//  11
	printf("*p + 1 = %d \n", *p + 1);

	// 20
	printf("*(p + 1) = %d \n", *(p + 1));

	// *p++
	printf("*p++ = %d %d %d\n", *p++, *p++, *p++);

}
  • 26
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
后缀表达式也称为逆波兰表达式,它是一种不包含括号的算术表达式。后缀表达式的运算符在后面,每个运算符的操作数都在它前面。例如,后缀表达式 "3 4 +" 等价于表达式 "3 + 4"。 后缀表达式求值可以使用栈来实现。具体步骤如下: 1. 从左到右扫描后缀表达式。 2. 如果是操作数,将其压入栈。 3. 如果是运算符,弹出栈顶的两个操作数,进行运算,并将结果压入栈。 4. 重复步骤 2 和步骤 3,直到表达式的最右端。 5. 最后,栈只剩下一个元素,即为表达式。 以下是使用 C 语言实现后缀表达式求值的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define MAX_STACK_SIZE 100 typedef struct { int top; int stack[MAX_STACK_SIZE]; } Stack; void push(Stack *s, int data) { if (s->top >= MAX_STACK_SIZE) { printf("Stack overflow\n"); exit(EXIT_FAILURE); } s->stack[++s->top] = data; } int pop(Stack *s) { if (s->top < 0) { printf("Stack underflow\n"); exit(EXIT_FAILURE); } return s->stack[s->top--]; } int evaluatePostfix(char *expr) { Stack s; s.top = -1; int i, op1, op2, result; for (i = 0; expr[i] != '\0'; i++) { if (isdigit(expr[i])) { push(&s, expr[i] - '0'); } else { op2 = pop(&s); op1 = pop(&s); switch (expr[i]) { case '+': result = op1 + op2; break; case '-': result = op1 - op2; break; case '*': result = op1 * op2; break; case '/': if (op2 == 0) { printf("Division by zero\n"); exit(EXIT_FAILURE); } result = op1 / op2; break; default: printf("Invalid operator\n"); exit(EXIT_FAILURE); } push(&s, result); } } result = pop(&s); if (s.top >= 0) { printf("Invalid expression\n"); exit(EXIT_FAILURE); } return result; } int main() { char expr[MAX_STACK_SIZE]; printf("Enter postfix expression: "); fgets(expr, MAX_STACK_SIZE, stdin); int result = evaluatePostfix(expr); printf("Result = %d\n", result); return 0; } ``` 在这个示例,我们使用了一个 `Stack` 结构体来实现栈的功能。`push` 函数用于将元素压入栈,`pop` 函数用于弹出栈顶元素。`evaluatePostfix` 函数用于计算后缀表达式。在函数,我们遍历后缀表达式的每个字符,如果是数字,就将其转化为整数并压入栈;如果是运算符,就弹出栈顶的两个操作数进行运算,并将结果压入栈;最后,弹出栈顶元素作为表达式,并检查栈是否为空。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值