1.字符串
字符串就是一个字符数组,结尾以'\0'作为标志
一个字符占用一个字节(汉字占用两个字节),从左到右依次存放,在字符串的结尾自动加入一个字节的结束标志'\0'
'a'与"a"的不同:'a'代表一个字符占用一个字节;"a"代表一个字符串占用两个字节.
字符串初始化:char str[10]="abc123!@#";//不能写成char str[10];str="dfh";(初始化声明的时候的=不代表赋值操作,只是初始化)
2.sizeof(类型名)
sizeof返回的值是无符号的整数
可以用sizeof(a)/sizeof(a[0])计算数组长度
3.类型定义(typedef)
typedef int Bool; //(后面变量名的首字母最好大写)
Bool flag; //类似与使用了int flag
4.宏定义
【定义宏】#define BOOL int
数组和指针不能用宏定义,宏定义中的替换列表为空也是合法的,也可以包含对另一个宏的调用,但宏不能调用它本身.
一个数字常量,如果不是0和1,就最好定义成宏.
【带参数的宏】 #define 标示符(x1,x1,…,xn) 替换列表 //参数在替换列表中都要放在圆括号中
5..数组
定义数组时,数组名不能和变量名相同,也不能和系统关键字一样
数组的地址就是数组元素的首地址,使用数组名a,代表的就是数组a[]的地址
多维数组:不常用,因为指针数组更加的灵活好用
无论是一维数组还是多维数组,通过单词const作为数组声明的开始可以把数组变为“常量”;
(如:const int months[]={31,28,31,30,31,30,31,31,30,31,30,31};)
6..函数
在调用函数前,都需要先声明函数,函数声明类似与函数定义的第一行,函数的声明必须与函数的定义一样。
【函数声明】 返回类型 函数名(形式参数); 【编译器只预处理函数,但是不分配内存】
【函数定义】 返回类型 函数名(形式参数) 【开辟内存空间,分配内存给函数,函数入口地址为函数名所在地址】
2)从返回值的角度:
有返回值:return,(函数有且只能返回一个返回值),可以是基本数据类型和指针等。
无返回值:void,在C89标准中可以忽略返回值类型,UNIX中默认为int,Window VC中为void;在C99标准中不可以忽略返回值类型。
3)从参数的角度:
带参数:需要告诉编译器参数的类型和数量
int main(int argc,char *argv[]);
int main(int argc,char **argv);
不带参数:参数列表为空,void,可以省略,即int main()或int main(void);就是不需要参数来参与运算。
.返回语句
return:【return 表达式】如果return中表达式的类型和函数返回的类型不一致,系统会把表达式的类型转换成返回类型
exit:任何函数中都可以使用,【exit(表达式)】;包含在#include 头文件中。
main函数的返回值是状态码,0表示正常结束,非0为异常结束。
7..递归
递归是函数嵌套调用的一种特殊形式,就是当一个函数调用另外一个函数的过程时,另一个函数恰好是它本身。
递归产生的条件:直接或间接的调用它本身,有一个出口(即结束递归的条件),要有一个明显的公理或公式,有规律可循。
1)直接递归调用
2)间接递归调用
注意:
1)递归调用在发生时,消耗了大量的系统资源,反复读写栈内存,CPU资源,会降低系统性能,不可控或深层递归都会造成系统不稳定
2)我们在开发过程中使用的都是浅层递归,如Windows搜索,使用了多线程,浅层递归(一般不超过3层)
3)递归调用也被用于分治算法
4)能不用就不用递归,如:.(){ .|. };. (.本身是一个函数,()为.函数的参数列表,;前为.函数的定义,最后一个.是调用这个函数)
8..迭代
迭代法又叫做递推,凡是能用递归来实现的迭代或递推都能实现。
9..指针
简单的说,指针就是地址。
内存中的最小存储单元是字节,一个字节有8位,每一位都有自己的地址,指针就是他们的首地址。
基本数据类型的指针,就是他们在内存中的首地址。
构造类型的指针,数组,他的位置就是,数组名称所在内存的首地址,即a[0]的地址或者是数组名。
函数类型的指针,就是函数的入口地址,即函数名所在内存的首地址。
指针变量:和其他基本数据类型的变量类似,特殊的是他是能保存地址的变量。
1.定义指针的时候没有初始化
2.指针指向一个局部变量,当局部变量执行完毕释放后,仍然指向该局部变量的时候(用完置NULL即可)
3.当指针指向一块动态的内存空间时malloc(new)使用完毕被free(delete)释放后,仍然指向该空间,(用完置NULL即可)
10.指针和常量的关系
常量指针:指针指向了一个常量的指针变量,常量的内容不可以修改,但是地址可以修改。
int const *p; const在*号后,是p的值不能修改;const在*号前,是*p的内容不能修改
指针常量:是个常量,是指指针变量P的值不能被修改,p是个常量,而指针指向的对象的值是可以改变的。
11.指针和数组的关系
数组指针:指向一维数组的指针,即数组的首元素
int a[10];int *p=NULL;p=a;
是一个指向二维数组一行的指针变量,即二维数组的首行的地址
int (*p)[表达式];
指针数组:数组元素是指针变量
int *p[表达式];
12.结构体(struct)
能够保存不同数据类型的一种构造数据类型
【关键字】struct
【定义结构体】 struct 结构体名{
成员变量1;
成员变量2;
…
成员变量n;
};
【结构体和指针】
1)指向结构体的指针
struct struct_name *p; //p是指针变量名
p=&object_name; //&取地址符不能忘
【结构体的嵌套】
一个结构体中嵌套了另一个结构体
struct struct_name{
成员变量1;
成员变量2;
struct struct_name_a{
成员变量a;
成员变量b;
}object_name_a;
}object_name;
【结构体数组】
数组中的每个元素都是一个结构体变量
struct struct_name{
成员变量1;
成员变量2;
}数组名[表达式]; //表达式可以为空,为空的时候是不定长度的数组
13.枚举(enum)
枚举的成员中只能用一种类型,成员内不指定序号的时候都以0开始,C语言把枚举变量和常量作为整数来处理
enum color{red, black, blue}a,b; //中间以逗号隔开
14.链表
链表是线性表的一种,是线性表的链式存储;是一种使用动态内存分配的,能保存不同数据类型的一种数据结构.构成链表的最小单位称为节点.
C语言执行过程中,在内存中的情况:
1)代码段(静态区域)
代码段由程序中的机器码组成,C语言中源代码编译后就形成了机器码,执行的时候,CPU的程序计数器指向了代码段的每一条代码,并由CPU依次执行
2)数据段(静态区域)
只读数据段,是程序使用一些不会被修改的数据,使用这些数的方式类似与查表式的操作,放置在只读存储器中;
已初始化读写数据段,是在程序中声明,有初值的变量,需占用寄存器空间,在程序执行时,位于可读写的内存区域内,供程序运行时读写
4)堆空间(动态区域)
只在程序运行时出现,一般由程序员分配和释放,在具有操作系统的情况下,若程序员忘记释放,在程序结束后,系统会自动回收内存
5)栈内存(动态区域)
只在程序运行时出现,在函数内部使用的变量,函数参数及返回值,函数调用(递归)都将使用栈空间.栈空间是由编译器自动分配和释放的内存.
C语言提供的两种内存分配的方式:
1).静态内存分配(栈内存)
由编译器自动为我们分配的内存空间,一般栈内存的大小为10M~30M
内存的对齐:是指整型占4个字节,大于4个字节的数据类型,也按照4个字节来计算,而且是4的整数倍
内存的补齐:只在结构体中有,如果所占字节数不足4个数据类型,比如char,需将不足的字节数补空,补够4个字节
2).动态分配内存(malloc向堆申请内存)
malloc函数(分配后不初始化)
void *malloc(size_t size); //返回值是万能指针,在Mac下占8个字节,在Win下占4个字节
用于动态的向堆内存申请内存空间,使用完后,要使用free()函数释放该内存
一旦指针p指向动态分配的内存块,就可以忽略p是指针的事实,并且把它用作数组的名字,p[i].
静态库(.a): 是指在编译链接时, 把库文件中的代码全部加入到可执行文件中, 因此生成的文件比较大, 但在运行时就不再需要库文件了.
动态库(.so): 在编译链接时, 并没有把库文件的代码加入到可执行文件中, 而是在程序执行时由运行时链接文件加载库, 节省了系统开销.