关键字

数据类型相关的关键字

用于定义变量或者类型

类型 变量名;

char 、short、int 、long 、 float、double、 struct、union、enum 、signed、unsigned、void

1、 ==char 字符型== ,用 char 定义的变量是字符型变量,占 1 个字节

char ch=’a’; =为赋值号

1
2
char ch1= ‘1’; //正确
char ch2 = ‘1234’;// 错误的

2、 ==short 短整型== ,使用 short 定义的变量是短整型变量,占 2 个字节

1
short int a=11; //-32768 --- 32767

3、 ==int 整型== ,用 int 定义的变量是整型变量,在 32 位系统下占 4 个字节,在 16 平台下占 2 个字节

1
int a=44; //-20 亿---20 亿

4、 ==long 长整型== 用 long 定义的变量是长整型的,在 32 为系统下占 4 个字节

1
long int a=66;

5、 ==float 单浮点型 (实数)==,用 float 定义的变量是单浮点型的实数,占 4 个字节

1
float b=3.8f;

6、 ==double 双浮点型 (实数)==,用 double 定义的变量是双浮点型的实数,占 8 个字节

1
double b=3.8;

7、 struct 这个关键字是与结构体类型相关的关键字,可以用它来定义结构体类型

8、 union 这个关键字是与共用体(联合体)相关的关键字

9、 enum 与枚举类型相关的关键字

10、signed 有符号(正负)的意思

​ 在定义 char 、整型(short、int、long)数据的时候用 signed 修饰,代表咱们定义的数据是有符号的,可以保存正数,也可以保存负数

例 :signed int a=10;

注意:默认情况下 signed 可以省略 即 int a=-10;//默认 a 就是有符号类型的数据

11、unsigned 无符号的意思

​ 在定义 char、整型(short、int、long) 数据的时候用 unsigned 修饰,代表咱们定义的数据是无符号类型的数据只能保存正数和 0

1
2
unsigned int a=101; 
unsigned int a=-101

扩展:内存存储

char ch= ‘a’; //占 1 个字节,存储的是 97

0110 0001

字节:内存的基本单位,8 位为 1 个字节

计算机存储时,只能存储 1 和 0 的二进制组合,1 和 0 都分别占 1 位字符型数据在内存中存储的不是字符本身,而是存储其 AsciI 码

整型变量存储的是其值的二进制

unsigned int a = 97;

扩展:正数和负数在内存中到底是怎么存的

原码、反码、补码

规定:正数的原码反码和补码相同 5

  • 原码:最高位为符号位 最高位为 1 代表是个负数

​ 5的二进制:0000 0101

​ -5的二进制:1000 0101

  • 反码:对原码除了符号位 其他位取反

​ 5的反码:1111 1010

  • 补码:反码 +1

​ 即反码的最后一位加1:1111 1011

注意:负数在内存中是以补码形式存放的

例:

1
2
3
4
5
6
7
#include <stdio.h>
int main(int argc, char *argv[]){
int a=-1;
printf("%d\n",a);
printf("%x\n",a);
return 0;
}
1
2
3
//1000 0000 0000 0000 0000 0000 0000 0001  原码
//1111 1111 1111 1111 1111 1111 1111 1110 反码
//1111 1111 1111 1111 1111 1111 1111 1111 补码

12、void 空类型的关键字

char、int 、float 都可以定义变量

void 不能定义变量,没有 void 类型的变量

void 是用来修饰函数的参数或者返回值,代表函数没有参数或没有返回值例:

1
2
3
void fun(void){

}

代表 fun 函数没有返回值,fun 函数没有参数

存储相关关键字

register、static、const、auto、extern

1、==register== 是 寄存器的意思,用 register 修饰的变量是寄存器变量,

即:在编译的时候告诉编译器这个变量是寄存器变量,尽量将其存储空间分配在寄存器中。 注意:

  1. 定义的变量不一定真的存放在寄存器中。
  2. cpu 取数据的时候去寄存器中拿数据比去内存中拿数据要快
  3. 因为寄存器比较宝贵,所以不能定义寄存器数组
  4. register 只能修饰 字符型及整型的,不能修饰浮点型
