目录
操作符
算数操作符:+ - * / %--加、减、乘、除、取余
举例:
int main()
{
float a = 5 / 2.0;//商2余1
printf("%f\n", a);// 想要得到小数5/2.0
return 0;
}
要想除得到小数,必须在除号的左边或者右边,有小数点。
移位操作符:<< >>--左移、右移
移位,移动二进制位,现在拿左移来举例
6----0110 向左移位后 1100--12
int main()
{
int a = 6;
int b = a << 1;
//移动的是二进制位
//00000000 00000000 00000000 00000110
//左移 00000000 00000000 00000000 00001100 --12
printf("%d\n", b);
printf("%d\n", a); //a是不变的
return 0;
}
注意上面代码中,移位后a的值是不变的。
位操作符:&--按位与 ^--按位异或 |--按位或
举例:
int main()
{
int a = 3;//0011
int b = 5;//0101
int c = a&b;//与有0就是0,0001
int d = a^b;//异或相同为0,不同为1;0110
int e = a | b;//或--有1就是1,0111
printf("%d\n", c);//c=1
printf("%d\n", d);//d=6
printf("%d\n", e);//e=7
return 0;
}
赋值运算符:= += -= *= /= &= ^= |= >>= <<=
举例:
int main()
{
int a = 10;//a初始化10
a = 20;//赋值
a = a + 10;
a += 10;//复合赋值
a = a - 8;
a -= 8;
a = a >> 1;
a >>= 1;
return 0;
}
单目操作符:
!就是取反,如果本身为真,加!就为假。
- +很容易理解,&和*后面会在指针部分讲解。
siezof求操作数所占的字节数。
举例:
int main()
{
int a = 10;
//siezof也是操作符
printf("%d\n", sizeof(a));//4
printf("%d\n", sizeof(int));//4
return 0;
}
想要理解~,这里首先讲解几个只是点:
整数在内存中存储的时候,存储二进制。
一个整数的二进制表示有3种形式:
原码
反码
补码
正的整数,原码、反码、补码相同
负的整数:原码、反码、补码计算
有符号的整数,最高位是0表示正数,最高位是1表示负数
int a = 1;
00000000 0000000 00000000 00000001--原码/反码/补码
int a = -1;
10000000 00000000 00000000 00000001--原码
11111111 11111111 11111111 11111110--反码--原码的符号位不变,其他位按位取反
11111111 11111111 11111111 11111111--补码--反码加1
内存种存储的是二进制的补码
计算的时候采用的也是补码
举例:
int main()
{
int a = 0;
//~对一个数的二进制按位取反
//00000000 00000000 00000000 00000000
//11111111 11111111 11111111 11111111--补码
//11111111 11111111 11111111 11111110--反码
//10000000 00000000 00000000 00000001--原码
printf("%d\n", ~a);//-1
return 0;
}
前置++表示先++,后使用,后置++表示先使用,后++。--的道理是相同的。
举例:
int main()
{
int a = 2;
int b = 2;
//++ --
//++ 前置++ 后置++
int c = ++a;//前置++,先++,后使用
int d = b++;//后置++,先使用,后++
printf("%d\n", c);//3
printf("%d\n", a);//3
printf("%d\n", d);//2
printf("%d\n", b);//3
return 0;
}
强制转换类型
举例:
int main()
{
int a = (int)3.14;//强制类型转换
printf("%d\n", a);//3
return 0;
}
3.14是一个浮点型,先要赋值给一个整型变量,必须进行强制转换。
关系操作符:
逻辑操作符:&& --逻辑与-并且 、|| --逻辑或-或者
&&与--左右两边都要满足条件,||--有一边满足条件即可。
举例:
int main()
{
int a = 3;
int b = 4;
/*if (a == 3 && b == 4)
{
printf("haha\n");
}*/
if ((a == 3) || (b == 4))//
{
printf("haha\n");
}
return 0;
}
条件操作符:exp1?exp2:exp3
它表示exp1成立就执行exp2,否则执行exp3.
举例:
int main()
{
int a = 10;
int b = 0;
if (a == 5)
{
b = -6;
}
else
{
b = 6;
}
b = ((a == 5) ? -6 : 6); //同上面写法
return 0;
}
逗号表达式:逗号表示是会从左到右依次计算,结果是最后一个表达式的结果。
举例:
int main()
{
int a = 0;
int b = 3;
int c = -1;
//,--逗号表达式
//逗号表示是会从左到右依次计算
//整个逗号b表达式的结果是最后y一个表达式的结果
//a=-2 b=-3 c=-5 c=-10
int d = (a = b - 5, b = a + c, c = a + b, c -= 5);
printf("%d\n", d);
return 0;
}
下标引用操作符:
举例:
int main()
{
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
arr[9];//[]下标引用操作符
//arr 9 是[]的操作数
return 0;
}
常见关键字
这里先简单介绍几个:
1.auto 一般会省略
2.typedef--别名
举例:
typedef unsigned int uint; //别名
int main()
{
uint num = 100;
return 0;
}
3.register--寄存器关键字
举例:
int main()
{
//建议把100存放在寄存器当中,编译器最终来决定
register int num = 100;
return 0;
}
4.static
- 修饰局部变量
- 修饰全局变量
- 修饰函数
局部变量举例:
void test()
{
//static修饰局部变量
//改变了变量的生命周期,但是不影响作用域
static int a = 1;//a出了生命周期也不销毁了
a++;
printf("%d\n", a);//2-11
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
}
return 0;
}
上面代码中,static修饰局部变量a,会改变a的声明周期。
全局变量和函数举例:
extern int g_val;
int main()
{
printf("%d\n", g_val);//如果用static修饰了g_val就会报错
return 0;
}
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修饰,使得全局变量的外部链接属性就变成了内部链接属性
//所以这时全局变量只能在本文件内部使用,其他源文件无法链接,也无法使用
static int g_val = 2021;
//函数具有外部链接属性
//如果被static修饰,外部链接属性就变成了内部链接属性
//所以这时函数只能在本文件内部使用,其他源文件无法链接,也无法使用
static int Add(int x, int y)
{
return x + y;
}
/默认的全局变量是有外部链接属性的,如果被static修饰,使得全局变量的外部链接属性就变成了内部链接属性,所以这时全局变量只能在本文件内部使用,其他源文件无法链接,也无法使用。函数也是同样的道理。
define定义常量和宏
举例:
#define NUM 100
#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);
printf("%d\n", c);
return 0;
}
指针
我想我一提到指针,很多人都觉的很难理解,其实它并不是很难,你要去理解它的原理,并且指针对我们C语言来说是非常重要的。
首先说一个概念就是内存,计算机中程序运行就是在内存中进行的,你可以把内存想象成一个大的方格,我们需要合理利用内存空间,就需要把内存分成小的内存单元,如图:
第一个箭头中,表示把内存分为一个个小的单元,每个小的内存单元是一个字节。
第二个箭头是表示每个小的内存单元都有自己所对应的地址。
举一个指针的例子来理解指针:
int main()
{
int a = 10;
//printf("%p\n", &a);//&取地址操作符
int* pa = &a; //*表示pa是指针变量,int表示pa所指的对象a是int类型
//pa是一个存放地址的变量--叫指针变量
*pa = 20;//*--解引用操作符 可以理解为*pa=a
printf("%d\n", a);//20
char ch = 'w';
char* pc = &ch;
*pc = 'b';
printf("%c\n", ch);
return 0;
}
int a=10,表示在内存中占用了4个小的内存单元,&a就是取a的地址。
int * pa = &a; *表示pa是一个指针变量,它存放的是a的地址,int表示pa所指向的对象a是int类型,*pa=20; 这里*表示解引用操作符,你可以理解*pa=a,将a里面的内容变成了20.
下面拿图表示:
上图201-204表示地址,其实计算机中地址是拿16进制写的,这里为了方便理解,就取10进制数字,a是整型占了4个字节,a里面放着是10,pa是一个指针变量,pa存放的是a当前地址的首地址。*pa=20就是把a存放的10变成了20.
指针变量的大小
指针变量是存放的是地址,所以取决于地址线,如果是32位机器,就是4个字节,如果是64位机器,就是八个字节。
举例:
int main()
{
printf("%d\n", sizeof(char*));//4 32位机器32根地址线,指针变量是存放地址,地址是4个字节,所以指针变量也是4个字节
printf("%d\n", sizeof(short*));//4
printf("%d\n", sizeof(int*));//4
printf("%d\n", sizeof(long*));//4
printf("%d\n", sizeof(float*));//4
printf("%d\n", sizeof(double*));//4
return 0;
}
结构体
结构体可以用来描述复杂对象。struct是结构体类型的关键字。
举例:
struct student
{
char name[20];
int age;
char sex[5];
char id[12];
};
//创建书
struct Book
{
char name[20];
int price;
char author[20];
};
int main()
{
//创建了一个结构体变量--struct student
struct student s1 = {"张三",20,"男","20200506"};
struct student s2 = { "李四", 30, "女", "20200908" };
struct Book b1 = {"c语言程序设计",55,"谭浩强"};
printf("名字:%s 年龄:%d 性别:%s 学号:%s\n", s1.name, s1.age, s1.sex, s1.id);
//.操作符--结构体变量.成员名
struct student* pb = &s1;
printf("名字:%s 年龄:%d 性别:%s 学号:%s\n", (*pb).name, (*pb).age, (*pb).sex, (*pb).id);
printf("名字:%s 年龄:%d 性别:%s 学号:%s\n", pb->name, pb->age, pb->sex, pb->id);
//->指向成员的内部
//->--结构体指针->成员名
return 0;
}
上面代码建立了一个学生结构体类型和书结构体类型,
struct student s1 = {"张三",20,"男","20200506"};
struct Book b1 = {"c语言程序设计",55,"谭浩强"};
这个struct student 是一个结构体类型 s1是结构体变量,要想输出结构体里面的内容,需要用.操作符,结构体变量.成员名。
但是当我们只知道结构体变量的地址时,我们输出有两种写法:
struct student* pb = &s1;
printf("名字:%s 年龄:%d 性别:%s 学号:%s\n", (*pb).name, (*pb).age, (*pb).sex, (*pb).id);
printf("名字:%s 年龄:%d 性别:%s 学号:%s\n", pb->name, pb->age, pb->sex, pb->id);
下面这种是更加简便的。
->指向成员的内部
->--结构体指针->成员名