sizeof 和 数组
size of是操作符,不是函数,size of()的括号可以去除,但是在使用的时候建议加上()
#include <stdio.h> void test1(int arr[]) { printf("%d\n", sizeof(arr));//(2) } void test2(char ch[]) { printf("%d\n", sizeof(ch));//(4) } int main() { int arr[10] = { 0 }; char ch[10] = { 0 }; printf("%d\n", sizeof(arr));//(1) printf("%d\n", sizeof(ch));//(3) test1(arr); test2(ch); return 0; }
++a与a++
关系操作符
>
>=
<
<=
!= 用于测试“不相等”
== 用于测试“相等
比较字符串是否相等时不能用==,用strcmp函数,头文件是sting.h
逻辑操作符
&& 逻辑与
|| 逻辑或
&& 左边为假,右边就不计算了
|| 左边为真,右边就不计算了
条件操作符
exp1 ? exp2 : exp3
逗号表达式
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
下标引用、函数调用和结构成员
[ ] 下标引用操作符
操作数:一个数组名 + 一个索引值
arr[7]=7[arr]=*(arr+7)=*(7+arr) ,但是定义数组的时候不能把arr[10]写作10[arr]。
( ) 函数调用操作符
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
访问一个结构的成员
.结构体.成员名
->结构体指针->成员名
#include<stdio.h> #include <string.h> struct Stu //创建结构体类型 { char name[20]; int age; double score; }; void set_stu(struct Stu* ps) { //strcpy((*ps).name, "zhangsan"); //(*ps).age = 20; //(*ps).score = 100.0; strcpy(ps->name, "zhangsan"); ps->age = 20; ps->score = 100.0; } void print_stu(struct Stu* ps) { printf("%s %d %lf\n", ps->name, ps->age, ps->score); } int main() { struct Stu s = { 0 }; set_stu(&s); //进行传参,这里采取了传地址 print_stu(&s); //同样进行传地址 return 0; }
访问结构体有俩种形式.和->
表达式求值
表达式求值的顺序一部分是由操作符的优先级和结合性决定。
同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。
隐式类型转换
C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度
一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长
度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令
中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转
换为int或unsigned int,然后才能送入CPU去执行运算。
我们可以看到5+126结果为-125,这是因为发生了整形提升
所以这里可以看到C输出的是负数。这是因为char类型占一个字节8个比特位,而在运算的时候,CPU一般处理int类型,而int类型占四个字节,32个比特位,此时8个比特位显然不够,编译器会自动补充其余24个比特位,补充的内容为符号位,无符号整形高位补0
int main() { char a = 0xb6; short b = 0xb600; int c = 0xb6000000; if(a==0xb6) printf("a"); if(b==0xb600) printf("b"); if(c==0xb6000000) printf("c"); return 0; }
代码会打印C,这是因为a,b要进行整形提升,但是c不需要整形提升 a,b整形提升之后,变成了负数
c只要参与表达式运算,就会发生整形提升,表达式 +c ,就会发生提升,所以 sizeof(+c) 是4个字
节.
表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节,但是 sizeof(c) ,就是1个字节
算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类
型,否则操作就无法进行。下面的层次体系称为寻常算术转换
long double
double
float
unsigned long int
long int
unsigned int
int
优先级自上而下逐渐降低,但存在精度丢失的风险
操作符的属性
复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序。
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。
操作符优先级
#include<stdio.h> int main() { int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; int f = 6; int h=a * b + c * d + e * f; printf("%d", h); return 0; }
这种运算方式,只能保证,*的计算是比+早,但是优先级并不 能决定第三个*比第一个+早执行
c + --c;
操作符的优先级只能决定自减--的运算在+的运算的前面,但是我们并没有办法得
知,+操作符的左操作数的获取在右操作数之前还是之后求值,所以结果是不可预测的,是有歧义的。(先算--c,然后算加法的时候不能保证C是--c之前的值还是--c之后的值)
#include<stdio.h> int main() { int a = 1; int b = (++a) + (++a) + (++a); printf("%d\n", b); return 0; }
不能保证先算哪个括号里面的,还有无法确定先算哪一个+
int main() { int i = 10; i = i-- - --i * ( i = -3 ) * i++ + ++i; printf("i = %d\n", i); return 0; }
编译器会凌乱
int fun() { static int count = 1; return ++count; } int main() { int answer; answer = fun() - fun() * fun(); printf( "%d\n", answer);//输出多少? return 0; }
但是上述代码 answer = fun() - fun() * fun(); 中我们只能通过操作符的优先级得知:先算乘法, 再算减法。 函数的调用先后顺序无法通过操作符的优先级确定。
下面代码的结果是:
#include <stdio.h> int i; int main() { i--; if (i > sizeof(i)) { printf(">\n"); } else { printf("<\n"); } return 0; }
全局变量,静态变量都是放在静态区,不初始化,会默认为0,局部变量不初始化默认值为随机值,局部变量在栈区
i一开始为0,i--为-1,-1>4为假,走else,但这样想是错的,因为sizeof这个操作符计算返回结果是无符号整形,size_t类型,所以这里是int和unsigned int进行比较,int转为unsigned int 此时i为一个非常大的正数,-1原码为10000000000000000000000000000001,补码为11111111111111111111111111111110,由于是无符号整形,所以计算机会把这个数字当正数看待
关于表达式求值说法不正确的是
A.表达式求值先看是否存在整形提升或算术转换,再进行计算
B.表达式真正计算的时候先看相邻操作符的优先级决定先算谁
C.相邻操作符的优先级相同的情况下,看操作符的结合性决定计算顺序
D.只要有了优先级和结合性,表达式就能求出唯一值
A:正确
B:正确
C:正确
D: 错误,有了优先级和结核性,表达式也有可能有不同的计算机路径,导致计算结果的差异。
BC68-X形图案
#include<stdio.h> int main() { int a; int i,j; while( scanf("%d",&a)!=EOF) { getchar(); for(i=0;i<a;i++) { for(j=0;j<a;j++) { if(i==j||i+j==a-1) printf("*"); else printf(" "); } printf("\n"); } } return 0; }