1
2
3
4
register char ch; 
register short int b;
register int c;
register float d;//错误的
  1. 因为 register 修饰的变量可能存放在寄存器中不存放在内存中,所以不能对寄存器变量取地址。因为只有存放在内存中的数据才有地址
1
2
3
register int a; 
int *p;
p=&a;//错误的,a 可能没有地址

2、==static== 是静态的意思
static 可以修饰全局变量、局部变量、函数这个以后的课程中重点讲解
3、==const== 是常量的意思
用 const 修饰的变量是只读的,不能修改它的值

1
2
const int a=101;//在定义 a 的时候用 const 修饰,并赋初值为 101
a=111;//错误的

从此以后,就不能再给 a 赋值了,const 可以修饰指针

4、==auto== auto int a;和 int a 是等价的,auto 关键字现在基本不用

5、==extern== 是外部的意思,一般用于函数和全局变量的声明

控制语句相关的关键字

if、else、break、continue、for、while、do、switch、case、goto、default

其他关键字

sizeof、typedef、volatile

  1. sizeof

    使用来测变量、数组的占用存储空间的大小(字节数)

    1
    2
    3
    int a=10;
    int num;
    num=sizeof(a);
  2. typedef

    重命名相关的关键字

    typedef 起别名的方法:

    1. 用想起名的类型定义一个变量
    1
    short int a;
    1. 用新的类型名替代变量名
    1
    short int INT16;
    1. 在最前面加 typedef
    1
    typedef short int INT16;
    1. 就可以用新的类型名定义变量了
    1
    INT16 b;和 short int b;//是一个效果
  3. volatile

易改变的意思

​ 用 volatile 定义的变量,是易改变的,即告诉 cpu 每次用 volatile 变量的时候,重新去内存中取保证用的是最新的值,而不是寄存器中的备份。
volatile 关键字现在较少适用

1
volatile int a=10;

命名规则:
在 c 语言中给变量和函数起名的时候,由字母、数字、下划线构成必须以字母或者下滑线开头,起名的时候要求见名知意

例:

1
2
3
4
int a2;//正确的
int a_2;//正确的
int _b;//正确的
int 2b;// 错误的

C 语言的程序结构

​ 一个完整的 C 语言程序,是由一个、且只能有一个 main()函数(又称主函数,必须有)和若干个其他函数结合而成(可选)
main 函数是程序的入口,即 程序从 main 函数开始执行

数据类型

基本类型

char、short int、int、long int、float、double

扩展:常量和变量

常量:在程序运行过程中,其值不可以改变的量例:100 ‘a’ “hello”

  • 整型 100,125,-100,0
  • 实型 3.14 , 0.125f,-3.789
  • 字符型 ‘a’,‘b’,‘2’
  • 字符串 “a”,“ab”,“1232”

变量:其值可以改变的量被称为变量

1
2
int a=100; 
a=101;

字符数据

==字符常量:==
直接常量:用单引号括起来,如:’a’、’b’、’0’等.
转义字符:以反斜杠“\”开头,后跟一个或几个字符、如’\n’,’\t’等,分别代表换行、横向跳格. ‘\’表示的是\ ‘%%’ ‘\’’
==字符变量:==
用 char 定义,每个字符变量被分配一个字节的内存空间字符值以 ASCII 码的形式存放在变量的内存单元中;
注:char a;
a = ‘x’;
a 变量中存放的是字符’x’的 ASCII :120
即 a=120 跟 a=’x’在本质上是一致的.

例:

1
2
3
4
5
6
7
#include <stdio.h>
int main() {
char a = 'x'; char b = 120;
printf("a=%c\n", a);//a=x
printf("b=%c\n", b);//b=x
return 0;
}

==字符串常量==
是由双引号括起来的字符序列,如“CHINA”、”哈哈哈” “C program”,“$12.5”等都是合法的字符串常量.
==字符串常量与字符常量的不同==
‘a’为字符常量,”a”为字符串常量
每个字符串的结尾,编译器会自动的添加一个结束标志位’\0’, 即“a”包含两个字符‘a’和’\0’

