2014.3.11-C语言学习小结

文件操作:

知识点:		持久化
	1.文本文件的读写
	2.二进制文件的读写
	3.缓冲文件系统

		1.打开文件
		2.读写文件
		3.保存
		4.关闭文件		



======================================
文本文件的读写
	1.文件的打开
	  1)打开模式
	      r(read)		读文件,不存在,打开失败
	      w(write)  	写文件,如果文件不存在,创建文件,存在则清空文件内容  
	      a(append)		以追加方式写文件

	      a+		读写方式打开,以追加方式写文件
	      r+		读写方式打开,文件存在打开
	      w+		读写方式打开,文件不存在创建,存在打开并清空
	  2)函数原型
		FILE *fopen(const char *path, 
			    const char *mode)
		思考:如果打开的文件不存在会如何
	2.文件的关闭
	  1)函数原型
		int fclose(FILE *file);
	3.读写文件内容
	  1)按字符读文本文件,从文件读取一个字符
	    1>函数原型
		int fgetc(FILE *file);
		函数返回值:读取成功返回该字符的ascii码,失败返回-1
			1.如果读到文件末尾,返回-1
			2.如果打开方式不对,返回-1

		思考:如何判断读到文件末尾
	  2)按字符写文本文件,向文件写入一个字符
		int fputc(int c, FILE *fp);
		函数返回值:写入成功返回写入字符对应的ascii码,失败返回-1
			1.打开方式不对,返回-1
			2.磁盘空间不足,返回-1
			3.对文件没有写权限,返回-1

		练习:
		    1.通过循环将字符数组中的内容写入到文件中
		    2.读取文件中的文件内容
	  3)按行读文本文件,从文本读取一行字符
	     1>函数原型
		char *fgets(char *buf, int size, FILE *fp);
		stdin  stdout  stderr
			fgets(buf, 100, stdin);
	
		函数返回值:读取成功返回读取和参数buf相同的地址,失败返回NULL
	  4)按行写文本文件,向文本写入一行字符
	     1>函数原型
		int fputs(char *s, FILE *fp);
		函数返回值:返回成功写如的字符数,失败返回-1
	  5)格式化读写文本文件
	     1>格式化输出函数原型,按照指定格式将内容写入文本文件	
		%s|%d|%d|%d|%d|%c
		
		%s	角色名		char *name
		%d	级别		int level	
		%d	血		int boold
		%d	攻		int act
		%d	防		int def
		%c	y/n		char boss

		int fprintf(FILE *fp, const char *fmt, …);
		函数返回值:成功返回写入的字符数,失败返回-1

	     2>格式化输入函数原型,按照指定格式从文本文件读取内容	
		int fscanf(FILE *fp, const char *fmt, …);	
			%[^'|']
		函数返回值:成功返回对应读取的变量个数,失败返回-1
		练习:1.按照指定格式保存自身的基本信息
		     2.按照指定格式读取自身的基本信息并且输出
=============================================
二进制文件的读写
	需求:
	    1.现在需要保存班级中的所有学生的身高信息
			int height[10]
		%s|%d|%d
		a|9|100
		a|100|9
			double  score[10]
	    2.保存学生的完整信息
	1.文件的打开
	  1)读写模式
	     同上
	2.读写文件内容
	  1)读取函数,从文件读取数据到内存中
	    size_t fread(void *ptr, size_t size, 
		         size_t n, FILE *stream);
		参数:1.要保存数据的首地址
		    2.每次读取的数据大小
		    3.读取次数,每次读取都会在首地址后+对应的数据大小
		    4.读取的文件
		返回值:成功返回读取的次数,失败返回0
	  2)写入函数,把内存的一块数据写入到文件
	    size_t fwrite(void *ptr, size_t size, 
		          size_t n,  FILE *stream);
		参数:1.要写入数据的首地址
		    2.每次写入的数据大小
		    3.写入次数
		    4.写入的文件
		返回值:成功返回写入的次数,失败返回0
	  3)文件定位函数,文件随机读写
	    1>ftell,读取文件当前读写位置
		long ftell(FILE *stream);
	    2>设置当前文件读写位置
		int fseek(FILE *stream, long offset, int whence);
		whence:
		       SEEK_SET		相对与文件开头
		       SEEK_CUR		相对于当前位置
		       SEEK_END		相对于文件末尾
		 练习:将文件位置指针向后移动n个位置
			   然后写入数据,查看最后的结果=============================================
