1.函数
1)函数定义:
返回类型 函数名(形式参数列表,可多个参数)
{
函数体;
}
函数返回类型为void 时函数体内可以有return,表示函数的返回,但后面不能跟返回值
如果返回类型不为void,则return后面一定要跟返回值
2)函数声明:
返回类型 函数名(形式参数列表,可多个参数);
3)函数调用:
实参和形参的个数、类型、顺序要相同
4)函数作用域:一般以其声明的下方都有效(函数默认为外部函数)
定义时前面加 static :其作用域仅在本文件内
作用:1)防止重名定义
2)防止外部文件调用该文件
2.数组
1)一维数组,二维数组,多维数组
2)定义方式:成员类型 数组名[成员个数]; char a[10];
3)初始化:
a) char[10]={1,2,3,45,50}给固定成员个数时,未初始化的成员值默认为0
b) 定义时候不初始化,程序运行时进行初始化,只能进行单个初始化
char a[10];
a[0]=1;
a[1]=2;
.........
访问时注意下标是从0开始的。注意不要越界
char a[10] : 访问为a[0]——a[9]
a[4]={1,2,3};
a[4]越界了,值不确定 经验结果:在KEIL中会循环取值,即a[4]=a[0]=1,可能和编译器有关
c)字符数组
char a[]="program" 或者 a[]={"program"} 数组长度要加一,后面会自动加上结束符'\0'’
char a[]={'p','r','o','g','r','a','m'} 数组长度不要加一
'a'=98, '0'=0+0x30; '1'=1+0x30 ASSIC值
3.指针
1)定义: 类型 *指针名;
2)指针的四要素:
char *P = NULL; //NULL = 0
a)本身类型:char *
b)指向类型:char
c)指向内存单元值:0地址的内容
d)本身占用的内存单元:此内存单元存的内容为地址
(用来判断是否可以作为左值使用)如int a[10]; a也是一个地址,
但不符合第四点,所有不可以给a赋值,a为(地址)常量 a=p是不合法的
用P去访问i
char **p;
char *p1;
char i;
P1=&i;
P=&P1;
所以可以写成:
**p=i;
3)字符指针
char *p="program"; 这种定义不规范,为静态方式,内容不能被修改。所有 *p=10 是非法的
要定义不能被修改的内容可以用以下语句:
const char *p="program";
扩展:
char const *P; p指向字符常量
const char *p; p指向字符常量
char *const P; p指向的地址是不可改变的
const char const *P; p指向的地址是不可改变的且它存储的值是常量
4)函数指针:指向函数的指针
定义:
char (*fP)(char,int);
赋值:
char function(char i,int j)
{
}
fp=function;
调用
(*fp)(10,100);
type char (*FUN)(char,int);类型定义
FUN fp ;定义fp为指向函数的指针
volatile的用法和作用
const与volatile相反,
volatile表示该内存中的数值可能随时会改变。
uchar a,b,c
a=5;
b=a; //b=5
c=a; //c=5
volatile uchar a,b,c
a=5;
b=a; //b不确定
c=a; //c不确定
例如单片机的P0口初始化为:
P0=0x0000 0001
a=p0; //如果人为使P0口外部都接高电平,则a=0x1111 1111,而不是0x0000 0001。与硬件相关
在定义寄存器相应的地址时常用到volatile:
#define rGPCCON (*(volatile unsigned *)0x56000020)
#define rGPCDAT (*(volatile unsigned *)0x56000024)
在项目里文件比较多时,少用全局变量,直接利用函数调用形式
单个文件: static char i; 定义静态变量,防止别的文件对变量值的意外修改。
char fun(void)
{
return(i);
}
直接使用外部调用全局变量形式:extern int i; 这样的缺点是存在隐患,当文件较多时很可能出现全局的变量重名的问题,这时候要修改的话可能较麻烦。
尽量避免在头函数.h文件里面进行变量的定义