初识C语言之操作符详解(下)
一.操作符分类
1.下标访问操作符
(1) 运用规则:一个数组名+一个索引名(下标)
(2) 运用举例:eg.
int main ( )
{
int arr [10]={1,2,3,4,5};
printf("%d",arr[4]);//数组下标为4的元素→5
return 0;
}
(3) 总结:上述下标访问操作符的操作数为arr和4,(数组名和数组的索引/下标)。
2.函数调用操作符
(1) 函数调用操作符为调用函数时的( )。
(2) 举例:
eg1.
int main ( )
{
printf("hehe\n");//printf为C语言的库函数,右边的小括号便是函数调用操作符。
printf("%d",100);
return 0;
}
eg2.
int add (int x, int y)//函数调用操作符,操作数为 add和 3和5。
{
return x+y;
}
int main ( )
{
int ret = add(3,5);
printf("%d",ret);
return 0;
}
(3) 总结:
函数调用操作符至少有1个操作数。
3.结构成员访问操作符
(1) 概念:
结构体是一种自定义的数据结构。结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。如:标量、数组、指针、甚至是其他结构体。(区别于数组,数组是一组类型相同元素的集合。)
(2) 结构体的运用规则
struct tag//struct为结构体的关键字,tag为结构体自定义的名字。
{
number-list;//成员列表
}variable-list;//变量列表
(3) 结构体变量的初始化
struct student
{
char name [20];
int age;
float score;
}S4={"小红",27,95.5};//创建一个结构体全局变量
struct student S1={"小王",18,100.0};
struct student S2={"name元素的名字",年龄元素,成绩元素}
(4)例子:
eg1.
struct student//创建一个名为student的结构体
{
char name [20];//创建变量name
int age;//创建变量age
float score;//创建变量score
//其中的name age score组成了struct的成员列表
}
struct student S3;//创建了S3的结构体的全局变量
int main ( )
{
struct student S1;//创建结构体的局部变量S2,S3
struct student S2;
return 0;
}
eg2.
struct S
{
char ch;
struct point p;
int arr [10];
double d;
} ;
int main( )
{
struct S s={ ' a ' , {4,5} , {1,2,3,4,5,6,7,8} , 3.14 };
}
(5) 结构成员访问操作符:
<1> 结构成员访问操作符包括两种:→(箭头)和.(点)。
<2> 举例:
struct S
{
char ch;
struct point p;//定义一个结构体:二维点
int arr [10];
double d;
} ;
int main( )
{
struct S s={ ' a ' , {4,5} , {1,2,3,4,5,6,7,8} , 3.14 };
printf ("%c",s.ch);//打印的结果为a
printf("%d %d",s.p.x,s.p.y);//打印的结果为4 5
printf("%d",s.arr[0]);//打印的结果为1
printf("%lf",s.d);//打印的结果为3.140000
return 0;
}
<3> 格式:结构体成员访问操作符的运用规则为:结构体变量名.结构体内的成员名。
二.操作符属性
1.操作符的属性有优先性和结合性。
2.相邻的操作符,优先级高的先执行。优先级相同的情况下,结构体说了算!
3.优先级和结合性表格(优先性从高至低)
(1) ++ -- ( ) [ ] .→ (结合性从左至右)
后缀自增 后缀自减 函数调用 数组下标 结构体成员访问操作符 结构体与联合体成员通过指针访问
(2) ++ -- + - ! ~ (type) * & sizeof (结合性从右向左)
前缀自增 前缀自减 一元加法 一元 减法 逻辑非 逐位非 强制类型转换 解引用 取地址 取大小
(3) * / % (结合性从左至右)
乘 除 取余
(4)+ - (结合性从左至右)
加 减
(5) << >> (结合性从左至右)
左移 右移
(6) < <= > >= (结合性从左至右)
小于 小于等于 大于 大于等于
(7) == != (结合性从左至右)
等于 不等于
(8) & ∧ | && || (结合性从左至右)
逐位与 逐位异或 逐位或 逻辑与 逻辑或
(9) ?: (结合性从右向左)
三元运算符
(10) = += -= *= /= %= <= >= &= ^= |= (结合性从右向左)
赋值 和赋值 差赋值 乘赋值 除赋值 取余赋值 左移赋值 右移赋值 逐位与等 逐位异或等 逐位或等
(11) , (结合性从左至右)
逗号操作符
三.表达式求值
1.整形提升
(1) 概念:
C语言中整形算术运算总是以默认整型类型进行的,为了获得这一精度,表达式中的字符(char)和短整型(short)操作数在使用之前被转换为普通整型。
(2) 作用:
CPU的操作数的字节长度,一般为int的字节长。.表达式各种长度可能小于int长度的整型值,都必须先转为int或unsigned int类型,然后才会送入CPU去计算。
(3)如何进行整形提升?
<1> 有符号整形提升是按照变量的数据类型的符号位来提升的。无符号整形提升的方法是高位补0。
<2> 整形类型提升的举例
eg.
char a= 20;
char b= 130;
char c =a+b;
printf("%d",c);
→分析:
a本应该的二进制序列
00010100
b本应该的二进制序列
10000010
a整形提升后的二进制补码序列
00000000000000000000000000010100
b整形提升后的二进制补码序列
11111111111111111111111110000010
计算后c的二进制补码序列
11111111111111111111111110010110
存储于char类型下c的二进制序列
10010110
整形提升后c的二进制补码序列
11111111111111111111111110010110
整形提升后c的二进制原码序列
10000000000000000000000001101010
所以打印的值c=-106。
→原因:如下图所示char类型的取值范围是-128~127,如果超过这一取值范围,则运算规律就像一个循环一样。重新返回最小值继续参与运算。
2.算数转换(讨论类型大于等于整形类型的类型)
<1> 运算过程中,如果操作符的不同操作数属于不同类型,那么除非其中一个操作数类型转换为另一个操作数类型才能参与运算,否则该运算将无法进行。
<2> 转换方式(从上至下依次减小)
long double
double
float
unsigned long int
long int
unsigned int
int
当进行需要转换的运算时,应该从小到大转换。
四.问题表达式解析
1. a * b + c * d + e * f
如果将五个符号的运算顺序分别记作1 2 3 4 5 。
则可能产生两种情况,一种为13524,另一种为13254。
2. c+--c
如果将两个符号的运算顺序分别记作1 2。
则该计算的顺序为21,但是左侧的c在运算时,到底是初始的c值还是进行完前置自减运算后的c呢?
3.
int i=10;
i=i-- - --i*(i=-3)*i++ + ++i
printf("%d",i);
上述代码运算复杂,在不同的编译器下运算顺序不同,为问题表达式。
4.
int fun ( )
{
static int count =1;
return ++count;
}
int main( )
{
int answer;
answer=fun( )-fun( )*fun( );
printf("%d",answer);
return 0;
}
上述代码在计算answer的值时,三次调用函数,后面两次的调用,会不会因为前面的函数调用而改变返回值呢?