r=j;
2.多维数组
二位数组的行与列:
inta[r][v];r—行,v—列;
可以将二位数组a[3][4]理解为含有三个元素:
a[0],a[1],a[2],每个元素a[i]都是包含四个元素的一维数组;
二维数组的内存分配:
按行优先存;
a[2][3]:
a,a+1代表行地址,a+1=&a[1][0];
a[0],a[0]+1代表列地址,a[0]+1=&a[0][1];
3.字符串数组
用字符串方式赋值比用字符逐个赋值多占一个字符——“\0”;
intscanf(constchar*restrictformat,...);
左值:
L-value中的L指的是Location,表示可寻址。
Avalue(computerscience)thathasanaddress.
右值:
R-value中的R指的是Read,表示可读。
incomputerscience,avaluethatdoesnothaveanaddressinacomputerlanguage.
字符串处理函数:
strcpy(),strcat(),strcmp(),strlen(),strtok();
六、指针
1.指针的本质是数据类型,而这个变量存的是存储空间的地址值
变量是存储空间的抽象,指针类型是存储数据的类型
指针和数组名是不同的!
!
!
所有数据类型的指针在32位机上都是32位(4个字节);
*(&m)=m;
野指针是没有初始化的指针,其指向是随机的;
NULL:
空指针,指向为空,唯一常量指针。
即int*p=0;orint*p=NULL;,指向0号存储单元。
但访问零号地址存储值或者修改其值,都是不允许的。
void指针:
指向的数据类型是不确定的,只知道指针目标的起始地址,不知道其占用的字节数,必须通过强制类型转换为其他数据类型才能使用;
指针的运算:
算数运算:
p+n,p-n,p++,p--,p-q
两个指针相减的结果值不是地址量,而是两个指针之间相隔数据的个数
关系运算:
p>q
const与指针
constint*p;pisapointtoconstint
int*constpconstpisapointtoint
字符指针
char*s="welcome";=constchar*s="welcome";
字符串的首地址赋值给s
在程序中使用字符串常量会产生一个“指向字符串的常指针”,当一个字符串出现在一个表达式中时,表达式所引用的值是存储该字符串常量的内存首地址,而不是字符串本身。
2.指针与数组
(1)指针与一维数组
inta[5],*p;
p=a;
a[1]=*(a+1),*(p+1)=p[1]
数组名是地址常量,指针是地址变量
(2)指针与二维数组
指针数组
int*p[2];
int*p[2]与int(*p)[2]区别?
答:
根据运算符的优先级,int*p[2]——p先与[]结合,p是一个数组名,是一个地址值,而数组元素是整形指针。
int(*p)[2];——p先与*结合,所以p是个指针,又因为(*p)相当于一个数组名,p是数组指针
数组指针
编译结果:
运行结果:
字符指针数组
char*a[3]={"welcome","to","suzhou"};
3.多级指针
不管是几级指针,都是存储内存的编号(地址)
4.数据类型与寻址方式
数据类型:
基本类型(单个存储单元)、构造类型:
数组、结构体、共用体
灵活的寻址方式实现了数据的结构化,以及结构化数据的存储单元的访问;
int*p;//间接寻址
int**q;//二次间接寻址
inta[4];//变址寻址、寄存器相对寻址
[…],变址运算符,也表示存储单元;…,存储单元的偏移地址;
七、函数
1.函数基础
(1)函数是一个能完成特定功能的代码模块。
把程序中独立的功能封装成函数可以减少重复劳动,使得程序更简洁,可读性更好。
是实现模块化编程的重要工具。
(2)如果返回值的数据类型是void,可以省略return语句,或者写成"return";
(3)函数声明的作用
函数声明称为函数原型(functionprototype)。
用函数原型是ANSIC的一个重要特点。
其作用主要是利用它在程序中的编译阶段对调用函数的合法性进行检查。
所谓合法性检查就是检查函数名是否正确,传递参数的类型、个数、顺序等。
编译器不检查形参名,故可以省略。
(4)一个C程序包含C语句、编译语句、符号等,既要遵从语言规则,又要符合编译规则。
语言规则对应语法错误,编译规则对应语义错误?
(5)参数传递
值传递、地址(指针传递)、全局变量传递
(6)函数和数组
传递数组,当形参是数组形式时,其本质上也是一个指针。
几维数组对应几级指针。
例inttest(inta[],int*p);inta[]等价于int*a
2.指针函数or函数指针
(1)指针函数
char*mystring(void);
指针函数不可以返回局部变量的地址,可以返回的地址有3种情况:
一、静态变量的地址;static
二、字符串常量的地址;“welcome”
三、堆上的地址;str=(char*)malloc(20)
内存的开辟与释放的本质是:
SP的存储值的改变,也即是存储空间指向的改变,原来存储单元的数据依然存在或者被覆盖。
chara[10]={0};0是存储值,ASCII码值,等价于转移字符'\0',打印数组无显示
(2)函数指针
函数名代表了函数的入口地址
int(*pfun)(int,int)函数指针
typedefint(*Pfun)(int,int)函数指针类型
int(*pa[3])(int,int)函数指针数组,元素是函数指针
理解void(*signal(intsig,void(*func)(int)))(int);
3.递归函数与循环
回调函数
attribute机制介绍:
函数属性、变量属性、类型属性,都是编译器要处理的
八、构造数据类型
1.结构体
定义结构体变量:
先定义结构体类型,再定义变量名;
在定义类型的同时,定义变量;
直接定义结构体变量;
对结构体、联合体中的数组用strcpy()进行赋值。
不能使用数组名直接赋值;
位域本质上是一种结构类型;
2.共用体
不同数据类型的数据使用相同的存储区域,使用方式和结构体一样;
3.枚举
九、嵌入式C高级用法
1.内存管理
代码区:
code
全局变量和静态变量区:
RW
栈区:
局部变量、函数名等
堆区:
heap,malloc()与free()
2.动态内存的申请与释放
void*malloc(size_t);
voidfree(void*ptr);
两者一定要配对使用,否则内存泄漏;
虽然malloc()申请到的空间是连续的,但就从堆的概念上来说,他是由许多分散的内存空间块以链表的数据结构组织一起的集合。
free()之后指针要赋值NULL.
利用memset()对申请到的内存空间进行清零;
3.堆和栈的区别
4.C语言和汇编语言的接口
内联汇编
_asm_(汇编语言模块:
输出部分:
输入部分:
破坏描述部分)
编译器优化
一般将内存变量缓存到寄存器和调整指令顺序充分利用CPU流水线等
C语言关键字volatile
一十、数据结构之线性表
1.线性表
零个或多个数据元素的有限序列;
数学语言描述;直接前驱、直接后继、一对一,位序
抽象数据类型:
变量形参与指针形参的区别;
2.线性表的顺序存储结构
定义:
用一段地址连续的存储单元存储线性表的数据元素
实现方式:
一维数组
属性:
起始位置、最大存储容量(数组长度)、线性表当前长度;
地址计算方式:
LOC(
)=LOC(
)+(i-1)*c
存取时间性能:
O
(1),随机存储结构;
插入删除:
O(n)
优点:
无需为表示表中元素之间的逻辑关系而增加额外的存储空间;
可以快速地存取表中任意位置的元素;
缺点:
插入和删除操作需要移动大量的元素;
当线性表长度变化较大时,难以确定存储空间的容量;
造成存储空间的“碎片”;
3.线性表的链式存储结构
(1)基本概念
起始结点:
是指链表中的第一个结点,它没有直接前驱
头指针:
是指指向起始结点的指针(没有头结点的情况下)。
一个单链表可以由其头指针唯一确定,一般用其头指针来命名单链表
头结点:
是在链表的开始结点之前附加的一个结点。
有了头结点之后头指针指向头结点,不论链表是否为空,头指针总是非空,而且头结点的设置使得对链表的第一个位置上的操作与在表中其它位置上的操作一致
数据元素与节点关系:
数据元素存放在节点的数据域
(2)单链表的读取
核心思想:
工作指针后移p=p->next
(3)单链表的整表创建
尾插法:
定义两个节点指针p、q,p指向当前节点,q指向新创建的节点
p->next=q;//当前节点指向新创建的节点
p=q;//工作指针后移
(4)单链表的整表删除
定义两个节点指针p、q,p指向当前节点,q指向下一个节点
q=p->next;
free(p);
p=q;//工作指针后移
(5)单链表的插入与删除
n个节点就有(n+1)个插入位置,编号可以从0到n
在编程时假设第(n+1)个节点存在,且为NULL.
(6)静态链表
是为没有指针的高级语言使用链表而创建的
(7)循环链表
最后一个节点指向头节点,增加一个尾指针
(8)双向链表
一十一、堆栈与队列
1.栈
栈是仅在表尾进行插入与删除操作的线性表
2.队列
队列(queue)是只一端进行插入,另一端进行删除操作的线性表
循环队列:
实现方式:
数组、取模操作(%)
队列满的条件是(rear+1)%QueueSlze=front,real指向最后一个元素的下个位置,因此队列中有一个位置是空的