自学C语言笔记

占位符

  • %d 以十进制的形式打印整数
  • %c 打印字符
  • %f 打印小数
  • %s 打印字符串
  • %zu 打印sizeof计算的结果
  • %p 打印地址
  • int 整型
  • char 字符类型

转义字符:

  • \n 换行
  • \0 字符串的结束标志
  • \t ‌作用是水平对齐

数据类型:

①内置类型:

  • 字符型:char
  • 整型:short,int,long,long long
  • 浮点型:float,double,long double

②自定义类型:

  • 数组
  • 结构体-struct
  • 枚举-enum
  • 联合体-union

关于scanf

scanf("%d", &age) &--取地址操作符,取出age的地址

当变量为char字符数组,使用指针接收数据时不需要加&号

vs中使用无法直接使用scanf,需要加#define _CRT_SECURE_NO_WARNINGS在文件的第一行
一劳永逸的方法:让每个.c文件自动加上这段话。在newc++file.cpp 中加上:#define _CRT_SECURE_NO_WARNINGS后生成的文件自动就有这句话了。

scanf读double类型时必须使用%lf,不能用%f

运算符

=号表示赋值,==号表示判断是否相等

分支

1.默认if和else语句中默认都只控制一条语句

2.else总是跟它最近的if匹配

3.switch语句用于判断条件有多个结果的情况。

switch (expression) { case value1: statement case value2: statement ... default: statement }
  • 根据expression不同的值,执行相应的case分支。如果找不到对应的值,就执行default分支。
  • switch后的expression必须是整型表达式,即结果是整数。
  • case后的值必须是整型常量表达式,即结果是整数,而且编译器在编译时就能确定这个结果。
  • case和后面的值之前必须有空格。
  • 找到对应case后需要break才可跳出switch。

循环

①for:

格式:

for(表达式1;表达式2;表达式3;)

  • 表达式1用于循环变量的初始化
  • 表达式2用于循环结束条件的判断
  • 表达式3用于循环变量的调整

eg:

for (i=1; i<11; i++)

②do-while 使用较少

格式:

do

{

}

while()

③break和continue语句

  • break:作用于永久的终止循环,只要break执行,直接就会跳出循环,继续往后执行
  • continue:作用是跳过本次循环,continue后面的代码

④go to语句

格式:go to xxxx;

xxxx:

数组

概念:一组相同类型元素的集合

  • 数组中存放的是1个或者多个数据,但是数组元素个数不能为0
  • 数组中存放的多个数据,类型是相同的
  • 数组分为一维数组和多维数组

一维数组创建基本语法:

type arr_name[常量值];

  • type指定的是数组中存放数据的类型,可以是:char,short,int等,也可以是自定义类型
  • arr name为数组名字,随意取
  • 常量值用于指定数组的大小

数组初始化:

  • 一般使用大括号,将数据放在大括号中,使用逗号隔开
  • 数组初始化后,数组的大小可以省略

数组的下标:

  • 数组具有下标,下标从0开始,若有n个元素,则最后一个元素的下标为n-1
  • C语言中数组的访问提供了一个操作符:[],叫作下标引用操作符
  • 下标访问操作符可以访问到数组的元素,例如访问下标为7的元素,可以使用

arr[7]

若为下标为3的元素,可以使用

arr[3]

二维数组:

type arr_name[常量值1][常量值2];

eg:

int arr[3][5];

3表示数组有3行 5表示每一行有3个元素

函数

函数的声明和定义:使用函数必须先声明,随后定义

eg:

int is_leap_year(int y);//函数声明

int main()

