C语言运算符的优先级
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
二、二维数组元素的地址
为了说明问题,我们定义以下二维数组:int a[3][4]={{0,1,2,3}, {4,5,6,7}, {8,9,10,11}};
二维数 a 也可这样来理解:数组 a 由三个元素组成:a[0],a[1],a[2],而每个元素又是一个一维数组,且都含
有 4 个元素(相当于 4 列)。如图所示:
/**************建立一个有 cnt 个结点的链表,返回链表头****************/ STUDENT_LINK *link_creat(int cnt) {
STUDENT_LINK *head = NULL; /* head 始终指向链表头,用于返回 */ STUDENT_LINK *new_node; /* new_node 始终指向新申请的节点 */ STUDENT_LINK *cur_node; /* cur_node 始终指向当前操作的(也是最后的)节点 */ int n = 1;
<< 5
>>
左移 右移
变量<<表达式 变量>>表达式
|= 按位或后赋值 变量|=表达式
左到右
15
,
逗号运算符 表达式,表达式,… 左到右
>
大于
表达式>表达式
>= 6
<
大于等于 小于
表达式>=表达式 表达式<表达式
左到右
<=
小于等于
表达式<=表达式
1
数组和指针
一、指向一维数组元素的指针
int a[10], *p; p=&a[0]; /* 与语句 p=a; 等价 */ 此时 p 指向数组中的第 0 号元素,即 a[0],*p 就是*a,就是 a[0]的值,*(a+i)就是 a[i]的值。由于数组元素在 内存中是连续存放的,根据地址运算规则,p+i 和 a+i 都表示为 a[i]的地址(即&a[i])。
运算符及其优先级
优先级 运算符 名称或含义
使用形式
结合方向 优先级 运算符 名称或含义
使用形式 结合方向
[]
数组下标
数组名[常量表达式]
==
7
()
圆括号
(表达式)/函数名(形参表)
!=
1
左到右
. 成员选择(对象)
wenku.baidu.com
对象.成员名
8
&
等于 不等于 按位与
表达式==表达式 左到右
表达式!= 表达式
表达式&表达式 左到右
-> 成员选择(指针) 对象指针->成员名
9
^
按位异或
表达式^表达式 左到右
-
负号运算符
-表达式
10
|
按位或
表达式|表达式 左到右
(类型) 强制类型转换
(数据类型)表达式
11 &&
逻辑与
表达式&&表达式 左到右
++
自增运算符
++变量名/变量名++
12 ||
逻辑或
表达式||表达式 左到右
--
自减运算符
5) 最后用 va_end 宏结束可变参数的获取。
下面的例子可以进一步加深对可变参数的理解,该函数的效果与 sprintf 函数完全相同: void my_printf(char *buffer, const char *format, ...) { va_list arg_ptr;
va_start(arg_ptr, format); vsprintf(buffer, format, arg_ptr); /* 将 arg_ptr 按 format 格式打印到 buffer 中 */ va_end(arg_ptr); }
while (n <= cnt)
{
printf("您正在创建节点%d:\n", n);
new_node = (STUDENT_LINK *)malloc(sizeof(STUDENT_LINK));
link_input(new_node);
if (n == 1) /* 判断是否为第一个结点,若是第 1 个结点则将 head 指向新节点 */
while(*nm!=0) printf("%s\n",*nm++);
}
3
可变参数的函数
下面是一个简单的可变参数的函数,该函数至少有一个整数参数,第二个参数也是整数,是可选的。 #include <stdarg.h> void simple_va_fun(int i, ...) { va_list arg_ptr; int j = 0;
|___|___|___|___|
| a[2] | ---- | 8 | 9 | 10| 11| ------> (0x1020)
|______|
|___|___|___|___|
但从二维数组的角度来看,a 代表二维数组的首地址,当然也可看成是二维数组第 0 行的首地址,a+1 就代表第
1 行的首地址,依次。如果此二维数组的首地址为 0x1000,由于第 0 行有 4 个整型元素,所以 a+1 为 0x1010。
typedef int (*T_MY_FUNC)(int ID);/* 此时”T_MY_FUNC fptr;”等价于”int (*fptr)(int ID);” */ 可以采用下面的形式把函数的地址赋值给函数指针:
fptr=&Function; /* 或用“fptr=Function;” */ 可以采用下面的形式通过指针来调用函数:
2
*
取值运算符
--变量名/变量名--
13 ?:
右到左
*指针变量
=
条件运算符 赋值运算符
表达式 1? 表达式 2: 右到左
表达式 3
变量=表达式
& 取地址运算符
&变量名
/=
除后赋值
变量/=表达式
! 逻辑非运算符
!表达式
*=
乘后赋值
变量*=表达式
~ 按位取反运算符
~表达式
%=
取模后赋值
变量%=表达式
sizeof 长度运算符
{
head = new_node;
}
else
/* 若不是第 1 个结点则将最后的节点的 next 指向新节点 */
{
cur_node->next = new_node;
}
cur_node = new_node; /* 让 cur_node 始终指向当前的(也是最后的)节点 */
cur_node->next = NULL; /* 不要忘记让最后的节点的 next 指向 NULL */
二、函数指针
指向函数的指针包含了函数的地址,可以通过它来调用函数。 格式: 类型说明符 (*函数名)(参数) 例如: int (*fptr)(int ID); 其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明笔 削和它指向函数的声明保持一致。指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就 变成了一个返回整型指针的函数的原型声明。 可以采用下面的形式定义函数指针数据类型:
______
_______________
a ---- | a[0] | ---- | 0 | 1 | 2 | 3 | ------> (0x1000)
|______|
|___|___|___|___|
| a[1] | ---- | 4 | 5 | 6 | 7 | ------> (0x1010)
|______|
既然我们把 a[0],a[1],a[2]看成是一维数组名,可以认为它们分别代表它们所对应的数组的首地址,也就是
讲 a[0]代表第 0 行中第 0 列元素的地址,即&a[0][0],a[1]是第 1 行中第 0 列元素的地址,即&a[1][0],根据地址
运算规则,a[0]+1 即代表第 0 行第 1 列元素的地址,即&a[0][1],一般而言,a[i]+j 即代表第 i 行第 j 列元素的地
格式: 类型标识 *数组名[整型常量表达式]; 例如: int *a[10]; 以上指针数组中包含 10 个指针变量 a[0],a[1],a[2],...,a[9],可以指向 10 个不同的地址。
2
指针函数和函数指针
一、指针函数
指针函数是指声明其返回值为一个指针的函数,实际上就是返回一个地址给调用函数。 格式: 类型说明符 *函数名(参数) 例如: void *GetDate(int ID);
1) #include <stdarg.h>
2) 在函数里定义一个 va_list 型的变量,这里是 arg_ptr,这个变量是指向参数的指针。
3) 用 va_start 宏初始化变量 arg_ptr,该宏的第二个参数是第一个可变参数的前一参数,是一固定的参数。
4) 用 va_arg 返回可变的参数,并赋值给 j。va_arg 的第二个参数是要返回的参数的类型,这里是 int 型。
址,即&a[i][j]。
另外,在二维数组中我们还可用指针的形式来表示各元素的地址,如 a[0]与*(a+0)等价,a[i]与*(a+i)等价,
它表示数组元素 a[i]的地址&a[i][0]。
而二维数组元素 a[i][j]可表示成*(a[i]+j)或*(*(a+i)+j),或者写成(*(a+i))[j]。
四、指向指针数组的指针
指针的指针另一用法是处理指针数组。有些程序员喜欢用指针数组来代替多维数组,一个常见的用法就是处理字 符串。
char *Names[]= {
"Bill", "Sam", "Jim", 0 };
main()
{
char **nm=Names;
/* 定义一个指向指针数组的指针的指针 */
/
除
sizeof(表达式) 表达式/表达式
+= 14 -=
加后赋值 减后赋值
变量+=表达式 变量-=表达式
右到左
3
*
乘
表达式*表达式
左到右
<<=
左移后赋值
变量<<=表达式
%
余数(取模) 整型表达式/整型表达式
>>=
右移后赋值
变量>>=表达式
+
加
4
-
减
表达式+表达式 表达式-表达式
左到右
&= 按位与后赋值 变量&=表达式 ^= 按位异或后赋值 变量^=表达式
单元起存放该位域。也可以有意使某位域从下一单元开始。
4
2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过 8 位二进位。 3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。
链表
typedef struct student {
int number; int score; struct student *next; } STUDENT_LINK;
好指向二维数组的第 1 行。和二维数组元素地址计算的规则一样,*p+1 指向 a[0][1],*(p+i)+j 则指向数组元素
a[i][j]。
四、指针数组
因为指针是变量,因此可设想用指向同一数据类型的指针来构成一个数组,这就是指针数组。数组中的每个元素 都是指针变量,根据数组的定义,指针数组中每个元素都为指向同一数据类型的指针。
三、指向一个由 n 个元素所组成的数组指针
数组指针用的比较少,但在处理二维数组时,还是很方便的。例如:
int (*p)[4];
/* 在数组指针的定义中,圆括号是不能少的,否则它是指针数组 */
int a[3][4];
p=a;
开始时 p 指向二维数组第 0 行,当进行 p+1 运算时,根据地址运算规则,此时放大因子为 4x4=16,所以此时正
va_start(arg_ptr, i);
/* va 在这里是可变参数(variable-argument)的意思 */
j=va_arg(arg_ptr, int);
va_end(arg_ptr);
printf("%d %d\n", i, j);
return;
}
从这个函数的实现可以看到,使用可变参数应该有以下步骤:
位域的使用
位域的定义和位域变量的说明与结构定义相仿,其形式例如为: struct bs { int a:8; int b:2; int :2 /* 无位域名,该 2bit 不能使用 */ int c:4; };
对于位域的定义尚有以下几点说明: 1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一
(*fptr)(ID); /* 或用“fptr(ID); ”的格式,使用这种调用格式看上去与调用普通函数无异,因此使 用前一种调用格式可以明确指出是通过指针而非函数名来调用函数的。*/
三、指针的指针
指针的指针用于指向指针的地址,它的声明有两个星号。例如:char **cp; 如果有三个星号,那就是指针的指针的指针,有四个星号那就是指针的指针的指针的指针,依次类推。
n++;
}
return(head); }
/**********删除链表中 number 字段为 num 的结点,并返回链表头***************/ STUDENT_LINK *link_delete(STUDENT_LINK *head, int num) {
STUDENT_LINK *cur_node; /* cur_node 始终指向当前操作的节点 */ STUDENT_LINK *pre_node; /* pre_node 始终指向当前操作的节点的上一个节点 */