==整型数据==
整型常量:(按进制分):
十进制: 以正常数字 1-9 开头,如 457 789
八进制: 以数字 0 开头,如 0123
十 六 进 制 : 以 0x 开 头 , 如 0x1e a=10,b=11,c=12, d=13,e=14,f=15

==整型变量:==
有/无符号短整型(un/signed) short(int) 2 个字节
有/无符号基本整型(un/signed) int 4 个字节
有/无符号长整型(un/signed) long (int) 4 个字节 (32 位处理器)

==实型数据(浮点型)==
实型常量
实型常量也称为实数或者浮点数
十进制形式:
由数字和小数点组成:0.0、0.12、5.0

指数形式:
​ 123e3 代表 12310 的三次方
​ 123e-3
​ 不以 f 结尾的常量是 double 类型
​ 以 f 结尾的常量(如 3.14f)是 float 类型
*实型变量

​ 单精度(float)和双精度(double)3.1415926753456
​ float 型: 占 4 字节,7 位有效数字,指数-37 到 38
​ 3333.333 33
​ double 型: 占 8 字节,16 位有效数字,指数-307 到 308

格式化输出字符

%d 十进制有符号整数
%u 十进制无符号整数
%x 以十六进制表示的整数
%o 以八进制表示的整数
%f float 型浮点数
%lf double 型浮点数
%e 指数形式的浮点数
%s 字符串
%c 单个字符
%p 指针的值

特殊应用:
%3d %03d %-3d %5.2f
%3d:要求宽度为 3 位,如果不足 3 位,前面空格补齐;如果足够 3 位,此语句无效
%03d:要求宽度为 3 位,如果不足 3 位,前面 0 补齐;如果足够 3 位,此语句无效
%-3d: 要求宽度为 3 位,如果不足 3 位,后面空格补齐;如果足够 3 位,此语句无效
%.2f:小数点后只保留 2 位

构造类型

概念:由若干个相同或不同类型数据构成的集合,这种数据类型被称为构造类型

例:int a[10];

数组、结构体、共用体、枚举

类型转换

数据有不同的类型,不同类型数据之间进行混合运算时必然涉及到类型的转换问题.

转换的方法有两种:

  • 自动转换:遵循一定的规则,由编译系统自动完成.
  • 强制类型转换:把表达式的运算结果强制转换成所需的数据类型

自动转换的原则:
1、 占用内存字节数少(值域小)的类型,向占用内存字节数多(值域大)的类型转换,以保证精度不降低.
2、 转换方向:

image-20231203203709428

  1. 当表达式中出现了 char 、short int 、int 类型中的一种或者多种,没有其他类型了参加运算的成员全部变成 int类型的参加运算,结果也是 int 类型的

    1
    2
    3
    4
    5
    #include <stdio.h>
    int main(){
    printf("%d\n",5/2); //2
    return 0;
    }
  2. 当表达式中出现了带小数点的实数,参加运算的成员全部变成 double 类型的参加运算,结果也是 double 型

    1
    2
    3
    4
    5
    #include <stdio.h>
    int main(){
    printf("%lf\n",5.0/2);//2.500000
    return 0;
    }
  3. 当表达式中有有符号数,也有无符号数,参加运算的成员变成无符号数参加运算结果也是无符 号数.(表达式中无实数)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>
    int main(){
    int a=-8;
    unsigned int b=7;
    if(a+b>0){
    printf("a+b>0\n");
    }else{
    printf("a+b<=0\n");
    }
    printf("%x\n",(a+b));//ffffffff
    printf("%d\n",(a+b));//-1
    return 0;
    }
  4. 在赋值语句中等号右边的类型自动转换为等号左边的类型

    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdio.h>
    int main(){
    int a;
    float b=5.8f;//5.8 后面加 f 代表 5.8 是 float 类型,不加的话,认为是 double 类型
    a=b;
    printf("a=%d\n",a);//a=5
    return 0;
    }
  5. 注意自动类型转换都是在运算的过程中进行临时性的转换,并不会影响自动类型转换的变量的 值和其类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdio.h>
    int main(){
    int a;
    float b=5.8f;//5.8 后面加 f 代表 5.8 是 float 类型,不加的话,认为是 double 类型
    a=b;
    printf("a=%d\n",a);//a=5
    printf("b=%f\n",b);//b 的类型依然是 float 类型的,它的值依然是 5.8
    return 0;
    }