{

if(int is_leap_year(year);//函数调用
...

}

int is_leap_year(int y);//函数定义

{

...

}

  • 顺序不可变,main函数在前,否则会报错
  • 括号内的形参和实参可以不同
  • 如果想在多个源文件中调用同一个函数,可以将函数声明放在.h头文件中,将函数定义放在.c源文件中。其他源文件通过#include"xxx.h"引入头文件,并在编译、链接时包含实现该函数的源文件

双引号""包含的是自己创建的头文件
<>包含的是标准库的头文件

操作符

分类:

  • 算术操作符:+-*/%
  • 关系操作符 :><>=<===!=
  • 逻辑操作符:&&||
  • 位操作符:&|^~<<>>
  • 赋值操作符:=+=-=*=/=%=
  • 条件操作符: ? :
  • 逗号操作符:,
  • 求大小操作符:sizeof
  • 指针相关操作符:&*
  • 成员访问操作符:.->
  • 下标操作符:[]
  • 函数调用操作符:()
  • 类型转换操作符:(类型)

移位操作符移的是二进制的位

按位与&:有0则为0,同时为1则为1

eg:a为00110001

b为00101001

a & b =00101001

按位或|:有1则为1,同时为0则为0

eg:a为00110001

b为00101001

a | b =00111001

按位异或^:相同为0,相异为1

eg:a为00110001

b为00101001

a ^ b =0001100

指针

int a = 100;

int* p =&a;

printf("%d\n", *p);//*号是解引用操作符,*p的意思是通过p里边存放的地址,找到p指向的对象,也就是a
输出为100

  • 指针变量大小与类型无关,只跟所处环境有关。例如x64环境中,输出的指针大小都是8个字节
  • 指针-指针得到的是指针和指针之间的元素个数,前提是两个指针指向同一个空间
  • 数组名是数组首元素的地址:&arr[0] == arr
  • 指针就是地址,地址就是编号,编号就是大小

const修饰指针:

const是常属性的,即不能被改变

eg:

正常输出100报错

但是,若是利用指针,则可改变

eg:

然而,const的位置改变也有相应的变化

  • 放在*的左边:const修饰的是指针变量指向的内容,不能通过修改指针变量修改它指向的内容但是指针变量的指向是可以修改的

eg:

报错

正常

  • 放在*的右边:const修饰的指针变量本身,指针变量的指向不能修改,但是指针指向的内容是可以通过指针来改变的

报错

正常

区别:左边的约束的是*p,右边约束的是p


一级指针:int* p;char* pc;

二级指针:

指针数组:存放指针的数组

字符指针变量:

char ch = 'A'; char *p = &ch;

数组指针变量:

int arr[3] = {10, 20, 30}; int (*p)[3] = &arr;

函数指针变量:

int add(int a, int b) //定义函数 { return a + b; } int main(void) { int (*p)(int, int) = add; //定义函数指针 printf("%d\n", p(3, 5)); return 0; }

结构体

结构体的声明、创建和初始化:eg:

struct stu { char name[20]; //名字 int age; //年龄 char id[20]; //学号 char sex[2]; //性别 }; struct stu s1; //全局变量 int main() { struct stu s2 = { "张三", 20 ,"202621734455", "男" }; //局部变量 printf("name: %s\n", s2.name); printf("age: %d\n", s2.age); printf("id: %s\n", s2.id); printf("sex: %s\n", s2.sex ); return 0; }

结构体指针

Node a;

Node *p = &a;

p->data = 10; // 通过指针改 a

等价关系(背下来):

p->data ≡ (*p).data

p->next ≡ (*p).next

顺序表:给数组套一个"当前用了多少"的壳

  • 顺序表是线性表的一种实现:用一段连续内存依次存放数据元素,再用一个变量记录"当前装了几个"
  • 顺序表实际上是数组+一个size变量

链表节点:数据+下一个节点的地址

代码里要记住三件事:structNode是节点类型;structNode *next是指向同类型节点的指针;NULL表示"后面没有节点了",也就是链表的结尾。

链表与数据表之间的区别

栈

单片机栈空间有限:局部大数组、深递归、中断嵌套都会把栈用爆。

void FunctionA(void)

{

int a = 10;

FunctionB(); // 嵌套调用

}

队列:先到的,先被处理

环形队列:让数组头尾相连

环形缓冲区

数组buffer有64 个元素,下标是0~63。取余就是为了让下标到达63后,下一步回到0,形成循环。

环形缓冲区+ 串口:中断收、主循环解、

其他:

system 函数是用来执行系统命令的
strcmp 两个字符串比较相等使用strcmp

如果(p+i)和name相等,那么就会 == 0

volatile和static都能放在变量声明中,但作用不同:

  • volatile:告诉编译器,这个变量可能被当前代码之外的因素改变,读写时不能随意省略访问。
  • static:根据位置不同,可以让局部变量保留数值,或者限制变量、函数只能在当前.c文件中使用。