首页 > 其他分享 >C语言的算符优先级

C语言的算符优先级

时间:2024-03-23 15:57:05浏览次数:26  
标签:算符 优先级 int C语言 运算符 ++ 数组 指针

C语言中提供许多算符,比如算术运算、逻辑运算、关系运算等,必须规定它们的优先级,否则将它们放到一起运算肯定要出乱子,正如算术中有先乘除后加减的规则,C语言同样要有确定的运算规则。C语言定义了15个算符优先级,其优先级规则如下:

规则1:优先级高的先运算

规则2:同一个优先级则需要按照结合性确定运算顺序,大部分为从左到右,仅有少数结合性为从右到左。

1 C语言运算符的优先级和结合性列表

优先级 运算符 含义 结合性
1 ( )
[ ]
.
->
圆括号
数组下标 a[N]
结构体成员 对象.成员
结构体指针 对象指针->成员名
从左到右
2 !
~
++
--
-
(类型)
*
&
sizeof
逻辑非
按位取反
自增
自减
负号运算符
强制类型转换
取值, *p表示某指针的内容
取址, &a表示变量a的地址
长度运算
从右到左
3 *
/
%


求余
从左到右
4 +
-

从左到右
5 >>
<<
右移
左移
从左到右
6 <
>
<=
>=
小于
大于
小于等于
大于等于
从左到右
7 ==
!=
等于运算符
不等于运算符
从左到右
8 & 按位余 从左到右
9 ^ 按位异或 从左到右
10 | 按位或 从左到右
11 && 逻辑与 从左到右
12 || 逻辑或 从左到右
13 ? : 条件判断 从右到左
14 =
+=
-=
*=
/=
%=
&=
^=
|=
>>=
<<=
赋值运算符
加后赋值
减后赋值
乘后赋值
除后赋值
取余后赋值
按位与后赋值
按位异或后赋值
按位或后赋值
右移后赋值
左移后赋值
从右到左
15 , 逗号运算符 从左到右

2 C语言容易弄错的算符优先级

此表摘录《C专家编程》

优先级问题 表达式 错误的理解 正确的结果
.的优先级高于*
->操作符用于消除这个问题
*p.f p所指对象的字段 *(p).f 对p取f偏移,作为指针,然后进行解除引用操作*(p.f)
[] 高于* int *ap[] ap是个指向int数组的指针 int (*ap)[] 指针数组 int *(ap[])
==和!=高于位操作运算符 (val & mask != 0) (val & mask) != 0 val & (mask != 0)
==和!= 高于赋值运算符 c = getchar() != EOF (c = getchar()) != EOF c = (getchar() != EOF)
算术运算符高于移位运算符 msb << 4 + lsb (msb << 4) + lsb msb << (4 + lsb)
逗号运算符在所有运算符中优先级最低 i = 1, 2 i = (1, 2) (i = 1), 2

另外补充几个:

优先级问题 表达式 错误的理解 正确的结果
==的优先级高于&& 和 || a && b == c (a && b) == c a && (b == c)
->的优先级高于& &p->offset (&p)->offset &(p>offset)

小结:

完全记住这些优先级有点困难,并且没有必要,可以简单的记一些:

  1. 括号(圆括号,中括号),结构体运算符(. 与 ->)优先级最高
  2. 赋值,逗号运算符优先级最低
  3. 单目运算符(* & 等 )优先级排第2
  4. 算术>移位>关系(比较)> 按位与或>逻辑与或(逻辑非处于第二等级)>赋值
  5. 只有单目运算符,三目运算符,赋值运算符的结合性为从右到左,其它结合性都是从左到右

3 算符优先级有关的几个知识点

3.1 指针数组与数组指针

下标引用[ ]的优先级高于间接访问*

指针数组:int *p[5]

数组指针:int (*p)[5]

指针数组:

本质是数组,只不过是是指针数组,如下例多个指针:

int a = 1;
int b = 2;
int c = 3;
int d = 4;
int *pa = &a;
int *pb = &b;
int *pc = &c;
int *pd = &d;

printf("a = %d b = %d c = %d, d = %d\r\n", *pa, *pb, *pc, *pd);

/* 或者定义指针数组,*p[4]是一个指针数组,数组里面的每个元素都是一个指针 */
int *p[4] = {&a, &b, &c, &d};
for (int i = 0; i < 4; i++) {
    printf("%d ", *p[i]);
}
printf("\r\n");

