1.赋值运算符与表达式
运算符 描述 实列
= 把右边操作数的值赋给左边操作数 A=B+C将B+C的值赋给A
+= 把右边操作数加上左边操作数的结果赋值给左边操作数 A+=B相当于A=A+B
-= 把左边操作数减去右边操作数的结果赋值给左边操作数 A-=B相当于A=A-B
*= 把右边操作数乘以左边操作数的结果赋值给左边操作数 A*=B相当于A=A*B
/= 把左边操作数除以右边操作数的结果赋值给左边操作数 A/=B相当于A=A/B
%= 求两个操作数的模赋值给左边操作数,浮点数不适用取余数 A%=B相当于A=A%B
赋值运算符支持的是C语言的基本数据类型,包括char、int和double,字符串(字符数组)不能使用赋值运算符。
例如:
#include<stdio.h>
int main()
{
int A=12; //定义变量A并初始化
int B=3; //定义变量B并初始化
A+=B; //A=A+B
printf("A的值=%d\n",A) ;
A-=B; //A=A-B
printf("A的值=%d\n",A) ;
A*=B; //A=A*B
printf("A的值=%d\n",A) ;
A/=B; //A=A/B
printf("A的值=%d\n",A) ;
A=100;
A%=B; //A=A%B
printf("A的值=%d\n",A) ;
return 0;
}
运行结果为:A的值为15,12,36,12,1.
2.算术运算符与表达式
假设变量A的值为12,变量B的值为3,则:
运算符 描述 实列
+ 两个数相加 A+B将得到15
- 一个数减另一个数 A-B将得到9
* 两个数相乘 A*B将得到36
/ 分子除以分母 A/B将得到4
% 余数运算符,整除后的余数 A%B将得到0
++ 自增运算符,整数值增加 1 A++将得到13
-- 自减运算符,整数值减少 1 A--将得到11
例如:
#include<stdio.h>
int main()
{
double A=12; //定义变量A,赋值12
double B=3; //定义变量B,赋值3
printf("A的值是:%lf\n",A) ;
printf("B的值是:%lf\n",B) ;
printf("A+B的值是:%lf\n",A+B) ;
printf("A-B的值是:%lf\n",A-B) ;
printf("A*B的值是:%lf\n",A*B) ;
printf("A/B的值是:%lf\n",A/B) ;
A++; //自增1
printf("A自增后的值是:%lf\n",A);
A--; //自减1
printf("A自减后的值是:%lf\n",A);
return 0;
}
运行结果为:
A的值是:12.000000
B的值是:3.000000
A+B的值是:15.000000
A-B的值是:9.000000
A*B的值是:36.000000
A/B的值是:4.000000
A自增后的值是:13.000000
A自减后的值是:12.000000
变量的自增或自减有两种写法:
变量名++; // 表示在本次使用变量后再自增;
++变量名; // 表示在本次使用变量前自增;
变量名–; // 表示在本次使用变量后再自增;
–变量名; // 表示在本次使用变量前自减;
例如:
#include<stdio.h>
int main()
{
int i=0; //定义变量i并初始化
i=10;
printf("i++的值是:%d\n",i++); //在使用后自增
printf("i的值是:%d\n",i);
i=20;
printf("++i的值是:%d\n",++i); //在使用前自增
printf("i的值是:%d\n",i);
return 0;
}
运行的结果是:
i++的值是:10
i的值是:11
++i的值是:21
i的值是:21
3.关系与算符
关系运算(Relational Operators),用于判断条件,决定程序的流程。
关系 C语言的表示
小于 <
小于等于 <=
大于 >
大于等于 >=
等于 ==
不等于 !=
C语言的基本数据类型有char、int、double,我们暂时认为只有char和int适用于上述关系运算符,double和字符串(字符数组)的关系运算以后再讨论。
注意了:
1)“=”是赋值,“==”才是判断两个数是否相等,不能混用。
2)C语言没有“之间”、“中间”、“之内”或“在某范围内”的关系运算符。
例如:
#include<stdio.h>
int main()
{
int grade=0; //定义一个整型变量grade,存放用户输入的分数
printf("请输入你的分数:") ; //提示用户输入
scanf("%d",&grade); //接受从键盘输入的分数
if(grade>=90)
{
printf("太棒了,你的成绩达到了优秀,恭喜你!\n");
}
else
{
printf("你还需要努力呦,加油\n");
}
return 0;
}
4.逻辑运算符与表达式
日常生活中,要做出某个决定,需要判断的条件肯定不止一个,需要判断多个条件。
例如:
#include<stdio.h>
int main()
{
int age=0; //年龄
int grade=0; //分数
int experience=0; //经验,1.多,2.少
int able=0; //个人能力,1.很强 ,2.普通,3.差
printf("请输入年龄、分数、经验(1.多,2.少):\n");
scanf("%d %d %d",&age,&grade,&experience);
printf("请输入能力(1.很强 ,2.普通,3.差):\n");
scanf("%d",&able);
if((age>=20)&&(age<=30)) //年龄在20-30 之间
{
if((grade>=80)&&(grade<=100)) //分数在80-100之间
{
if(experience==1) //经验,1.多
{
if((able==1)||(able==2)) //能力,1.很强,2.普通
{
printf("很适合我公司,恭喜你录取了\n");
return 0;
}
}
}
}
printf("你的条件不适合我公司,希望下次合作\n");
}
采用了if嵌套的方法,其实可以采用一个复杂的if逻辑表达式一次性完成全部的判断,采用括号、对齐、空格、换行有助于更清晰的表达复杂的逻辑表达式。
逻辑运算符有三种,上文介绍了&&和||,还有一个!没介绍,接下来讲一下,
!就是非,取相反的意思。
例如:if ( grade = 90 ) //判断分数是90
等同于:if ( ! (grade != 90)) //判断分数不是90再取反
这是吃饱没事做。
5.逗号运算符与表达式
逗号是运算符不?
是的,但是其实可以说它是分隔符。在C语言中我们就经常使用逗号,看似逗号是非常平凡的分隔符,但是它关联到一个你必须知道但可能未曾思考的小知识:理论上,每条语句(分号结束),最终都会转换成一个值。
例如1:
#include<stdio.h>
int main()
{
1,2,3; //这是一条语句
int a=(1,2,3); //把上面这条语句的值赋值给变量a
printf("a=%d\n",a);
}
输出结果:a=3
因为a的值是整条语句的值,而整条语句的值是最后那个逗号后面的值。
例如2:
#include<stdio.h>
int main()
{
int a=1,b=2,c=3;
int x=0;
int y=(x=a+b);
printf("第一个y=%d\n",y);
y=((x=a+b),(b+c),(a+c),(a+b+c));
printf("第二个y=%d\n",y);
}
运出来的结果:
第一个y=3
第二个y=6
逗号运算符让你明白什么?一条语句理论上是有返回值的,如果语句里面有多个逗号,则以最后一个逗号后面的表达式值为返回值!
逗号的表达式(顺序表达式):表达式1,表达式2,表达式3,......,表达式n
结果为表达式n的值。
6.条件运算符
也叫三目运算符、三元运算符,是由一个问号和一个冒号组成。
语法:表达式1?表达式2:表达式3;
意思:先执行表达式1,如果表达式1的结果如果为真,那么执行表达式2,并且这个整体的运算式的结果是表达式2的结果;如果表达式1的结果如果为假,执行表达式3,运算式的结果是表达式3的结果。
int a,b,c;
a=7;
b=6;
c=(a>b)?a:b;
等同于
if (a>b) c=a;
else c=b;
三目运算符可以嵌套使用,我不建议使用三目运算符,过于复杂的三目运算难以理解。
比如判断year是不是闰年,是则返回1,不是返回0。
int year;
year=(year%100==0)?(year%400==0?1:0):(year%4==0?1:0);
蒙了吧。
7.sizeof运算符
sizeof是C语言的关键字,它用来计算变量(或数据类型)在当前系统中占用内存的字节数。
sizeof不是函数,产生这样的疑问是因为sizeof的书写确实有点像函数,sizeof有两种写法:
用于数据类型
sizeof(数据类型);
数据类型必须用括号括住。
printf("字符型变量占用的内存是=%d\n",sizeof(char)); // 输出:字符型变量占用的内存是=1
printf("整型变量占用的内存是=%d\n",sizeof(int)); // 输出:整型变量占用的内存是=4
用于变量
sizeof(变量名);
sizeof 变量名;
变量名可以不用括号括住,带括号的用法更普遍,大多数程序员采用这种形式。
(1)sizeof(结构体)
理论上讲结构体的各个成员在内存中是连续存放的,和数组非常类似,但是,结构体占用内存的总大小不一定等于全部成员变量占用内存大小之和。在编译器的具体实现中,为了提高内存寻址的效率,各个成员之间可能会存在缝隙。用sizeof可以得到结构体占用内容在总大小,sizeof(结构体名)或sizeof(结构体变量名)都可以。
#include <stdio.h>
// #pragma pack(1) # 告诉编器内存按1字节对齐。
struct st_girl
{
char name[50]; // 姓名
int age; // 年龄
int height; // 身高,单位:厘米cm
char sc[30]; // 身材,火辣;普通。
char yz[30]; // 颜值,漂亮;一般;歪瓜裂枣。
};
int main()
{
struct st_girl queen;
printf("sizeof(struct st_girl) %d\n",sizeof(struct st_girl));
printf("sizeof(queen) %d\n",sizeof(queen));
}
运行结果:
sizeof(struct st_girl) 120
sizeof(queen) 120
从上面的示例可以看出,struct st_girl全部成员变量占用的内存是50+4+4+30+30=118,但是结构体占用的内存是120。
注意,C语言提供了结构体成员内存对齐的方法,可以使结构体成员变量之间的内存没有空隙,启用#pragma pack(1)代码即可。
(2)不要对void使用sizeof
printf("sizeof(void)=%d\n",sizeof(void)); // 输出sizeof(void)=1
以上代码在有些编译器中可能无法通过。
void是无值型或空类型,不知道存储空间大小的类型,编译器也不能确定它的大小。void不能声明变量,以下代码编译无法通过:
void vv;
但是以下代码是正确的:
void *pv;
printf("sizeof(void*)=%d\n",sizeof(pv)); // 输出sizeof(void)=8
pv是一个void指针,在64位操作系统中,指针变量占用的内存的大小都是8,下同。
(3)不要在子函数中对字符指针用sizeof
如果把一个字符串(如char strname[21])的地址传给子函数,子函数用一个字符指针(如char *pstr)来存放传入的字符串的地址,如果在子函数中用sizeof(pstr),得到的不是字符串占用内存的字节数,而是字符指针变量占用内存的字节数(8字节)。
所以,不能在子函数中对传入的字符串进行初始化,除非字符串的长度也作为参数传入到了子函数中。
(4)不要在子函数中对结构体指针用sizeof
如果把一个结构体(如struct st_girl stgirl)的地址传给子函数,子函数用一个结构体指针(如struct st_girl *pgril)来存放传入的结构体的地址,如果在子函数中用sizeof(pgirl),得到的不是结构体占用内存的字节数,而是结构体指针变量占用内存的字节数(8字节)。正确的用法是用sizeof(struct st_girl)。