缓冲文件系统
	思考:printf的内容一定会马上输出到屏幕吗
	1.缓冲系统的作用
	2.缓冲的过程
	  printf->fprintf->缓冲区->write
		行缓冲
		全缓冲		fflush(fp)
		无缓冲		stderr
			
		
	3.手动刷新缓冲
	  fflush
	4.系统的标准输输入,输出,错误输出
			stdin,   stdout,  stderr
=============================================
作业:
	1.文件十六进制显示工具
	
	fp1 %c —> fp2 %x
	fprintf(fp2, “%x”, var);
	

  

链表:

知识点:
	1.链表基础
	2.节点的创建和添加		llist_append_node
	3.链表的遍历		llist_print_each
	4.链表的查找与修改
	5.链表的插入与删除
	6.链表的销毁
	7.链表逆序


==========================
回顾数组
	1.数组的常用操作
	  1)插入
	  2)修改
	  3)遍历
	  4)删除
	  5)逆序
	2.数组操作的问题
	  1)插入和删除的效率低
			1 2 3 5 6 0 0
			1 2 3 4 9 5 6
			1 2 3 4 9 5 6 0
	  2)当数组空间不足时需要重新申请内存空间
	  3)但是遍历速度快
==========================
链表基础
	1.什么是链表
	   链表(Linked list)是一种常见的基础数据结构,是一种线性表
	2.链表的作用
	  一种数据结构,保存数据
	3.如何创建链表
==========================
链表节点的创建和添加
	1.如何创建和添加一个节点
	2.如何插入一个节点
	4.处理链表的框架
void llist_append_node
			(struct node *head, 
		          struct node *new)
void llist_change_node(struct node *head, 
			             int id, 
			             char *name)
		append	*
		insert  *
		search	*
		change
		delete
		destory
		print_all  *
		print_node

	5.添加节点模块append
	练习:添加一个节点到头结点后面
==========================
链表的遍历
	1. llist_print_each函数
	void llist_print_each(struct node *head);
	 练习:
	      1.遍历输出链表内容
	      2.向链表添中加多个节点
==========================
链表的查找与修改
	1. llist_search_node函数
struct node *llist_search_node(struct node *head, int id)
void llist_print_node(struct node *nd)
	  1)遍历链表
	  2)比较要搜索的内容是否和节点数据内容匹配
	  3)返回节点地址
	  练习:
		1.查找指定id的学生信息,并输出该信息
	2.change函数
	  1)搜索要修改的节点空间
	  2)修改节点内的数据
		1.修改指定id的学生性别
==========================
链表的插入和删除
	1. llist_insert_node函数
void llist_insert_node(struct node *head,
			            struct node *nd, int id)
	  1)创建一个新节点
	  2)插入到指定位值
	  练习:
			链表包含10个节点
			id=3,id=4 <== tmp
			       id=1
	       1.创建一个新节点并且插入到第一个节点的前面
	       2.创建一个节点并且插入到第三和第四个节点之间
	2.delete函数
void llist_delete_node(struct node *head, int id);
	  1)修改该节点上一个节点的指向
	  2)释放当前节点
	  练习:
		1.删除id为1节点
		2.删除id为10节点
		3.删除id为5节点
==========================
链表销毁
	1.destory函数
	int llist_destory(struct node *head);
	 1)销毁和清空是两种不同的操作
	   例如:倒空杯子的水和砸碎杯子两个操作
	 练习:
	     销毁上面创建的链表
