po主非科班,要学习数据结构 算法,发现mooc上都是用c教,重新认真学了遍c,给自己总结一下。。
int main (void)
``
关键字void表示 mian () 函数不需要参数。 `
return 0;
它结束main()函数的运行,并向系统返回了一个整数0,作为程序的结束状态。由于main()函数的返回值是整型数,因此,任何整数都可以作为返回值。 按照惯例,如果main()函数返回0,说明程序运行正常,返回其他数字则用于表示各种不同的错误情况。
flaot 和 double 都是浮点型, 用于存放浮点数(实数), 区别在于double型数据占用空间更大,精度更高,取值范围更大。float 型数据用 %f,而double 型数据使用%lf。 l是long的首字母。
常用数学函数
- 平方根函数
sqrt (x)
- 绝对值函数
fabs (x)
- 幂函数
pow (x)
循环语句只能是一条语句。这是初学者常犯的错误,而且在程序运行时系统没有任何错误提示。
如何循环语句由多条语句组成,必须由大括号把他们括起来,变成一条复合语句。
return 语句只能返回一个值
一般情况下把全局变量定义在程序的最前面,即第一个函数的前面。
由于全局变量和局部变量作用范围不同,允许他们同名。当某函数的局部变量与全局变量同名时,在该函数中全局变量不起作用,而由局部变量起作用。
变量从定义开始分配储存单元,到运行结束储存单元被回收,整个过程称为变量生存周期。当main()函数调用其他函数时,由于main()还未运行结束,其局部变量仍然存在,还在生存周期中。全局变量的生存周期为整个程序执行周期。
C语言把保存所有变量的数据区分成动态储存区和静态储存区。
动态储存区是使用堆栈来管理的,适合函数动态分配与回收储存单元。
静态储存区相对固定,管理比较简单,它用于存放全局变量和静态变量。
静态储存区中,除了全局变量以外,还有静态局部变量,由于储存单元被保留,一旦含有静态局部变量的函数再次被调用,则静态局部变量会被重新激活,上一次函数调用后的值仍然被保存,可以供本次调用后继续使用。
静态变量定义格式:
static 类型名 变量表
自动变量如果没有赋初值,其存储单位中将是随机值,就静态变量而言,如果定义时没有初始值,系统将自动赋0。并且赋初值只在函数第一次调用时起作用,以后调用都按前一次调用保留的值使用。这是因为静态局部变量的生存周期始于函数的第一次调用,贯穿整个程序。当函数第一次调用时,静态局部变量的内存单元得以分配,赋以初值,而函数被再次调用时,此静态局部变量单元已经存在,计算机不会再次为它分配单元,赋初值也不会再发生。
但静态局部变量受变量作用范围限制,不能作用于其他函数(包括主函数)。
静态局部变量和全局变量一样,位于静态存储区,他们的共同点是生存周期贯穿整个程序执行过程。区别在于作用范围不同,全局变量可作用于所有函数,静态变量只能用于定义函数,而不能用于其他函数。
字符型变量内存占用一个字节,字符型常量指单个字符,用一对单引号来表示。
ch -‘a’ + ‘A’ 可把小写字母转换为大写字母。
数组名是一个地址常量,存放数组内存空间的首地址。
矩阵术语与二维数组下标的对应关系
- 主对角线 从矩阵的左上角至右下角的连线 i == j
- 上三角 主对角线以上的部分 i <= j
- 下三角 主对角线以下的部分 i >= j
- 副对角线 从矩阵的右上角至左下角的连线 i + j == N-1
字符串可以存放在一维字符串中。例如
static char s[6] = {'H', 'a', 'a', 'p', 'y', '\0'}
数组s中就存放了字符串’Happy’了。
字符数组的初始化还可以使用字符串常量,上述初始化等价于:
static char s [6] = {"Happy"};
或者
static char s[6] = "Happy";
字符串由有效字符和字符串结束符’\0’组成。
区分”a”和‘a’,前者是字符串常量,包括’a’和’\0’两个字符,用一位字符数组存放;后者是字符常量,只有一个字符,可以赋给字符变量。
将十六进制字符转换为十进制数number的表达式如下:
number = number * 16 + hexad[i] - ‘0’
number = number * 16 + hexad[i] - ‘A’ + 10
number = number * 16 + hexad[i] - ‘a’ + 10
指针
int型变量占2个字节
char型变量占1个字节
float型和double型分别需要占用4和8个字节的内存单元
如果未加说明,把指针和指针变量同等对待,都是指存放内存地址的指针变量。
在定义指针变量时需要使用指针声明符 *, 但指针声明符并不是指针的组成部分。例如,定义 int *p; 说明p是指针变量,而不是 *p。
在程序中,“*”除了被用于定义指针变量外,还被用于访问指针所指向的变量,它也称为间接运算符。
在C语言中实参和形参之间的数据传递是单向的“值传递”方式,调用函数不能改变实参变量的值,当指针变量作为函数时也遵守这一个规则。调用函数不能改变实参指针变量的值,但可以改变实参指针变量所指向的变量的值。这样的机制被称为引用调用。
冒泡排序
void bubble (int a[], int n)
{
int i, j, t;
for (i = 1; i < n; i++)
for (j = 0; j < n-i; j++)
if (a[j] > a[j+1]) {
t = a[j]; a[j] = a[j+1]; a[j+1] = t;
}
}
选择排序和冒泡排序初始条件:
选择排序
i = 0; i < n-1
index = i; //index 存放最小值的下标
j = i+1; j < n
if (a[j] < a[index]) index = j;
冒泡排序
i = 1; i < n;
j = 0; j < n-i;
if (a[j] > a[j+1])
int a[] 等价于 int *a
字符数组与字符指针都可以处理字符串,但两者之间有重要区别。例如
char sa[] = "This is a string";
char *sp = "This is a string";
字符数组sa在内存中占用一块连续的单元,有确定的地址,每个数组元素放字符串的一个字符,字符串就存放在数组中。字符指针sp只占用一个可以存放地址的内存单元,存储字符首字符的地址,而不是将字符串放到字符串指针变量中去。
采用函数gets()输入的字符串允许带空格。如果输入成功则返回值是字符串第一个字符的地址,如果输入失败则返回NULL。
puts()输出遇’\0’自动将其转换为’\n’,即输出字符串后换行。同样函数puts()也有返回值,如果成功执行了输出字符串的操作,则返回换行符号’\n’,否则返回EOF。
函数printf()和函数puts()的区别在于后者输出字符串会自动换行。
函数scanf()只能输入不带空格的字符串,而gets()则没有这个限制。
strcpy (s1, s2);
字符串复制函数
参数s1必须是字符型数组基地址,参数s2可以是字符型数组名或字符串常量。
字符串连接函数strcat (s1, s2)
参数s1必须是字符型数组基地址,参数s2可以是字符型数组名或字符串常量。
字符串比较函数strcmp (s1, s2);
若s1和s2相等,返回0。
若s1大于s2,返回一个正数。
若s1小于s2,则返回一个负数。
字符串长度函数 strlen(s1)
计算字符串的有效个数
- exit(0):正常运行程序并退出程序;
- exit(1):非正常运行导致退出程序;
- return():返回函数,若在主函数中,则会退出函数并返回一值。
**
- malloc () 调用malloc()时, 应该使用sizeof计算存储块大小,不要直接写数值。若申请成功,则返回一个指向被分配内存空间的起始地址的指针;若申请内存空间不成功,则返回NULL(0)。
- calloc () 在内存的动态存储区中分配n个连续空间,每一个存储空间的长度为size,并且分配后还把存储块里的全部初始化为0.若申请成功,则返回一个指向被分配内存空间的起始地址的指针;若申请内存空间不成功,则返回NULL(0)。
- malloc() 对所分配的存储块不做任何事情,calloc()对整个区域进行初始化。
- free() 为了保证动态存储块的有效利用,在知道某个动态分配的存储块不再用用时,就应该及时把他释放。
- realloc() 更改以前的存储分配。
**free()详解 内存释放
既然有分配,那就必须有释放。不然的话,有限的内存总会用光,而没有释放的内存却在空闲。与malloc对应的就是free函数了。free函数只有一个参数,就是所要释放的内存块的首地址。比如上例:free(p);
free函数看上去挺狠的,但它到底作了什么呢?
其实它就做了一件事:斩断指针变量与这块内存的关系。
比如上面的例子,我们可以说malloc函数分配的内存块是属于p的,因为我们对这块内存的访问都需要通过p来进行。free函数就是把这块内存和p之间的所有关系斩断。从此p和那块内存之间再无瓜葛。至于指针变量p本身保存的地址并没有改变,但是它对这个地址处的那块内存却已经没有所有权了。那块被释放的内存里面保存的值也没有改变,只是再也没有办法使用了。
这就是free函数的功能。按照上面的分析,如果对p连续两次以上使用free函数,肯定会发生错误。因为第一使用free函数时,p所属的内存已经被释放,第二次使用时已经无内存可释放了。关于这点,我(陈正冲老师)上课时让学生记住的是:一定要一夫一妻制,不然肯定出错。
malloc两次只free一次会内存泄漏;malloc一次free两次肯定会出错。也就是说,在程序中malloc的使用次数一定要和free相等,否则必有错误。这种错误主要发生在循环使用malloc函数时,往往把malloc和free次数弄错了。
4、内存释放之后
既然使用free函数之后指针变量p本身保存的地址并没有改变,那我们就需要重新把p的值变为NULL:p = NULL;
这个NULL就是我们前面所说的”栓野狗的链子”。如果你不栓起来迟早会出问题的**
**
指针函数是指函数的返回值是地址, *不带括号
函数指针是指定义一个指针变量,接受函数的入口地址,这就是指向函数的指针,也称为函数指针。
结构也是一种构造数据类型(或叫派生数据类型)
当p指向结构变量s1时,下面三条语句的效果是一样的:
s1.num = 101;
(*p).num = 101;
p->num = 101;
一般按照结构化程序设计方法组织函数,主要原则可以概括为“自顶向下, 逐步求精, 函数实现”。
递归程序设计
- 递归出口:即递归的结束条件,到何时不再递归调用下去。
- 递归式子:递归的表达式,如fact (n) = n * fact (n-1)。
宏定义#define是C语言中常用的功能。用宏来定义一些符号常量,可以方便程序的编制。
宏定义的格式:
#define 宏名 宏定义字符串
宏引用形式与函数调用非常相似,但两者的实现完全不同。宏替换在程序编译处理时完成。
C语言的编译预处理主要包括文件包含(#include)、宏定义(#define)和条件编译。
extern 变量名表
他只起说明作用,不分配存储单元,对应的存储单元在全局变量定义时分配。
C语言的静态全局变量可以把变量的作用范围仅局限于当前的文件模块中,即使其他文件模块使用外部变量声明,也不能使用该变量。