目录
一、常量
1.概念
所谓的常量,就是指整个程序运行的过程中,值不会发生变化的量。
2.分类
变量名称 | 例子 | 输出占位符 | |
整型常量 | 二进制 | 0b1011、0B1011 | |
八进制 | 0765 | %o %# | |
十进制 | 520 | ||
int | %d | ||
long | %ld | ||
long long | %lld | ||
十六进制 | 0xFE25 | %x %#x | |
实型(浮点型) | 3.14 | float(%f) double(%lf) | |
指数常量 | 314可标识成 3.14e2 | %e | |
字符型常量 | 'M' '1' | %c | |
字符串常量 | "haohaoxuexi" | %s | |
标识常量(宏定义) | #define |
3.整型常量
#include <stdio.h>
int main(int argc, const char *argv[])
{
//可以直接输出常量
printf("%d\n", 520);//520
//也可以将常量的值保存在变量里
int value1 = 520;
printf("value1 = %d\n", value1);//520
//可以参与运算,将运算的结果直接输出
printf("value1 - 100 = %d\n", value1 - 100);//420
//输出long类型 需要用 %ld
long value2 = 1314;
printf("value2 = %ld\n",value2);
//输出long long 类型 需要用 %lld
long long value3 = 9999;
printf("value3 = %lld\n",value3);
return 0;
}
4.实型常量(小数)
一般形式 float double
指数形式
[+/-]M.Ne[+/-]T
浮点型数据,存储的是一个近似值。
#include <stdio.h>
int main(int argc, const char *argv[])
{
printf("%f\n", 3.1234589);//3.123459
//float 单精度浮点型 4字节
float f1 = 3.1415926;
//默认输出 6为小数 不足补0 超了四舍五入
printf("f1 = %f\n", f1);
printf("f1 = %.3f\n", f1);//指定输出3位小数
//double 双精度浮点型 8字节
double f2 = 3.1415926;
printf("f2 = %lf\n", f2);
printf("f2 = %.4lf\n", f2);
//指数形式
float f3 = 314159;
printf("f3 = %e\n", f3);// 3.14e+05
float f4 = -0.00031415;
printf("f4 = %e\n", f4);//-3.141500e-04
return 0;
}
5.字符常量
//字符就是整型,整型就是字符,具体看我们怎么用。
在C语言中,看到任何 被单引号 '' 引住的 都是字符常量
例如 'A' 'm' '\n' '8' '7' 注意: '8' 和 8 是不一样的
注意:单引号只能引住一个字符
#include <stdio.h>
int main(int argc, const char *argv[])
{
//可以直接输出 字符常量
printf("%c\n", 'A');//A
printf("%d\n", 'A');//65
printf("%c\n", 65);//A
printf("%d\n", 65);//65
//也可以将常量保存在变量里
char c1 = 'A';
char c2 = 65;
printf("c1 = %d [%c] c2 = %d [%c]\n", c1, c1, c2, c2);//65 [A] 65 [A]
//字符可以直接参与运算 本质上是 字符对应的ascii码参与运算
char c3 = 'A'+3;
printf("c3 = %d [%c]\n", c3, c3);//68 [D]
char c4 = 10;
printf("c4 = %d [%c]\n", c4, c4);//10 [
// ]
//思考 如何将 大写A-Z 转换成 小写的 a-z
char c5 = 'A';
char c6 = 'Z';
printf("c5+32 = %c c6+32 = %c\n", c5+32, c6+32);
char c7 = c5 + ('a' - 'A');
//思考 如何将 字符的 '8' 转换成 整数的 8
char c8 = '8';//'0' '8'
int value1 = c8 - '0';
int value2 = c8 - 48;
printf("value1 = %d value2 = %d\n",value1, value2);//8 8
return 0;
}
6.字符串常量
字符串是由一个或多个字符组成的,
C语言中的字符串需要用 双引号 " " 引起来,
C语言中每个字符串的结尾都会有一个隐藏的字符 '\0',用来标记字符串结尾的
C语言中,对字符串的处理,遇到 '\0' 就结束了
如:"hello" 需要 有 6 个字节来存储
注意:
a 这是变量a
'a' 这是字符a 一个字节存储
"a" 这是字符串a 两个字节存储,因为结尾有一个 '\0'
#include <stdio.h>
int main(int argc, const char *argv[])
{
//C语言中没有专门存储字符串的类型
//可以将字符串存储在数组里
char a[] = "www.hqyj.com";
printf("a = %s\n", a);
//也可以使用指针指向字符串常量
char *p = "hello world";
printf("p = %s\n", p);
//C语言中,对字符串的处理,遇到 '\0' 就结束了
char *p2 = "www.bai\0du.com";
printf("p2 = %s\n", p2);//www.bai
//注意 '\0' 和 '0' 是不一样的
char *p3 = "www.bai0du.com";
printf("p3 = %s\n", p3);//www.bai0du.com
return 0;
}
7.标识常量(宏定义)
宏定义就是给常量起一个别名,
在后面的代码中想使用这个常量时,直接使用这个名字即可。
注意,这个名字也是一个标识符,命名时要符合命名规范,
(一般而言标识常量的名字都要大写)
格式:
#define 宏名 宏值
例如:
#define STU 50
注意:
宏定义语句后面不要随便加 分号,替换时可能会出问题。
宏定义是在预处理阶段完成替换的,且宏定义只能完成简单的替换。
#include <stdio.h>
#define STU 50
int main(int argc, const char *argv[])
{
printf("student = %d\n", STU);
printf("student = %d\n", STU);
printf("student = %d\n", STU);
printf("student = %d\n", STU);
printf("student = %d\n", STU);
printf("student = %d\n", STU);
return 0;
}
例2:宏定义只是简单地替换
#include <stdio.h>
#define M 10
#define N 20
#define SUM M+N
#define SUM2 (M+N) //如果宏值的表达式左为一个整体 需要加括号
int main(int argc, const char *argv[])
{
int ret1 = SUM * 2;
//int ret1 = M+N*2;
//int ret1 = 10+20*2;
printf("ret1 = %d\n", ret1);//50
int ret2 = SUM2 * 2;
//int ret2 = (M+N)*2;
//int ret2 = (10+20)*2;
printf("ret1 = %d\n", ret2);//60
return 0;
}
二、变量
1.概念
变量:在程序运行过程中,值可以发生变化的量
变量的大小:由变量的类型来决定
变量的名字:是一个标识符,要遵循命名规范
定义变量的格式:
数据类型 变量名;
其实在数据类型前面,应该还有存储类型:
const static register volatile extern auto,不加的时候,默认是auto
2.变量的初始化及赋值
#include <stdio.h>
int main(int argc, const char *argv[])
{
//定义变量时,类型的作用相当于一个模子,
//规定了由他定义的变量占用的内存空间的大小
//变量的初始化:在定义变量的同时给变量赋值
int a = 10;
printf("a = %d\n", a);//10
//变量的赋值:先定义变量,然后在赋值
//int b;
//如果定义变量时没有初始化,那么里面存的就是个随机值
//printf("b = %d\n", b);//随机值
//所以为了防止随机值对我们程序的影响,一般定义变量不知道用什么初始化时
//最好也用0来初始化一下
int b = 0;
b = 20;
printf("b = %d\n", b);//20
//变量可以被重新赋值 等号右边赋值给等号左边
a = 520;
//变量也是可以参与运算的
int c = a + b;
int d = 0;
d = c + 100;
printf("c = %d\n", c);
printf("d = %d\n", d);
//在同一个 {} 里面不允许定义多个同名的变量
//int a = 1314;//错误的
//可以在一行定义多个变量,多个变量之间用 逗号 分隔
int v1,v2=100,v3,v4=50;
return 0;
}
练习:
一个水分子的质量是 3.0 * 10 ^ (-7) g,一升水有 980 g,
写程序,求出 5升水共 包含多少个水分子?
变量的类型都使用 double
#include<stdio.h>
int main(int argc, const char *argv[])
{
double a = 0;
double sum = 0;
a = 980;
sum = a*5/3.0e-7;
printf("sum = %e\n",sum);
return 0;
}
3.强制类型装换
所谓的强制类型转换,就通过某种方法,将一个类型在某次运算的过程中转换成其他类型。
3.1显式强制类型转换
格式:
(新的类型)变量名;
#include <stdio.h>
int main(int argc, const char *argv[])
{
int m = 5;
int n = 2;
//在C语言中 两个整数做除法,得到的结果也是一个整数
//会舍弃小数部分
//有些场景我们需要用到小数部分,就得使用强制类型转换
//下面的代码表示 在本次运算中 将 m 和 n 的类型转换为 浮点型
float ret = (float)m / (float)n;
printf("ret = %f\n", ret);
//强制类型转换不会影响到变量原来的值
printf("m = %d n = %d\n", m, n);
return 0;
}
强制类型转换是不安全的,小类型转大类型一般是没问题的,如果大类型转小类型,可能会出现数据的丢失。
#include <stdio.h>
int main(int argc, const char *argv[])
{
char m = 127;
short n = (short)m;
printf("m = %d n = %d\n", m, n);//127 127
short a = 1000;
char b = (char)a;
printf("a = %d b = %d\n", a, b);//数据会出现丢失
return 0;
}
3.2隐式强制类型转换
隐式强制类型转换,是由编译器根据上下文自动推导的。
对于危险的操作,有的编译器会报一个警告,有的就不会,具体取决于编译器的严谨程度。
例:
#include <stdio.h>
int main(int argc, const char *argv[])
{
float f1 = 3.14;
//编译器自动根据上下文推导
//将f1的整数部分赋值给a --隐式强制类型转换
int a = f1;
printf("f1 = %f a = %d\n", f1, a);//3.140000 3
return 0;
}
有符号数和无符号数参与运算时,会讲有符号数强转成无符号数来运算。
#include <stdio.h>
int main(int argc, const char *argv[])
{
signed int a = -20;
unsigned int b = 6;
if(a+b>0){
printf("yes\n");//会输出
}
return 0;
}
三、运算符
1.概念
运算符就是一个符号,用来多个值之间做运算的;
运算符是用来连接表达式的
所谓的表达式是由 运算符、运算量、标点符号等组成的一个有效序列,
是用来描述一个运算过程的。
2.分类
1.算数运算符:+ - * / %(模除..就是取余) ++ --
2.关系运算符:> < >=
3.逻辑运算符:&& || !
4.位运算符: & | ^ ~ >
5.赋值运算符: = += -+ *=
6.条件运算符(三目运算符): ?:
7.逗号运算符
8.sizeof运算符
3.算数运算符
+ - * / %(要求运算数必须是整数)
#include <stdio.h>
int main(int argc, const char *argv[])
{
int m = 20;
int n = 3;
printf("m + n = %d\n", m + n);//23
printf("m - n = %d\n", m - n);//17
printf("m * n = %d\n", m * n);//60
//整数做除法 别忘了强制类型转换
printf("m / n = %f\n", (float)m / (float)n); //6.666667
//输出% 需要写两个 %
printf("m %% n = %d\n", m % n);//2
float f1 = 5.28;
float f2 = 3.14;
//错误的 浮点型不能做 % 运算
//printf("f1 %% f2 = %f\n", f1 % f2);
return 0;
}
自增运算符 ++
自减运算符 --
a++ ---> a = a+1
++a ---> a = a+1
a-- ---> a = a-1
--a ---> a = a-1
以 a = 10 为例
对于 a++ 和 ++a 两个表达式, a 的值都自增了
但是表达式的结果是不一样的 ++a 表达式的结果是11 而 a++ 表达式的结果还是10
对于自减运算符 同理
#include <stdio.h>
int main(int argc, const char *argv[])
{
//可以理解成 ++a 是先自增后使用
int a = 10;
int b = ++a;
printf("a = %d b = %d\n", a, b);//11 11
// a++ 是先使用后自增
a = 10;
b = a++;
printf("a = %d b = %d\n", a, b);//11 10
return 0;
}
C语言中的输入函数:scanf
#include <stdio.h>
int main(int argc, const char *argv[])
{
int value = 0;
//注意 不要加 \n, 变量前要加 &
//scanf会让程序阻塞,直到用户输入 并按下回车
printf("请输入一个数(int):");
scanf("%d", &value);
printf("input is %d\n", value);
return 0;
}
练习:
从终端输入一个三位数,
输出 这个三位数的 百位数字 + 十位数字 + 个位数字 的和
如:532 ---> 5 + 3 + 2 = 10
#include <stdio.h>
int main(int argc, const char *argv[])
{
int value = 0;
printf("input your num(int):");
scanf("%d", &value);
//获取 个位 十位 百位
int ge = value % 10;
int shi = value / 10 % 10;
int bai = value / 100;
printf("sum = %d + %d + %d = %d\n", ge, shi, bai, ge+shi+bai);
return 0;
}
4.关系运算符
> < >=
关系运算符一般是用来判断连接的多个表达式之间的关系的。
关系运算符连接的表达式的结果是一个 bool 类型
bool 类型只有两种值:0 假 非0 真(即使是负数也是真)
注意:一定要区分 = ==
a = b; 表示将 b 的值赋给 a
a == b; 表示判断 a 和 b 是否相等
#include <stdio.h>
int main(int argc, const char *argv[])
{
int m = 20;
int n = 10;
int ret1 = m > n;
int ret2 = m <= n;
printf("ret1 = %d ret2 = %d\n", ret1, ret2);//1 0
//关系运算符一般多用于控制语句
if(m != n){
//如果if后面 () 里的条件为真,则执行这里
printf("yes\n");
}else{
//如果if后面 () 里的条件为假,则执行这里
printf("no\n");
}
if(n == 10){
printf("n == 10\n");
}else{
printf("n != 10\n");
}
return 0;
}
5.逻辑运算符
逻辑运算符是用来连接多个由关系运算符组成的表达式的,
逻辑运算符连接的表达式的结果 也是一个 bool
&& 逻辑与,表示并且
逻辑与运算符连接的多个表达式,全为真时,整个表达式才为真
有一个表达式为假,整个表达式的结果就为假
即:全真为真,一假则假
如 a>b && a>c 相当于,a 要比 b 和 c 都大,才为真
|| 逻辑或,表示或者
逻辑或运算符连接的多个表达式,有一个表达式为真,整个表达式就为真
所有表达式都为假,整个表达式的结果才为假
即:一真则真,全假为假
如 a>b || a>c 相当于,a>b 或者 a>c 任意一个为真 整个表达式就为真
! 逻辑非, 真变假 假变真
注意:
数学中: 10 < x < 20
C语言中没有这种写法,需要写成: x>10 && x
#include <stdio.h>
int main(int argc, const char *argv[])
{
int m = 0;
int n = 0;
scanf("%d%d",&m, &n);
#if 0
if(m>0 && n>0){
printf("yes\n");
}else{
printf("no\n");
}
#endif
if(m>0 || n>0){
printf("yes\n");
}else{
printf("no\n");
}
printf("---------------------------\n");
if(!(m>0 || n>0)){
printf("yes\n");
}else{
printf("no\n");
}
return 0;
}
逻辑运算符的短路原则:
逻辑与 && 连接的多个表达式,从左向右,遇到某个表达式为假了
后面的就都不执行了。
逻辑与 || 连接的多个表达式,从左向右,遇到某个表达式为真了
后面的就都不执行了。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int m = 20;
int n = 10;
int value = 100;
int ret1 = m<n && value--;//此处的value-- 不会执行
printf("ret1 = %d value = %d\n", ret1, value);//0 100
int ret2 = m>n || value--;//此处的 value-- 不会执行
printf("ret2 = %d value = %d\n", ret2, value);//1 100
int ret3 = m>n && value--;//此处的 value-- 会执行
printf("ret3 = %d value = %d\n", ret3, value);//1 99
value = 100;
int ret4 = m<n || value--;//此处的 value-- 会执行
printf("ret4 = %d value = %d\n", ret4, value);//1 99
//注意a++ 和 ++a 的问题
int a = 0;
int b = 10;
int c = 20;
int ret5 = c < b || --a;
printf("ret5 = %d a = %d\n", ret5, a);//1 -1
return 0;
}
练习:
输入两个数,分别存在两个变量里,交换这两个变量的值,并输出。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int v1 = 0;
int v2 = 0;
scanf("%d%d", &v1, &v2);//10 20
#if 0
//方法1:三杯水交换 ----比较常用
int temp = v1;
v1 = v2;
v2 = temp;
#endif
#if 1
//方法2:不使用第三个变量 --不常用
//使用的时候容易出现数据溢出的情况
v1 = v1 + v2;
v2 = v1 - v2;
v1 = v1 - v2;
#endif
#if 0
//方法3:三次异或实现两个数交换 --不常用
v1 = v1 ^ v2;
v2 = v1 ^ v2;
v1 = v1 ^ v2;
#endif
printf("v1 = %d v2 = %d\n", v1, v2);//20 10
return 0;
}
6.位运算符
& | ^ ~ >
不管几进制的数,做位运算时,都要先转换成 二进制 的再做运算。
如果需要用到位运算,一般使用的都是 unsigned 的,
如果是有符号的,可能还会涉及原码、反码、补码转换的问题。
& 按位与,全1为1,有0为0
| 按位或,有1为1,全0为0
^ 按位异或,不同为1,相同为0
~ 按位取反,1变0,0变1
>> 右移,舍弃低位,高位补0
#include <stdio.h>
int main(int argc, const char *argv[])
{
unsigned char a = 35;
unsigned char b = 57;
unsigned char c = 0;
c = a & b;
//a:0010 0011
//b:0011 1001
//&
//c:0010 0001 --> 0x21
printf("c = a & b = %#x\n", c);
c = a | b;
//a:0010 0011
//b:0011 1001
//|
//c:0011 1011 --> 0x3b
printf("c = a | b = %#x\n", c);
c = a ^ b;
//a:0010 0011
//b:0011 1001
//^
//c:0001 1010 --> 0x1a
printf("c = a ^ b = %#x\n", c);
c = ~a;
//a:0010 0011
//~
//c:1101 1100 --> 0xdc
printf("c = ~a = %#x\n", c);
c = a<<2;
//a:0010 0011
//a<<2
//c:1000 1100 --> 0x8c
printf("c = a<<2 = %#x\n", c);
c = a>>2;
//a:0010 0011
//a>>2
//c:0000 1000 --> 0x08
printf("c = a>>2 = %#x\n", c);
return 0;
}
位运算的小技巧:
1或任何数都是1
1与任何数都是任何数
0或任何数都是任何数
0与任何数都是0
位运算一般多用于标志位或者硬件设备的控制。
练习:
1.有8个LED灯,初始状态全灭(0)
2.将1 3 5 7 号灯点亮
3.将 5 号灯熄灭
4.将 4 号灯点亮,其他灯全熄灭
#include <stdio.h>
int main(int argc, const char *argv[])
{
//初始状态全灭 0000 0000
unsigned char led = 0;
//将 1 3 5 7 号灯点亮 ---> 0101 0101
//led = 0x55;//这种写法 可以实现功能,但是可能会影响其他位
led = led | 0x55;
printf("led = %#x\n", led);//0x55
//将5号灯熄灭 ---> 0100 0101
//led = led & 0xEF;
led = led & ~(1<<4);
printf("led = %#x\n", led);//0x45
//将 4 号灯点亮
led = led | (1<<3);
printf("led = %#x\n", led);//0x4d
//其他灯全熄灭
led = led & (1<<3);
printf("led = %#x\n", led);//0x8
return 0;
}
7.赋值运算符
=
一般使用格式:
左 = 右;
注意:是将右边的值 赋给左边
左边的值一定是一个 变量
复合赋值运算符:
a += b a = a + b
a -= b a = a - b
a *= b a = a * b
其他的同理,详见下图
#include <stdio.h>
int main(int argc, const char *argv[])
{
int m = 10;
int n = 20;
printf("m = %d n = %d\n", m, n);//10 20
m += n; //等价与 m = m + n;
printf("m = %d n = %d\n", m, n);//30 20
return 0;
}
8.条件运算符
是C语言中唯一一个 三目运算符
?:
使用格式:
表达式1?表达式2:表达式3
执行逻辑:先执行表达式1,如果表达式1为真,则执行表达式2,否则执行表达式3
他和if..else语句很像
if(表达式1){
表达式2
}else{
表达式3
}
#include <stdio.h>
int main(int argc, const char *argv[])
{
int m = 10;
int n = 20;
printf("m = %d n = %d\n", m, n);//10 20
m>n ? m++ : n++;//执行n++
printf("m = %d n = %d\n", m, n);//10 21
m<n ? m++ : n++;//执行m++
printf("m = %d n = %d\n", m, n);//11 21
return 0;
}
9.sizeof运算符
格式:
sizeof(类型名或者变量名)
作用:
sizeof他是一个关键字,不是一个函数,可以用来计算类型或者变量占用的
内存空间的大小,返回值结果是以 字节 为单位的。
32为系统,返回的是 int %d
64为系统,返回的是 long %ld
#include <stdio.h>
int main(int argc, const char *argv[])
{
char a;//1
short b;//2
int c;//4
long d;// 4 或者 8
long long e;//8
float f;//4
double g;//8
printf("sizeof(char) = %ld, sizeof(a) = %ld\n", sizeof(char), sizeof(a));
printf("sizeof(short) = %ld, sizeof(b) = %ld\n", sizeof(short), sizeof(b));
printf("sizeof(int) = %ld, sizeof(c) = %ld\n", sizeof(int), sizeof(c));
printf("sizeof(long) = %ld, sizeof(d) = %ld\n", sizeof(long), sizeof(d));
printf("sizeof(long long) = %ld, sizeof(e) = %ld\n", sizeof(long long), sizeof(e));
printf("sizeof(float) = %ld, sizeof(f) = %ld\n", sizeof(float), sizeof(f));
printf("sizeof(double) = %ld, sizeof(g) = %ld\n", sizeof(double), sizeof(g));
//也可以使用变量保存sizeof的结果
long ret = sizeof(int);
int ret2 = sizeof(int);//隐式强转 也没问题
printf("ret = %ld ret2 = %d\n", ret, ret2);
return 0;
}
10.逗号运算符
----不常用,了解一下就可以
格式:(表达式1,表达式2,...,表达式n)
执行逻辑:从左向右依次执行,最后一个表达式的结果就是整个表达式的结果
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 10;
int b = 20;
int c = 30;
int ret = 0;
ret = (++a , ++b, ++c);
//先算 ++a 然后算 ++b 最后算 ++c
//ret 的结果 就是 ++c 的结果
printf("ret = %d a = %d b = %d c = %d\n", ret, a, b, c);//31 11 21 31
//注意如果是 逗号运算符 想获取整个表达式的结果,需要用 ()扩起来
//否则就不是逗号运算符了
ret = ++a , ++b, ++c;
//从左想右依次运算, ret 中保存的就是 ++a 的结果
printf("ret = %d a = %d b = %d c = %d\n", ret, a, b, c);//12 12 22 32
return 0;
}
6.运算符的优先级
如果自己写代码时,运算符优先级拿不准了,可以用()来控制优先级。
顺口溜:单算移关与 异或逻条赋。