一.逗号操作符
1.形式: exp1, exp2, exp3 ......逗号表达式:由逗号隔开的一串表达式
2.执行过程:从左到右依次执行每一个表达式,表达式的结果是最后一个表达式的结果
int main() {
int a = 1;
int b = 2;
int c = (a > b, a = b + 10,a, b = a + 1);
// 0 12 2 12 13 12
//c = 13
printf("%d", c);
return 0;
}
此时,会依次执行a > b的判断,a = b + 10 ,b = a + 1,最后c的结果是a + 1的结果
逗号表达式实际上的值只与最后一个式子有关,因此它可以放到while函数中,例如:
int i = 0;
while(i++, i < 10){
printf("%d",i);
}
二.下标引用和函数调用
下标引用是[ ],函数调用是( )
对于下标引用,例如:
int main() {
int arr[10] = { 0 };
arr[5] = 6; //[]就是下标引用操作符
//[] 是操作符,他的操作数是: arr , 5
return 0;
}
对于函数调用,例如:
void test() {
printf("hehe");
}
//函数在调用的时候,函数名后面的括号就是函数调用操作符 ()
//它的操作数是:Add 2 3 函数名+参数
//函数调用操作符最少有一个操作数 - 函数名
int main() {
test();
printf("hehe");
printf("%d", 100);
return 0;
}
函数调用操作符可以调用内置数据类型(C语言自身的类型),也可以调用自定义的数据类型(根据实际需要可以创建的类型)
三.结构体
结构体是一些值的结合,与数组类似,称为成员变量,但不同的是,结构体的每个成员可以是不同类型的变量,而数组的每个变量都是同种类型的,我们使用struct来创建结构体
例如,我们想声明一个学生类型,包括:姓名,性别,年龄,学号
其中涉及 字符串 字符串 整数 字符串
其中就用到了字符数组和整型数组。
代码如下:
struct student {
char name[20];
char sex[12];
int age;
char id[17];
}s5,s6,s7; //全局变量
student是声明,其中s5,s6,s7是全局变量,在整个代码中都有作用。
int main() {
//局部变量
struct student s1 = { "张三","男","18","20220909" };
struct student s2 = { .name = "李明", };
printf("%s %s %d %s \n", s1.name, s1.sex, s1.age, s1.id);
//结构体变量.结构体成员
return 0;
}
我们在主函数中定义的是局部变量,可以有两种初始化方法,可以直接用双引号括起来,也可以使用.name的方式来直接定义某个值
当然,结构体变量是要在创建的时候进行初始化的
结构体也有嵌套的初始化,代码如下:
struct Point {
int x;
int y;
};
struct Point p1;
struct Node {
int deta;
struct Point p;
struct Node* next;
}; //结构体嵌套初始化
这是结构体与指针相结合的内容
四.操作符的属性
1.操作符的属性:优先级,结合性
他们决定了表达式求值的计算顺序
优先级(相邻操作符才说优先级)一个表达式包含多个运算符,优先级高的先进行,低的后算
优先级相同,看结合性,根据运算符是左结合还是右结合
2.表达式求值
有时候我们进行运算的时候,会将多种不同类型的进行相加减,在运算前,会把他们转换为同一个类型,方法如下:
(1)整型提升 整型算数运算总是以缺省(默认)整型类型的精度计算的
例子:char 字符类型 也属于整型家族的 存储的是ASCII值,是整数
那么,如何进行整型提升的呢?
有符号的整数按照变量的数据类型的符号位提升(直接补充符号位)
无符号,高位补0
实例如下:
int main() {
char a = 5;
//5
//00000000000000000000000000000101
//0000 0101 - a //截断
char b = 125;
//0111 1101 - b
//首先转换为int类型,然后再计算,计算完放到c中
char c = a + b;
//0000 0101 - a
//0111 1101 - b
//a与b的长度小于int类型的长度,再计算的时候默认发生整型提升
//00000000000000000000000000000101 - a
//00000000000000000000000001111101 - b
//00000000000000000000000010000010 - c
//10000010 - c
printf("%d", c);
//按照有符号整数的形式打印
//10000010 - c
//11111111111111111111111110000010 - c 补码
//10000000000000000000000001111110 - c 原码
return 0;
}
(2)算数转换:如果某个操作符的各个操作数右不同的类型,除非一个操作数转换为另一个类型,否则无法运算
排名如果靠后,需要转换为排名靠前的
五.问题表达式解析
例子一:
//表达式的求值部分由操作符的优先级决定
a*b + c*d + e*f
执行顺序可能是以下两种可能:
当他们的顺序可能出现不同的时候,就出现了歧义,这是个问题表达式
例子二:
c + --c;
我们知道会先运算--c,但是不清楚是先获得c的值,还是运算后再带入c的值,出现了歧义
例子三:
对于这个代码,编译器不同导致了结果的不同
表达式四:
我们不清楚fun()是先取还是后取,出现了歧义
表达式五:
不同的编译器结果不同
因此,我们尽量不要写出过于复杂的表达式。