前言:
- 想学好C的原因:
- 为考研复试做准备
- 高级语言似乎大同小异,只要把C的框架描绘得足够清楚,学别的语言就只需要改动枝叶(语句的书写方式、学习不同的库函数)
- 为接下来的FPGA学习做出准备
- 声明:内容主要来源于作者对C程序设计(第五版) 的学习,之后还会添加对C Primer Plus(第六版) 的学习内容。
- 在学习阶段能力有限,希望我的错误可以得到大家的指正。
基础语法
语法规则
输入、输出问题
printf("%m.nf", a)
m表示至少占的宽度,输出是向右停靠的;n表示保留的小数位数;a可以是表达式也可以是变量。- “”表示字符串,’‘表示字符,
printf
中一定要使用”“ putchar()
与getchar()
,对字符串的输出输入
typedef
- 用于创建新的类型:
typedef struct;
- 用于简写:
typedef unsigned char BYTE;
语句
- 控制语句
- 条件:if、switch
- 循环:for、while
- 调用语句
- 表达式语句
- 需加上
;
- 对数:
lg10(p)
表示以10为底的log p - 指数:
pow(m,n)
表示m的n次幂
- 需加上
- 空语句
- 复合语句
运算符
- 优先级:非>算术运算符>关系运算符
>
>逻辑运算符&&
>赋值运算符==
- 单目:
!
,双目:&&
,三目:?
- ++:
M = (i++)
;执行后i会加一,M=i-1;不同于M = (++i)
-先加再赋值(从左到右) - 三目运算符:
表达式1?表达式2:表达式3
当1成立时,运算2 - 编译逻辑:1为真,0为假。逻辑运算符的逻辑:非0为真,0为假,如:
!4
为0
定义新类型
函数模块化
函数
返回类型 函数名(形参){
声明
语句
}
- 函数被调用时使用的变量是实参
- 形参可以是数组,与指向首位的指针等价
(float c[10])
=(float *c)
变量
-
作用域:某个变量名字可用的代码范围
-
生存期:变量值存在的时间
-
块:一个花括号
{}
就是一个块。 -
链接:使程序的不同部分可以调用变量
- 外部链接:跨文件的变量使用
- 内部链接:仅供一个文件中的函数调用(有static声明的变量一般是,具有信息隐藏的作用)
- 无链接
-
声明类型:
auto、static、register
(将变量放在CPU中加速处理)、extern
-
局部
- 通常来说,变量的作用域和生存期都是在一个块内。
- 静态局部变量:
int static n
作用域没有改变,但特点在于:生存期贯彻程序始终。表现在:在反复调用一个函数时,若需要n++之类的,会用到它。
-
全局
- 声明就在
#
下面,独立于所有函数。 - 可以被其他函数使用、更改。
- 栈用全局变量建立,之后函数可以写压栈(入栈)、出栈、判满、判空等
- 跨文件的全局要如此引入(声明):
extern A;
- 声明就在
结构体类型
-
意义:
- 定义一种不属于内部的变量类型。
- 根据成员分配空间。
- 帮助有内在联系的数据归类。(多维数组也可以做到)
-
定义方式
- 如图(ps:结构名需大写,表示非系统提供类型)
- 众变量放结构体的首行
struct 结构体名
{众成员
}众变量名;
struct Student
{
int no;
char name[12];
}student1,student2;
-
初始化方式
- 在结构体中
student1={};
- 在结构体外
struct Student student1 ={};
- 对成员的赋值:成员运算符为
.
student1.name="Li";
- 在结构体中
-
结构体与其他类型
- 数组
- 众变量名换为数组
- 一维时,根据众成员依次赋值
student[2]={"Li",20,"Zhao",30};
- 多维时,每行表示一个变量
student[2]={{},{}};
此外,交换行时,临时变量需要定义成结构体类型:struct Student temp;
- 指针
- 定义:
struct student *p; p=&student1;
此时p指向的是一段与结构体等字节的空间。 - 用法:
(*p).name
与p -> name
等价。p++
表示下一个结构体,与多维数组配合使用。
- 定义:
- 数组
数据结构
补码
while(~scanf("%d",&n))
scanf
是输出,返回值为输入的个数如printf("%d",scanf("%d",&n));
管你输入什么返回都为1,会自动换行&
表示地址位%
表示数值d
表示数值取十进制,详见这里- 相当于
while(scanf("%d",&n)!=EOF)
,其中EOF(end of file)相当于None,地址位为-1 ~
是取反:~1+(-2的补码)=-0
,~(-1)=-0
十进制的1 | 十进制的-2 | -1 | 0 | |
---|---|---|---|---|
源码 | 00000001 | 10000010 | 10000001 | 00000000 |
反码 | 00000001 | 11111101 | 11111110 | 00000000 |
补码 | 00000001 | 11111110 | 11111111 | 00000000 |
- 对于正数原码、反码以及补码是其本身。负数的原码是其本身,反码是对原码除符号位之外的各位取反,补码则是反码加1。
- 计算机只认识补码,因此x取反实则:1.x的补码取反(除符号位),得到y的补码。2.解出y。
数据类型
-
数值数组
- Why?解决了繁琐的多变量定义问题;体现出变量间的联系。
- 不支持动态定义
int a[n]
- 全0初始化
int a[10] = {0};
- 数组赋值要写在定义处
char a[]={1,2,3}
,否则之后的a[4]就仅代表一个数。 - 注意定义的大小和可用的量:
int a[10] ={0}
中a[10]是不存在的 - 函数调用时无法直接返回数组,但可以用返回c[0]处的指针再现数组。
-
字符型数组char a[10]={“a”,“b”};
-
数据类型的零碎知识
-
对于单字符、-9~9的数组,如果用int则浪费内存。
-
[10]可以空[],单个字符可以合并成字符串{“ab”}。
-
输入scanf("%s",c); 其中%s表示字符串,不可写&c,因为&c指代&c[0]
-
浮点型需注意:1.小数点不可省略(a = 300.)2.表示指数时E前后都要有数字(a = 1E-2)
-
浮点型的单、双精度:单精度为二进制32位:1位符号,8位指数,23位小数;双精度为64位:1位符号,11位指数,52位小数。
-
并不是说char只能存字符,char只有一字节,则可以存一个字符也可以存数字,否则会出现overflow,数字只有-9~+9
-
‘B’>='A’
会把B、A转为ASCLL码比较
-
指针
- what:直接访问是:
i = 2;
间接访问是先从地址下手:pointer = &i; *pointer = 2;
指针可以通过地址,在调试、中断过程中发挥作用。 - pointer称为指针变量,它用来指针的地址。
- *pointer是指针,表示这pointer所指向的变量。
- pointer与&a中都存放着地址与数据类型,因此,指针必须与变量同类型(不可用整型指针
int *p
指向浮点型变量float i
) - 指针在定义处必须定义指针变量的具体值(地址)
- 指针与数组
a[i]
与*(a+i)
等价,运行速度也一样,而p=&a;for;*(p++)
更快,因为,后者不需要总是去计算地址。p+1
表示在当前地址上+该指针数据类型的字节数。*p++
中++
与*
优先级相同,程序自右向左,等价于*(p++)
:先对p运算再以p++结束。区别*++p
:让p++再对p操作。- 初始化时int
*p=&a;
或int *p = a;
都等价于int *p; p=&a[0]
- 字符串的指针使用、定义都与数组类似。%s表示从当前指针位置一直索引到“\0”
文件
- WHAT:文件是存储在外部介质的数据集合(操作系统上每个输入输出设备都被看作文件)
- 传输:根据微机原理,文件的传输是从源地址先传输到文件缓存区,满了之后再传输到目标地址中。
- 分类:程序文件、数据文件
- 其中数据文件又分为ASCII文件、二进制文件
- 数据文件的存储:数据在内存中通通会映射成二进制数,直接存储就是二进制文件,又称映像文件。把数据转换成ASCII即ASCII文件,又称文本文件。
- 打开关闭
- “好像打开门才能进房子,门关闭就无法进入了一样,所谓打开是指创建相应的信息区于文件缓存区”
<stdio.h>
中可用FILE类型定义文件的结构体变量,由于fopen
函数返回的是指针类型,因此通常用FILE定义一个文件指针FILE *fp
- 打开方式:
fopen(文件名,使用方式)
,使用方式有‘r’、‘w’…,返回值为文件指针。 - 关闭:
fclose(文件指针)
- <stdio.h>中定义:NULL=0,EOF(end of file)=-1
内置函数
- 随机播种:
srand((unsigned)time(NULL));