强制转换:通过类型转换运算来实现
(类型说明符) (表达式)
功能:
把表达式的运算结果强制转换成类型说明符所表示的类型例如:
(float)a; // 把 a 的值转换为实型
(int)(x+y); // 把 x+y 的结果值转换为整型
注意:
类型说明符必须加括号

说明:
无论是强制转换或是自动转换,都只是为了本次运算的需要,而对变量的数据长度进行的临时性转换,而不改变数据定义的类型以及它的值

运算符

运算符

​ 用算术运算符将运算对象(也称操作数)连接起来的、符合C语法规则的式子,称为C算术表达式运算对象包括常量、变量、函数等
​ 例如: a* b / c-1.5 + ‘a’

运算符的分类

1、双目运算符:即参加运算的操作数有两个
例:+
a+b
2、单目运算符:参加运算的操作数只有一个
++自增运算符 给变量值+1
—自减运算符

1
2
int a=10
a++;

3、三目运算符:即参加运算的操作数有 3 个
()?():()

算数运算符

+ - * / % += -= *= /= %=
10%3 表达式的结果为 1
复合运算符:
a += 3 相当于 a=a+3
a*=6+8 相当于 a=a*(6+8)

关系运算符

(>、<、= =、>=、<=、!= )
!=为不等于
一般用于判断条件是否满足或者循环语句

逻辑运算符

1、&& 逻辑与
两个条件都为真,则结果为真
if((a>b) && (ab) || (ab)){
}

位运算符

正数在内存中以原码形式存放,负数在内存中以补码形式存放
正数的 原码=反码=补码
原码:将一个整数,转换成二进制,就是其原码。
如单字节的 5 的原码为:0000 0101;-5 的原码为 1000 0101。
反码:正数的反码就是其原码;负数的反码是将原码中,除符号位以外,每一位取反。
如单字节的 5 的反码为:0000 0101;-5 的反码为 1111 1010。
补码:正数的补码就是其原码;负数的反码+1 就是补码。
如单字节的 5 的补码为:0000 0101;-5 的补码为 1111 1011。
在计算机中,正数是直接用原码表示的,如单字节 5,在计算机中就表示为:0000 0101。
负数用补码表示,如单字节-5,在计算机中表示为 1111 1011。
无论是正数还是负数,编译系统都是按照内存中存储的内容进行位运算。

  1. &按位 与
    任何值与 0 得 0,与 1 保持不变
    使某位清 0
    0101 1011&
    1011 0100

​ 0001 0000

  1. | 按位或
    任何值或 1 得 1,或 0 保持不变
    0101 0011 |
    1011 0100


    1111 0111

  2. ~ 按位取反
    1 变 0,0 变 1
    0101 1101 ~


    1010 0010

  3. ^ 按位异或
    相异得 1,相同得 0
    1001 1100 ^
    0101 1010


    1100 0110

  4. 位移

​ >>右移
​ <<左移
​ 注意右移分:逻辑右移、算数右移

(1)右移
逻辑右移 高位补 0,低位溢出
算数右移 高位补符号位,低位溢出 (有符号数)
A)逻辑右移
低位溢出、高位补 0
0101 1010 >>3


​ 0000 1011
​ B)算数右移:
​ 对有符号数来说
​ 低位溢出、高位补符号位。

​ 1010 1101 >> 3


​ 1111 010 1

​ 0101 0011 >>3


​ 0000 101 0

总结 右移:
1、逻辑右移 高位补 0,低位溢出
注:无论是有符号数还是无符号数都是高位补 0,低位溢出
2、算数右移 高位补符号位,低位溢出 (有符号数)
注:对无符号数来说,高位补 0,低位溢出
对有符号数来说,高位补符号位,低位溢出