==========================
链表逆序
	H->A->B->C->D->E
	   ^  ^	 ^  
	   p  pp  t
	1.inverse函数
void llist_inverse(struct node *head);
	 练习:
	     1.按照上述顺序实现一个链表的逆序,并输出逆序的结果
==========================
多文件封装
	1.头文件
	2.实现文件
==========================
创建一个班级链表,该链表包含10个学生信息
1.每个学生包含信息有
		姓名,年龄,身高,性别,语数英三门成绩
2.实现:
	1)添加学生信息
	2)输出所有的学生信息
	3)搜索指定学生的信息,并且输出
	4)将指定学生插入到指定学生的前面
	5)删除指定学生信息
	6)销毁班级链表
	========================
	enume menu{
			EXIT, ADD, SONE, SALL, 
		         INSERT, DEL, DELALL};
	1.添加学生
	2.查询指定学生信息
	3.查询所有学生信息
	4.学生插队
	5.删除指定学生信息
	6.删除班级
	0.退出系统

  

预处理:

知识点:
	1.宏的定义		#define    #undef
	2.宏与函数的区别
	3.文件包含和多文件编译	#include <> “”	#import
	3.条件编译		#if  #elif #else #endif
				#ifdef  #ifndef
	4.typedef关键字

> gcc -E  源代码文件.c -o 预处理结果文件.i //预处理
> gcc -S   预处理结果文件.i -o 汇编结果文件.s //编译  翻译为汇编   
> gcc -c 汇编结果文件.s -o 目标文件.o //汇编
> gcc 目标文件.o -o a.out         //链接	ld
=================================
宏定义
	0.什么是宏定义
	  1)宏定义是C提供的三种预处理功能中的一种,预处理包括宏定义、文件包含、条件编译
	1.宏定义的作用
	  1)使用标识符来替换一些常用的代码
		for (i = 0; i < 100; ++i)
  
		LOOP100
		{
			printf(“i”);
		}
		WALK  小明---nickname 别名
	2.宏定义的本质
	  1)一种占位符,用来代替一些常用代码
	  2)一切以转换为前提,做任何事情之前先要替换
	2.基本的宏定义
	  0)#define指令语法!!!!
		宏指令	  宏名		宏体
	  1)标识符
	  2)大写,不加分号结束
	  3)使用
	  示例:定义常量PI的宏
	  练习:
		  定义数组大小的宏
	      	  定义重力加速度宏	9.8	G
	3.带有参数的宏定义
	  1)示例:计算两数最大值的宏
	    练习:
		 1.计算两数最小值的宏	?:
		 2.计算两数之和的宏,两数之积


	思考:ADD(1,2)*ADD(1,2)结果
	  
       


	4.宏替换的问题
	  1)宏替换作用的演示,gcc编译参数	
	  2)思考:能否嵌套定义或调用




	5.常用宏  
	  2)字母大小写转换
		TOLOWER		ch + 32
		TOUPPER		ch - 32
	
	  4)设置指定数某位为1或0
		SET1, SET0

	  5)获取某一位的值
		GETBITS
	  6)取得一个short的高1个字节和低1个字节
		SLOW
		SHIGH
	  7)将short的高字节和低字节互换	
	  8) 交换两数宏  
	  9)安全释放内存宏  SAFTY_FREE
		
	6.宏和函数的区别
	  1)思考:宏的本质和函数的本质
	  2)思考:宏和函数调用的速度,安全性和空间	
	  3)回忆函数调用的过程
		函数调用需要开辟栈空间,保存参数和局部变量
	  4)本质:宏只是替换,并不会产生函数调用
	  5)速度:宏不占运行时间,只占编译时间,函数调用占运行时间
	  6)安全:宏不会检查参数类型,函数会检查参数类型
	  7)空间:宏的参数不占用空间,函数的用空间
	  8)能否调用自身:宏不能进行递归调用,函数可以
	   思考:如何结合宏与函数的优势
		1.代码非常简单而又十分常用的时候使用宏
		2.代码非常复杂,一般使用函数