结果为:

a = 1 b = 2 c = 3, d = 4
1 2 3 4

指针数组多用来存放字符串列表,便于管理

char *str[] = {
    "hello",
    "what's your name",
    "my name is hanmeimei",
    "how are you"
};
for (int i = 0; i < 4; i++) {
    printf("%s \r\n", str[i]); // 因为要打印字符串,所以这里用的是str[i],而非*str[i]
}

结果为:

hello
what's your name
my name is hanmeimei
how are you

数组指针:

本质是一个指针,这个指针指向数组,相当于行指针,一般用来指向二维数组。

int aa[6] = {1, 2, 3, 4, 5, 6};
int *pa = aa;
int (*p)[3] = &aa;

printf("aa = 0x%x, &aa = 0x%x, &aa[0] = 0x%x\r\n", aa, &aa, &aa[0]);
printf("p = 0x%x, *p = 0x%x *(p + 0) = 0x%x *p[0] = 0x%x, pa = 0x%x, *pa = 0x%x\r\n", p, *p, *(p + 0), *p[0], pa, *pa);
p = p + 1;
pa = pa + 1;
printf("p = 0x%x, *p = 0x%x *(p + 0) = 0x%x *p[0] = 0x%x, pa = 0x%x, *pa = 0x%x\r\n", p, *p, *(p + 0), *p[0], pa, *pa);

打印如下:

aa = 0x900fffb0, &aa = 0x900fffb0, &aa[0] = 0x900fffb0
p = 0x900fffb0, *p = 0x900fffb0 *(p + 0) = 0x900fffb0 *p[0] = 0x1, pa = 0x900fffb0, *pa = 0x1
p = 0x900fffbc, *p = 0x900fffbc *(p + 0) = 0x900fffbc *p[0] = 0x4, pa = 0x900fffb4, *pa = 0x2

第一行打印说明:数组的地址和数组首元素的地址数值上相同(但这并不意味着数组的地址和数组首元素的地址是完全相同的)

第二行打印说明:数组指针的解引用为第i行首元素地址,而数组元素指针的解引用为元素值,(但我没有明白*(p + 0)和*p[0]有什么区别?)

第三行打印说明:数组指针指向的是数组的地址(不是元素的地址),数组指针指针指向数组的地址,指针加1相当于跳过当前数组,指向下一个数组。

数组指针和多维数组的关系:

数组 数组指针
二维 int arr[3][4] int (*p)[4]
三维 int arr[3][4][5] int (*p)[4][5]
四维 int arr[3][4][5][6] int (*p)[4][5][6]

如下用数组指针来遍历二维数组:

int aa[3][2] = {1, 2, 3, 4, 5, 6};
int (*p)[2] = aa;
for (int i = 0; i < 6; i++) {
   for (int j = 0; j < 2; j++) {
      printf("%d ", *(*(p + i) + j)); // *(p + i) 为第i行数组指针的解引用,表示第i行首元素地址,
                                      // 所以 *(p + i) + j) 表示第i行第j列元素地址
   }
   printf("\r\n");
}

输出日志为:

1 2
3 4
5 6

3.2 函数指针与指针函数

圆括号的优先级高于*

指针函数:int * fun(int x,int y);
函数指针:int (*fun)(int x,int y);

指针函数:

类似于 int * fun(int x,int y); 这种形式,本质是函数,函数的返回值为指针。

函数指针:

本质是指针变量,这个指针指向函数。

int (*fun)(int x,int y); // 定义

fun = &Function;         // 赋值,以下两种方式均可
fun = Function;

x = (*fun)();            // 调用,以下两种方式均可,建议用1,可以清楚的指明这是通过指针的方式来调用函数
x = fun();

3.2 *p++与(*p)++与*(p++)与*++p与++*p

*的优先级与++相同,这时候需要查看其结合性,其结合性是从右到左

所以:*p++与*(p++)等价

*p++与*(p++) 表示先取*p的值,然后p指针自增,等价于 a = *p; p++;

(*p)++ 表示取*p的值,然后*p的值加1

*++p 等价*(++p),表示p先自增,然后取这个指针位置的元素,等价于 ++p; a = *p

++*p等价于++(*p),表示*p的值加1, 然后取值