在一个编译系统中到底是逻辑右移动,还是算数右移,取决于编译器

(2) 左移 << 高位溢出,低位补 0
5<<1
0000 0101


​ 0000 1010

条件运算符号

()?():()
A?B:C;
如果?前边的表达式成立,整个表达式的值,是?和:之间的表达式的结果
否则是:之后的表达式的结果

逗号运算符

(),()

逗号运算符的结果是,后边表达式的结果

自增自减运算符

i++ i—

运算符在变量的后面,在当前表达式中先用 i 的值,下条语句的时候 i 的值改变

++i 先加 ,后用

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main(int argc, char* argv[])
{
int i = 3;
int j = 4;
int num;
int num2;
num = (i++) + (i++) + (i++);//3+3+3,先求和再自增
num2 = (++j) + (++j) + (++j);//7+7+7,先自增再求和
printf("num = %d\ni = %d\n", num,i);
printf("num2 = %d\nj = %d\n", num2,j);
return 0;
}

运算符优先级及结合性

运算符优先级
在表达式中按照优先级先后进行运算,优先级高的先于优先级低的先运算。
优先级一样的按结合性来运算

1
2
int a;
a=2+5+3*4-6

运算符结合性
左结合性:从左向右运算

1
2
int a;
a=2+3+9+10;

​ 右结合性:从右向左运算

1
2
int a,b,c,d;
a=b=c=d=100;

优先级和结合性表:

image-20231203210737143

image-20231203210753782

注:建议当表达式比较复杂的时候,用()括起来,括号的优先级最高,优先算括号里的。

控制语句

选择控制语句

1、 if 语句
形式1:

​ if(条件表达式)
​ {//复合语句,若干条语句的集合
​ 语句 1;
​ 语句 2;
​ }

如果条件成立执行大括号里的所有语句,不成立的话大括号里的语句不执行

形式2:

​ if(条件表达式) { } else { }

​ if else 语句的作用是,如果 if 的条件成立,执行 if 后面{}内的语句,否则执行 else 后的语句

形式3:

​ if(条件表达式 1){ } else if(条件表达式 2){ } else if(条件表达式 3){ } else{ }

​ 在判断的时候,从上往下判断,一旦有成立的表达式,执行对应的复合语句,下边的就不再判断了,各个条件判断是互斥的

2、 switch 语句

switch(表达式)//表达式只能是字符型或整型的(short int int long int

{
case 常量表达式1:
语句1;
break;
case 常量表达式2:
语句2;
break;
default:
语句3;
break;
}

循环控制语句

1、 for 循环
for(表达式 1;表达式 2;表达式 3)
{//复合语句,循环体
}
第一次进入循环的时候执行表达式 1,表达式 1 只干一次,
表达式 2,是循环的条件,只有表达式 2 为真了,才执行循环体,也就是说
每次进入循环体之前要判断表达式 2 是否为真。
每次执行完循环体后,首先执行表达式

2、 while 循环

形式 1:
while(条件表达式)
{//循环体,复合语句
}
进入 while 循环的时候,首先会判断条件表达式是否为真,为真进入循环体,否则退出循环

形式 2 :
do{//循环体
}while(条件表达式);
先执行循环体里的代码,然后去判断条件表达式是否为真,为真再次执行循环体,否则退出循环

形式 1 和形式 2 的区别是,形式 1 先判断在执行循环体,形式 2 先执行循环体,再判断

break 跳出循环
continue 结束本次循环,进入下一次循环

return 返回函数的意思。结束 return 所在的函数,
在普通函数中,返回到被调用处,在 main 函数中的话,结束程序

goto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
int main() {
printf("test01010101\n");
printf("test02020202\n");
//跳转到tmp位置,跳过执行之间的代码
goto tmp;
printf("test03030303\n");
printf("test04040404\n");
printf("test05050505\n");
printf("test06060606\n");
printf("test07070707\n");
tmp:
printf("test08080808\n");
printf("test09090909\n");
return 0;
}