==================================
文件包含和多文件编译
	1.思考:如何实现多人合作项目
		接口---->函数原型	.h	//head
		实现---->函数定义	.c
		
	cvs	git	svn
		
	2.回忆函数定义和声明
	3.头文件和源文件
	4.#include指令语法!!!!
	  1)本质:头文件包含实际是替换文件内容
	  2)作用:实现声明和实现相分离,进一步使程序更加的模块化	

		#include <stdio.h>  尖括号表示系统标准目录		
	    双引号表示自定义路径		
	  		add,  sub, mut, div
	5.示例:链表的实现的声明相分离
	  练习:
		1.实现加减乘除四则运算,并将函数的声明与实现相分离
		  并编写测试函数测试该些函数

		A B C D		200		100

		
===================================
条件预编译
	需求:现在用户只购买系统中的某些模块
	1.思考:如何可以简单快速的在编译的过程中满足用户的需求
	2.#ifdef 条件编译语法!!!!
	     #ifndef
		1)作用:模块选择
	  示例:判断是否定义过PI宏
	  练习:判断是否有定义上述的常用宏
	思考:
	   1.如何可以安全,快速的注释代码
	   2.// 和 /**/注释是否可以嵌套使用
	3.#if 条件编译语法!!!!
	  1)作用
	     快速安全的注释代码
	4.安全注释
	思考:如果重复包含头文件会如何
	5.防止头文件重复包含
===================================
调试宏
		NSLog
	思考:如何使用printf调试代码,是否方便移出
	1.调试宏定义
	  INFO, WARN, ERROR, DEBUG
	2.调试开关
	3.预定义宏
		printf("line = %d, file = %s, DATA = %s, TIME = %s", 
				__LINE__, __FILE__, __DATE__, __TIME__);
	  __LINE__:行号
	  __FILE__:文件名
	  __DATE__:日期		%s
	  __TIME__:时间
	  __FUNCTION__, __func__:函数名
===================================
typedef关键字				int4		int32		int64
	思考:程序的跨平台性		64	32	16	8
					int    int     int2
					long  long	   long 

			size_t

			long long	int64
			long

	1.typedef作用
	   1)typedef常用来定义一个标识符和及关键字的别名,并不分配实际的内存
	   2)typedef可以增强程序的可读性
	   3)typedef可以增强标识符的灵活性
	2.typedef本质
	   typedef本质为类型的别名
	3.typedef语法使用!!!!
	4.重定义结构体
	5.重定义类型
	6.typedef与define的区别
	  1)typedef是为了程序的可读性而为标识符另起的别名,而
	    define在c语言中是为了定义常量,常用代码替换
	  2)define可以使用#ifdef和#ifndef来进行逻辑判断

  

动态内存分配:

知识点:	
	动态内存管理
	1.数据在内存中的存储
	2.内存分配malloc和realloc和calloc函数使用和注意事项
	3.free函数使用
	4.堆和栈的区别      .heap  .stack	 .bss	.data	.rodata
	5.常用内存操作函数  
==============================
内存使用
	1.回顾函数在使用时候所开辟的内存栈
	2.变量所在的内存空间
	3.栈空间的限制	stack  
	  1)栈大小:一般在2M左右
	4.栈数据的特点
	  1)回顾局部变量的生命周期
	  2)每个变量的内存大小均在编译时候确定,空间由操作系统分配
	  3)数据由系统自动释放
	  4)数据分配在栈段
	思考:	
			int var;
			return &var;