参考:

  1. C语言运算符优先级列表(超详细)

  2. C语言常被搞错的运算符优先级

  3. 彻底理解数组指针和指针数组的区别-CSDN博客

  4. 指针的各种用法

  5. 数组指针详解

  6. C语言:数组的地址和数组首元素的地址的区别

标签:算符,优先级,int,C语言,运算符,++,数组,指针
From: https://www.cnblogs.com/sureZ-learning/p/18091207

相关文章

  • 华为路由协议优先级
    名称优先级DIRECT0OSPF10IS-IS15STATIC60RIP100OSPFASE150OSPFNSSA150IBGP255EBGP255......
  • C语言 03 原码 反码 补码
    原码计算机中所有的数字都是使用0和1这样的二进制数来进行表示的。这时如果要存储一个数据,比如十进制的3,那么就需要使用2个二进制位来保存,二进制格式为11,占用两个位置,称为2bit位。一般占用8个bit位表示一个字节(B),2个字节等于1个字,所以一个字表示16个bit位......
  • C语言字符函数和字符串函数及内存函数详解(干货小知识:常用函数的模拟实现)
    文章目录1.字符函数1.1字符分类函数1.2字符转换函数2.字符串函数2.1strlen函数2.1.1strlen函数的使用:2.1.2strlen函数的模拟实现2.2strcpy函数2.2.1strcpy函数的使用2.2.2strcpy函数的模拟实现2.3strcat函数2.3.1strcat函数的使用2.3.2strcat函数的模拟实......
  • PAT乙级 1062 最简分数 C语言
    最简分数一个分数一般写成两个整数相除的形式:N/M,其中M不为0。最简分数是指分子和分母没有公约数的分数表示形式。现给定两个不相等的正分数N1​/M1​和N2​/M2​,要求你按从小到大的顺序列出它们之间分母为K的最简分数。输入格式:输入在一行中按N/M的格式给出两个......
  • PAT乙级 1055 集体照 C语言
    集体照拍集体照时队形很重要,这里对给定的N个人K排的队形设计排队规则如下:每排人数为N/K(向下取整),多出来的人全部站在最后一排;后排所有人的个子都不比前排任何人矮;每排中最高者站中间(中间位置为m/2+1,其中m为该排人数,除法向下取整);每排其他人以中间人为轴,按身高......
  • PAT乙级 1054 求平均值 C语言
    本题的基本要求非常简单:给定N个实数,计算它们的平均值。但复杂的是有些输入数据可能是非法的。一个“合法”的输入是[−1000,1000]区间内的实数,并且最多精确到小数点后2位。当你计算平均值的时候,不能把那些非法的数据算在内。输入格式:输入第一行给出正整数N(≤100)。随......
  • 0基础学习C语言第一章:常量与变量详解
    一、常量定义:在程序运行过程中,其值不能被改变的量称为常量。常用常量有以下几类:1.整型常量十进制整数形式例如:234,-1232.实型(浮点型)常量十进制小数形式:由数字、小数点组成例如:2.345、-23.345指数形式:如:1.23e2(相当于1.23x10²)由于在计算机输入输出时,无法表示上角......
  • 0基础学习C语言第二章:运算符与表达式
    表达式:表达式是c语言的主体,在c语言中,表达式由操作符和操作数组成。简单的表达式可以只有一个操作数。根据操作符的个数,可以将表达式分为简单表达式和复杂表达式,简单的表达式只含有一个操作符(如:5+5),而复杂的表达式则含有两个或者两个以上的操作符(如5+5+6*4);表达式是本身什么事情也......
  • 8.Golang中的运算符-算术运算符、关系运算符、逻辑运算符、赋值运算符
    Golang中的运算符1、Golang内置的运算符算术运算符关系运算符逻辑运算符位运算符赋值运算符2、算数运算符运算符描述+相加-相减*相乘/相除%求余=被除数-(被除数/除数)*除数注意:++(自增)和--(自减)在Go语言中是单独的语句,并不是运算符。pa......
  • 杨辉三角C语言
    杨辉三角输出杨辉三角前10行#include<stdio.h>intmain(){ inta[10][10]; for(inti=0;i<10;i++){ a[i][0]=1; a[i][i]=1; } for(inti=2;i<10;i++) for(intj=1;j<i;j++) a[i][j]=a[i-1][j]+a[i-1][j-1]; for(inti=0;i<10;i++){ for(intj=0......