从0开始的C语言
0 简单的了解操作符
算数操作符:+ - * / %
移位操作符:>> <<
位操作符有:& ^ |
赋值操作符:= += -= *= /= &= ^= |= >>= <<=
单目操作符:!- + & sizeof ~ -- ++ * (类型)
关系操作符:> >= < <= != ==
逻辑操作符:&& ||
条件操作符:exp1?exp2:exp3
逗号表达式:exp1,exp2,exp3,…expN
下标引用、函数调用和结构成员:[] () . ->
算数操作符和移位操作符 详见0002
0.1 位操作符
位操作符有:& ^ |
0.1.0 位操作符 “ & ”
位操作符 & 的意思是 (按2进制位)与
与的计算方式是:两个数所对应的二进制位,只要存在一个零,与的结果就为零。
- 例一
int main()
{
int a = 3;
int b = 5;
int c = a & b;//按位与 —— 只要有 0 结果就为 0
//a == 0000 0000 0000 0000 0000 0000 0000 0011 == 3
//b == 0000 0000 0000 0000 0000 0000 0000 0101 == 5
//c == 0000 0000 0000 0000 0000 0000 0000 0001 == 1
printf("%d\n", c);//结果为1
return 0;
}
0.1.1 位操作符 “ ^ ”
位操作符 ^ 的意思是 (按2进制位)异或
异或的计算方式是:两个数所对应的二进制位,相同为0,相异为1。
int main()
{
int a = 3;
int b = 5;
int c = a ^ b;//按位异或 —— 相同为0,相异为1
//a == 00000000000000000000000000000011 == 3
//b == 00000000000000000000000000000101 == 5
//c == 00000000000000000000000000000110 == 6
printf("%d\n", c);
return 0;
}
0.1.2 位操作符 “ | ”
位操作符 | 的意思是 (按2进制位)或
或的计算方式是:两个数所对应的二进制位,存在一个1,或的结果为1
int main()
{
int a = 3;
int b = 5;
int c = a | b;//按位或 —— 只要有1就为1
00000000000000000000000000000011 == 3
00000000000000000000000000000101 == 5
00000000000000000000000000000111 == 7
printf("%d\n", c);
return 0;
}
0.2 赋值操作符
赋值操作符:= += -= *= /= &= ^= |= >>= <<=
0.2.0 “ = ”
" = "的意思是赋值1
注:它和等于的意思不同。
例:
int main()
{
int a = 10;//创建变量a,并且初始化为10.
a = 20;//20赋值给a
return 0;
}
0.2.1 “ += 、-= 、*= 、/= ”
int main()
{
//加等 +=
int a = 10;//创建一个变量a,并切初始化为10.
a += 10;//a加等10
//等价于
a = a + 10;
//减等 -=
a -= 10;//a减等10
//等价于
a = a - 10;
//乘等 *=
a *= 10;//a乘等10
//等价于
a = a * 10;
//除等 /=
a /= 10;//a除等10
//等价于
a = a / 10;
return 0;
}
0.2.2 “ &= 、^= 、|= ”
int main()
{
//与等 &=
int a = 10;//创建一个变量a,并切初始化为10.
a &= 3;//a 与等 3
//等价于
a = a & 3;
//异或等 ^=
a ^= 3;//a 异或等 3
//等价于
a = a ^ 3;
//或等 |=
a |= 3;//a 或等 3
//等价于
return 0;
}
0.2.3 “ <<= 、>>= ”
int main()
{
//左移等 <<=
int a = 10;
a <<= 1;
//等价于
a = a << 1;
//a == 00000000000000000000000000000010
//二进制位向左移动一位
//a == 00000000000000000000000000000100
//右移等 >>=
a >>= 1;
//等价于
a = a >> 1;
return 0;
}
0.3 单目操作符
单目操作符:!- + & sizeof ~ -- ++ * (类型)
0.3.0 “ ! ”
! 的意思是逻辑反操作
C语言的判断真假:非 0 就是真,0就是假。
例如5是真,0是假。
int main()
{
int a = 10;
if(a)//a为真,进入if语句
{
}
if(!a)//a为假,进入if语句
{
}
return 0;
}
0.3.1 “ + 、- ”
正号 +
负号 -
int main()
{
int a = 10;
int b = -a;//负值
int c = a;//正号(+)一般省略
return 0;
}
0.3.2 “ & ”
& - 取地址操作符,学指针时学习。
0.3.3 “ sizeof ”
sizeof - 操作数的类型长度(以字节为单位)
int main()
{
int a = 10;
printf("%d\n",sizeof(a));//结果为4字节
printf("%d\n",sizeof(int));//结果为4字节
return 0;
}
0.3.4 “ ~ ”
~ 是对一个数的二进制位按位去反。
例一:为什么打印结果是-1呢?
int main()
{
int a = 0;
printf("%d\n",~a);//结果打印为-1
//00000000000000000000000000000000 == a
//~ 按位取反
//11111111111111111111111111111111 == 4294967295
return 0;
}
补充:整数在内存中储存的时候,存储的是二进制。
一个整数的二进制表示有3种形式:原码、反码和补码。
正的整数:原码、反码、补码都相同。
负的整数:原码。反码。补码需要计算。
例:
int main()
{
//有符号的整数,最高位是0,表示正数.
int a = 1;//int a 是4个字节,也就是32个比特位
//原码 = 00000000000000000000000000000001
//反码 = 00000000000000000000000000000001
//补码 = 00000000000000000000000000000001
//有符号的整数,最高位是1,表示负数.
a = -1;
//原码是:根据这个数的真实值,结合符号位,得出的
//原码 = 10000000000000000000000000000001
//反码是:符号位不变其他位按位取反,得出的
//反码 = 11111111111111111111111111111110
//补码是:反码的二进制序列加一,得出的
//补码 = 11111111111111111111111111111111
return 0;
}
内存中存储整数的时候,存储的是补码,计算的时候采用的也是补码。
例一中按位取反后,得到的是a的补码,所以要补码转换为原码,再打印出来。
int main()
{
int a = 0;
printf("%d\n",~a);//结果打印为-1
//00000000000000000000000000000000 == a
//~ 按位取反
//11111111111111111111111111111111 ——补码
//补码减一,得到反码
//11111111111111111111111111111110 ——反码
//反码符号位不变,按位取反,得到原码
//10000000000000000000000000000001 ——原码
return 0;
}
所以结果为-1;
0.3.5 “ ++ ”
++分为
前置++ 和 后置++
int main()
{
int a = 2;
//前置++ ,先++,后使用
int c = ++a;
printf("c = %d\n", c);//3
printf("a = %d\n", a);//3
//后置++ ,先使用,后++
int c = a++;
printf("c = %d\n", c);//2
printf("a = %d\n", a);//3
return 0;
}
0.3.6 “- -”
–分为
前置–和后置–
int main()
{
int a = 2;
//前置-- ,先--,后使用
int c = --a;
printf("c = %d\n", c);//1
printf("a = %d\n", a);//1
//后置-- ,先使用,后--
int c = a--;
printf("c = %d\n", c);//2
printf("a = %d\n", a);//1
return 0;
}
0.3.6.0 注意不可取的++ --问题
有一些代码,虽然编译器可以编译过去,但是每个编译器的计算结果不同,所以这些代码是不可取的、是错误的代码
如:
//不可取的代码
//每个编译器结果不同 gcc 的结果是 10;
int main()
{
int a = 1;
int b = (++a) + (++a) + (++a);
printf("b = %d\n", b);//vs的结果是12
return 0;
}
//错误的代码
int main()
{
int a = 10;
printf("%d %d\n", --a, --a);//8 8
return 0;
}
0.3.7 “ * ”
间接访问操作符(解引用操作符),在指针部分学习。
0.3.8 “(类型)”
强制类型转换-尽量避免,能不使用就不要使用。
int main()
{
int a = (int)3.14;
printf("%d\n", a);//3
return 0;
}
0.4 关系操作符
关系操作符有:
大于 >
等于 ==
小于 <
不等于 !=
大于等于 >=
小于等于 <=
0.5 逻辑操作符
逻辑操作符有:
逻辑与 && 相当于并且的意思
逻辑或 || 相当于或者的意思
用法:
int main()
{
int a = 3;
int b = 4;
if ((a == 3) && (b == 4))
{
printf("哈哈\n");
}//当a等于3并且b等于4时,打印哈哈
if ((a == 3) || (b == 4))
{
printf("呵呵\n");
}//当a等于3或者b等于4时,打印呵呵
return 0;
}
0.6 条件操作符
条件操作符 也叫 三目操作符
用法:
int main()
{
int a = 10;
int b = 0;
if (a == 5)
{
b = -6;
}
else
{
b = 6;
}
//相当于
b = ((a == 5) ? (-6) : (6));
// 如果a ==5 ,b ==-6 否则 b==6。
return 0;
}
0.7 逗号表达式
逗号表达式从左向右依次计算,整个逗号表达式的结果是最后一个表达式的结果
例题:
int main()
{
int a = 0;
int b = 3;
int c = -1;
int d = (a = b - 5, b = a + c, c = a + b, c -= 5);
//a = 3-5 = -2
//b =(-2)+(-1)= -3
//c = (-2) + (-3) = -5
//c = c - 5 = -5 - 5 = -10
printf("%d\n", d);// 打印的结果为-10
return 0;
}
0.8 下标引用、函数调用和结构成员
下标引用、函数调用和结构成员:[] () . ->
结构成员. ->
,这两个操作符,在学习结构体时学习。
用法:
int Add(int x, int y)
{
return x + y;
}
void test()
{
}
int main()
{
//[]下标引用
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//数组的下标从0开始数,arr[0]代表的是1,arr[6]代表的是7
printf("%d\n", arr[9]);//10
//arr和9是[]的操作数
//()函数调用操作符
printf("hehe\n");
int ret = Add(3, 5);
test();
return 0;
}
1. 常见的关键字
1.0类型关键字:
- char 字符
- short 短整型
- int 整型
- long 长整型
- folat 单精度浮点型
- double 双精度浮点型
- void 空类型也是无的意思
1.1 循环语句关键字
- break 意思是跳出、停止、中断。用于循环语句和switch语句
- continue 的意思是继续 只能用于循环语句
- do 用于 do while 循环
- for 用于for循环语句
- while用while循环语句
1.2 选择语句关键字
- case 用于 switch case 语句,同switch一起使用
- default 用于switch语句的默认选项。
- else 用于if else语句
- goto是跳转的意思,可以实现分割的效果,也可以实现循环
- if 用于if else语句
- switch 用于switch语句
1.3 数据类型关键字
- enum 枚举关键字
- struct 结构体关键字
- union 联合体也叫共用体
1.4 其他常见的关键字
- auto(自动)自动变量
- const 常属性
- extern 声明外部符号的
- register 寄存器
- return 返回 应用到函数
- signed 有符号数
- unsigned 无符号的
- sizeof 计算所占内存空间大小的
- static 静态的,用来修饰变量,函数等
- typedef 类型重定义
- volatile 易变得。在学习linux时学习
2.简单了解4个关键字
2.0 auto
auto是自动的意思,在C语言中的意思为自动变量。
一个局部变量变量进入局部作用域时创建,出局部作用域时销毁,所以局部变量也称为自动变量,也就是说所有的局部变量都是自动变量,所以一般省略auto。
int main()
{
auto int a = 10;
return 0;
}
2.1 typedef
typedef顾名思义是类型定义,也可以理解为类型重命名。
比如,某个工程中用到很多个无符号数,但是unsigned int 每次写很麻烦,所以可以用typedef简化它,如简化为unit
typedef unsigned int unit;
int main()
{
unsigned int num = 100;
unit num2 = 200;
return 0;
}
2.2 register
register(寄存器)是存储空间 ,一般集成在CPU中,不同于内存,是独立的存储空间。
用法:
int main()
{
register int num = 100;
//建议把100存放在寄存器中,由编译器最终决定,是否存入寄存器
#//错误,取地址的取是取内存的地址
return 0;
}
2.3 static
static 在C语言中的用法:
1.修饰局部变量
2.修饰全局变量
3.修饰函数
- 修饰局部变量用例:
在没有用static修饰时,代码运行结果是这样的:
void test()
{
int a = 1;
a++;
printf("%d", a);
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
}
return 0;
}//运行结果为 2222222222
用static修饰后:
void test()
{
//static修饰局部变量
static int a = 1;
a++;
printf("%d ", a);
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
}
return 0;
} //运行结果为 2 到 11
结论:static修饰局部变量时,改变了变量的生命周期,但不影响作用域。
- 修饰全局变量用例
创建两个源文件,test1.c和 test2.c
在test1 定义一个全局变量int g_val = 2021;
在test2 中可以正常打印
//声明外部符号 extern
extern int g_val;
int main()
{
printf("%d\n", g_val);
return 0;
}
当static修饰全局变量时static int g_val = 2021;
test2不能正常打印
结论:默认的一个全局变量是具有外部链接属性的。而如果全局变量被static修饰,使得全局变量的外部链接属性变成了内部链接属性,这个时候这个全局变量只能在本源文件内部使用,其他源文件无法链接到,也无法使用。
- 修饰函数用例
test 1 中写入一个Add函数:
int Add(int x, int y)
{
return x + y;
}
test 2写入如下代码:
extern int Add(int x,int y)
int main()
{
int a = 10;
int b = 20;
int c = Add(a, b);
printf("%d\n", c);
return 0;
}
这个函数可以正常调用。
但加上static修饰时:
static int Add(int x, int y)
{
return x + y;
}
运行后:
结论:函数是具有外部链接属性的,但如果被static修饰,外部链接属性就变成了内部链接属性,就不能在其他源文件中使用
3. define 定义的常量和宏
//define定义标识符常量
#define NUM 100
//define定义宏
#define MAX(X,Y) (X>Y?X:Y)
int main()
{
printf("%d\n", NUM);
int a = 10;
int b = 20;
int c = MAX(a , b);
//这句代码,会被替换成宏体
int c = (a > b ? a : b);
int c = MAX(a+2, b);
//如果是a+2,替换时替换成a+2,而不是一个整体
int c = (a+2> b ? a+2 : b);
printf("%d\n", c);
return 0;
}
总结
所有知识仅为了解,之后再仔细学习。
是将某一数值赋给某个变量的过程。 ↩︎