20000 / 1000 == 20
		0.是否可以返回函数执行过程中局部变量的内存地址
		1.如果需要的内存栈无法提供足够的内存容纳我们的数据怎么办
		2.如果需要将函数内的数据保存到程序结束再销毁,是否可以
	5.堆空间的使用		heap
	  1)堆空间的特点
	    1>大小由程序员决定,空间由程序员分配
	    2>大小在运行时候确定
	    3>由程序员手动释放
	    4>数据分配在堆段
==============================
动态内存分配函数
	1.malloc  内存分配 
	  1)函数原型
		void *malloc(size_t size) 
		void *calloc(int n, size_t size) 
	        申请size个字节的内存
	  2)函数使用
	      void *p = malloc(4096 * 1024 * 1024);
	  3)分配内存注意	
	     1)函数执行完后如果成功,返回该size大小内存的首地址
	     2)函数执行失败返回NULL
	     3)malloc会在堆上寻找一块size个字节的内存返回给用户
	     4)使用之前一定要判断是否分配成功,因为malloc函数执行有可能会失败(内存不足)
			1.内存不足
			2.没有足够大的连续内存空间
	
			
		练习:
		1.分配一能足够保存double			  数据的内存空间,并且赋值输出
	        2.分配一个足够保存n个double类型数据		  的内存空间,并且赋值输出


	思考:如果现在所使用的内存空间不足,想要重新分配一块内存,但是又不想丢失原来的数据,么办
	2.realloc  重新分配内存
	  1)函数原型
	      void *realloc(void *ptr, size_t size)
	      在ptr指针后再分配size个字节的内存空间
	  2)函数使用
		realloc(ptr, 40);
	  3)函数使用注意
	    1)思考:如果ptr执行NULL会如何
	    2)思考:如果在ptr后没有size个字节的内存会如何
	    3)思考:函数返回值是什么
	 	练习:使用realloc函数为malloc分配的内存向后扩展40个字节的空间
		    0.比较返回地址是否为原理的内存地址
		    1.输出新空间中的所有内容
		    2.对新的内存空间进行赋值
		   
================================
内存释放函数
	思考:申请的内存是否需要释放,不释放是否可以,会造成怎样的结果
	1.free 内存释放
	  1)函数原型
	     void free(void *ptr)
	  2)函数使用
	    free(ptr)
	  3)函数使用注意
		思考:释放后的内存是否可以继续使用
	    1>只能对有效分配的内存进行释放
		思考: 被释放的内存还可以引用吗
	    2>思考:如果对一个指针连续释放两次会如何
	         3>不能释放栈上的空间
	    3>如何避免上述情况
		练习:释放malloc和realloc申请的内存空间
================================
堆和栈的区别
	1.分配大小
		栈	不能超过2M
		堆	可以任意分配,只要系统有内存
	2.分配速度
		栈	快
		堆	慢
===============================
数据在内存中的存储与分布
	1.数据区:栈,堆,数据段
	2.栈
	  1)进入函数时分配空间,函数结束时释放空间
	  2)局部变量,函数参数均在此段中
	  3)此段中的初始值均为随机数
	3.堆
	  1)malloc申请,free释放
	  2)初始值
	4.数据段
	  1)全局变量    bss 没有初始化的全局变量
	  2)static静态变量
	  3)字符串常量(只读静态存储取)   rodata
================================
常用内存处理函数

	1.memset 将指定地址指定大小设置为指定内容
	  1)函数原型
		void *memset(void *ptr, int c, size_t len)
	  2)函数使用
	  3)函数使用注意
	    练习:分配10个字节的内存空间
		1.输出该空间中的内容
		2.将该内存空间上的内容全部设置为1	
	2.memmove  内存拷贝,从s2拷贝len的字节内容到s1中
	   1)函数原型
		void *memmove(void *dst, const void *src, size_t  len)
		void *memcpy(void *dst, const void *src, size_t  len)
	   2)函数使用
	   3)函数使用注意
===========================================


  

原文地址:https://www.cnblogs.com/firstrate/p/3593180.html