版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、目录1.C 语言中的指针和内存泄漏52.C语言难点分析整理103.C语言难点184.C/C+实现冒泡排序算法325.C+中指针和引用的区别356.const char*, char const*, char*const的区别367.C中可变参数函数实现388.C程序内存中组成部分419.C编程拾粹4210.C语言中实现数组的动态增长4411.C语言中的位运算4612.浮点数的存储格式:5013.位域5814.C语言函数二维数组传递方法6415.C语言复杂表达式的执行步骤6616.C语言字符串函数大全6817.C语言宏定义技巧8918.C语言实现动态数组10019.C语言笔试-运算符和表达式10
2、420.C语言编程准则之稳定篇10721.C语言编程常见问题分析10822.C语言编程易犯毛病集合11223.C语言缺陷与陷阱(笔记)11924.C语言防止缓冲区溢出方法12625.C语言高效编程秘籍12826.C运算符优先级口诀13327.do/while(0)的妙用13428.exit()和return()的区别14029.exit子程序终止函数与return的差别14130.extern与static存储空间矛盾14531.PC-Lint与CC+代码质量14732.spirntf函数使用大全15833.二叉树的数据结构16734.位运算应用口诀和实例17035.内存对齐与ANSI C中s
3、truct内存布局17336.冒泡和选择排序实现18037.函数指针数组与返回数组指针的函数18638.右左法则- 复杂指针解析18939.回车和换行的区别19240.堆和堆栈的区别19441.堆和堆栈的区别19842.如何写出专业的C头文件20243.打造最快的Hash表20744.指针与数组学习笔记22245.数组不是指针22446.标准C中字符串分割的方法22847.汉诺塔源码23148.洗牌算法23449.深入理解C语言指针的奥秘23650.游戏外挂的编写原理25451.程序实例分析-为什么会陷入死循环25852.空指针究竟指向了内存的哪个地方26053.算术表达式的计算26554.结
4、构体对齐的具体含义26955.连连看AI算法27456.连连看寻路算法的思路28357.重新认识:指向函数的指针28858.链表的源码29159.高质量的子程序29560.高级C语言程序员测试必过的十六道最佳题目+答案详解29761.C语言常见错误32062.超强的指针学习笔记32563.程序员之路关于代码风格34364.指针、结构体、联合体的安全规范34665.C指针讲解35266.关于指向指针的指针36867.C/C+ 误区一:void main()37368.C/C+ 误区二:fflush(stdin)37669.C/C+ 误区三:强制转换 malloc() 的返回值38070.C/C+
5、 误区四:char c = getchar();38171.C/C+ 误区五:检查 new 的返回值38372.C 是 C+ 的子集吗?38473.C和C+的区别是什么?38774.无条件循环38875.产生随机数的方法38976.顺序表及其操作39077.单链表的实现及其操作39178.双向链表39579.程序员数据结构笔记39980.Hashtable和HashMap的区别40881.hash 表学习笔记41082.C程序设计常用算法源代码41283.C语言有头结点链表的经典实现41984.C语言惠通面试题42885.C语言常用宏定义4501.C 语言中的指针和内存泄漏在使用 C 语言时,
6、您是否对花时间调试指针和内存泄漏问题感到厌倦?如果是这样,那么本文就适合您。您将了解可能导致内存破坏的指针操作类型,您还将研究一些场景,了解要在使用动态内存分配时考虑什么问题。引言对于任何使用 C 语言的人,如果问他们 C 语言的最大烦恼是什么,其中许多人可能会回答说是指针和内存泄漏。这些的确是消耗了开发人员大多数调试时间的事项。指针和内存泄漏对某些开发人员来说似乎令人畏惧,但是一旦您了解了指针及其关联内存操作的基础,它们就是您在 C 语言中拥有的最强大工具。本文将与您分享开发人员在开始使用指针来编程前应该知道的秘密。本文内容包括:1.导致内存破坏的指针操作类型2.在使用动态内存分配时必须考虑
7、的检查点3.导致内存泄漏的场景如果您预先知道什么地方可能出错,那么您就能够小心避免陷阱,并消除大多数与指针和内存相关的问题。?什么地方可能出错?有几种问题场景可能会出现,从而可能在完成生成后导致问题。在处理指针时,您可以使用本文中的信息来避免许多问题。1.未初始化的内存在本例中,p 已被分配了 10 个字节。这 10 个字节可能包含垃圾数据,如图 1 所示。char *p = malloc ( 10 ); 图 1. 垃圾数据 如果在对这个 p 赋值前,某个代码段尝试访问它,则可能会获得垃圾值,您的程序可能具有不可预测的行为。p 可能具有您的程序从未曾预料到的值。良好的实践是始终结合使用 mem
8、set 和 malloc,或者使用 calloc。char *p = malloc (10);memset(p,0,10); 现在,即使同一个代码段尝试在对 p 赋值前访问它,该代码段也能正确处理 Null 值(在理想情况下应具有的值),然后将具有正确的行为。2.内存覆盖由于 p 已被分配了 10 个字节,如果某个代码片段尝试向 p 写入一个 11 字节的值,则该操作将在不告诉您的情况下自动从其他某个位置“吃掉”一个字节。让我们假设指针 q 表示该内存。图 2. 原始 q 内容 图 3. 覆盖后的 q 内容 结果,指针 q 将具有从未预料到的内容。即使您的模块编码得足够好,也可能由于某个共存模
9、块执行某些内存操作而具有不正确的行为。下面的示例代码片段也可以说明这种场景。Char *name = (char *) malloc(11); / Assign some value to namememcpy ( p,name,11); / Problem begins here 在本例中,memcpy 操作尝试将 11 个字节写到 p,而后者仅被分配了 10 个字节。作为良好的实践,每当向指针写入值时,都要确保对可用字节数和所写入的字节数进行交叉核对。一般情况下,memcpy 函数将是用于此目的的检查点。内存读取越界内存读取越界 (overread) 是指所读取的字节数多于它们应有的字节数
10、。这个问题并不太严重,在此就不再详述了。下面的代码提供了一个示例。char *ptr = (char *)malloc(10);char name20 ;memcpy ( name,ptr,20); / Problem begins here 在本例中,memcpy 操作尝试从 ptr 读取 20 个字节,但是后者仅被分配了 10 个字节。这还会导致不希望的输出。内存泄漏内存泄漏可能真正令人讨厌。下面的列表描述了一些导致内存泄漏的场景。重新赋值我将使用一个示例来说明重新赋值问题。char *memoryArea = malloc(10);char *newArea = malloc(10);这
11、向如下面的图 4 所示的内存位置赋值。图 4. 内存位置 memoryArea 和 newArea 分别被分配了 10 个字节,它们各自的内容如图 4 所示。如果某人执行如下所示的语句(指针重新赋值) memoryArea = newArea; 则它肯定会在该模块开发的后续阶段给您带来麻烦。在上面的代码语句中,开发人员将 memoryArea 指针赋值给 newArea 指针。结果,memoryArea 以前所指向的内存位置变成了孤立的,如下面的图 5 所示。它无法释放,因为没有指向该位置的引用。这会导致 10 个字节的内存泄漏。图 5. 内存泄漏 在对指针赋值前,请确保内存位置不会变为孤立的
12、。首先释放父块假设有一个指针 memoryArea,它指向一个 10 字节的内存位置。该内存位置的第三个字节又指向某个动态分配的 10 字节的内存位置,如图 6 所示。图 6. 动态分配的内存 free(memoryArea)如果通过调用 free 来释放了 memoryArea,则 newArea 指针也会因此而变得无效。newArea 以前所指向的内存位置无法释放,因为已经没有指向该位置的指针。换句话说,newArea 所指向的内存位置变为了孤立的,从而导致了内存泄漏。每当释放结构化的元素,而该元素又包含指向动态分配的内存位置的指针时,应首先遍历子内存位置(在此例中为 newArea),并
13、从那里开始释放,然后再遍历回父节点。这里的正确实现应该为:free( memoryArea-newArea);free(memoryArea);返回值的不正确处理有时,某些函数会返回对动态分配的内存的引用。跟踪该内存位置并正确地处理它就成为了 calling 函数的职责。char *func ( ) return malloc(20); / make sure to memset this location to 0void callingFunc ( ) func ( ); / Problem lies here在上面的示例中,callingFunc() 函数中对 func() 函数的调用未
14、处理该内存位置的返回地址。结果,func() 函数所分配的 20 个字节的块就丢失了,并导致了内存泄漏。归还您所获得的在开发组件时,可能存在大量的动态内存分配。您可能会忘了跟踪所有指针(指向这些内存位置),并且某些内存段没有释放,还保持分配给该程序。始终要跟踪所有内存分配,并在任何适当的时候释放它们。事实上,可以开发某种机制来跟踪这些分配,比如在链表节点本身中保留一个计数器(但您还必须考虑该机制的额外开销)。访问空指针访问空指针是非常危险的,因为它可能使您的程序崩溃。始终要确保您不是在访问空指针。总结本文讨论了几种在使用动态内存分配时可以避免的陷阱。要避免内存相关的问题,良好的实践是:始终结合
15、使用 memset 和 malloc,或始终使用 calloc。每当向指针写入值时,都要确保对可用字节数和所写入的字节数进行交叉核对。在对指针赋值前,要确保没有内存位置会变为孤立的。每当释放结构化的元素(而该元素又包含指向动态分配的内存位置的指针)时,都应首先遍历子内存位置并从那里开始释放,然后再遍历回父节点。始终正确处理返回动态分配的内存引用的函数返回值。每个 malloc 都要有一个对应的 free。确保您不是在访问空指针。2.C语言难点分析整理这篇文章主要是介绍一些在复习C语言的过程中笔者个人认为比较重点的地方,较好的掌握这些重点会使对C的运用更加得心应手。此外会包括一些细节、易错的地方
16、。涉及的主要内容包括:变量的作用域和存储类别、函数、数组、字符串、指针、文件、链表等。一些最基本的概念在此就不多作解释了,仅希望能有只言片语给同是C语言初学者的学习和上机过程提供一点点的帮助。变量作用域和存储类别:了解了基本的变量类型后,我们要进一步了解它的存储类别和变量作用域问题。变量类别子类别局部变量静态变量(离开函数,变量值仍保留)自动变量寄存器变量全局变量静态变量(只能在本文件中用)非静态变量(允许其他文件使用)换一个角度变量类别子类别静态存储变量静态局部变量(函数)静态全局变量(本文件)非静态全局/外部变量(其他文件引用)动态存储变量自动变量寄存器变量形式参数extern型的存储变量
17、在处理多文件问题时常能用到,在一个文件中定义extern型的变量即说明这个变量用的是其他文件的。顺便说一下,笔者在做课设时遇到out of memory的错误,于是改成做多文件,再把它include进来(注意自己写的*.h要用“”不用),能起到一定的效用。static型的在读程序写结果的试题中是个考点。多数时候整个程序会出现多个定义的变量在不同的函数中,考查在不同位置同一变量的值是多少。主要是遵循一个原则,只要本函数内没有定义的变量就用全局变量(而不是main里的),全局变量和局部变量重名时局部变量起作用,当然还要注意静态与自动变量的区别。函数:对于函数最基本的理解是从那个叫main的单词开始
18、的,一开始总会觉得把语句一并写在main里不是挺好的么,为什么偏择出去。其实这是因为对函数还不够熟练,否则函数的运用会给我们编程带来极大的便利。我们要知道函数的返回值类型,参数的类型,以及调用函数时的形式。事先的函数说明也能起到一个提醒的好作用。所谓形参和实参,即在调用函数时写在括号里的就是实参,函数本身用的就是形参,在画流程图时用平行四边形表示传参。函数的另一个应用例子就是递归了,笔者开始比较头疼的问题,反应总是比较迟钝,按照老师的方法,把递归的过程耐心准确的逐级画出来,学习的效果还是比较好的,会觉得这种递归的运用是挺巧的,事实上,著名的八皇后、汉诺塔等问题都用到了递归。例子:longfun
19、(intn)longs;if(n=1|n=2) s=2; elses=n-fun(n-1);returns;main()printf(%ld,fun(4); 数组:分为一维数组和多维数组,其存储方式画为表格的话就会一目了然,其实就是把相同类型的变量有序的放在一起。因此,在处理比较多的数据时(这也是大多数的情况)数组的应用范围是非常广的。具体的实际应用不便举例,而且绝大多数是与指针相结合的,笔者个人认为学习数组在更大程度上是为学习指针做一个铺垫。作为基础的基础要明白几种基本操作:即数组赋值、打印、排序(冒泡排序法和选择排序法)、查找。这些都不可避免的用到循环,如果觉得反应不过来,可以先一点点的把
20、循环展开,就会越来越熟悉,以后自己编写一个功能的时候就会先找出内在规律,较好的运用了。另外数组做参数时,一维的里可以是空的,二维的第一个里可以是空的但是第二个中必须规定大小。冒泡法排序函数:voidbubble(int a,int n)inti,j,k;for(i=1,in;i+) for(j=0;jaj+1) k=aj; aj=aj+1; aj+1=k; 选择法排序函数:voidsort(int a,int n)inti,j,k,t;for(i=0,in-1;i+) k=i; for(j=i+1;jn;j+) if(akaj)k=j; if(k!=i) t=ai; ai=ak; ak=t;
21、折半查找函数(原数组有序):voidsearch(inta,intn,intx)intleft=0,right=n-1,mid,flag=0;while(flag=0)&(left=right) mid=(left+right)/2; if(x=amid) printf(%d%d,x,mid); flag =1; elseif(x整型atoi(char *)整型-字符串型itoa(int,char *,int)做课设时挺有用的sprintf(char *,格式化输入)赋给字符串,而不打印出来。课设时用也比较方便注:对字符串是不允许做=或!=的运算的,只能用字符串比较函数指针:指针可以说是C语言
22、中最关键的地方了,其实这个“指针”的名字对于这个概念的理解是十分形象的。首先要知道,指针变量的值(即指针变量中存放的值)是指针(即地址)。指针变量定义形式中:基本类型 *指针变量名 中的“*”代表的是这是一个指向该基本类型的指针变量,而不是内容的意思。在以后使用的时候,如*ptr=a时,“*”才表示ptr所指向的地址里放的内容是a。指针比较典型又简单的一应用例子是两数互换,看下面的程序,swap(intc,intd)intt;t=c;c=d;d=t;main()inta=2,b=3;swap(a,b);printf(“%d,%d”,a,b);这是不能实现a和b的数值互换的,实际上只是形参在这个
23、函数中换来换去,对实参没什么影响。现在,用指针类型的数据做为参数的话,更改如下:swap(#3333FF *p1,int*p2)intt;t=*p1;*p1=*p2;*p2=t;main()inta=2,b=3;int*ptr1,*ptr2;ptr1=&a;ptr2=&b;swap(prt1,ptr2);printf(“%d,%d”,a,b);这样在swap中就把p1,p2 的内容给换了,即把a,b的值互换了。指针可以执行增、减运算,结合+运算符的法则,我们可以看到:*+s取指针变量加1以后的内容*s+取指针变量所指内容后s再加1(*s)+指针变量指的内容加1指针和数组实际上几乎是一样的,数组
24、名可以看成是一个常量指针,一维数组中ptr=&b0则下面的表示法是等价的:a3等价于*(a+3)ptr3等价于*(ptr+3)下面看一个用指针来自己实现atoi(字符串型-整型)函数:intatoi(char*s)intsign=1,m=0;if(*s=+|*s=-)/*判断是否有符号*/sign=(*s+=+)?1:-1;/*用到三目运算符*/while(*s!=)/*对每一个字符进行操作*/ m=m*10+(*s-0); s+;/*指向下一个字符*/ returnm*sign;指向多维数组的指针变量也是一个比较广泛的运用。例如数组a34,a代表的实际是整个二维数组的首地址,即第0行的首地址
25、,也就是一个指针变量。而a+1就不是简单的在数值上加上1了,它代表的不是a01,而是第1行的首地址,&a10。指针变量常用的用途还有把指针作为参数传递给其他函数,即指向函数的指针。看下面的几行代码:voidInput(ST *);voidOutput(ST *);voidBubble(ST *);voidFind(ST *);voidFailure(ST *);/*函数声明:这五个函数都是以一个指向ST型(事先定义过)结构的指针变量作为参数,无返回值。*/void(*process5)(ST *)=Input,Output,Bubble,Find,Failure;/*process被调用时提供
26、5种功能不同的函数共选择(指向函数的指针数组)*/printf(nChoose:n?);scanf(%d,&choice);if(choice=0&choice=4)(*processchoice)(a);/*调用相应的函数实现不同功能*;/总之,指针的应用是非常灵活和广泛的,不是三言两语能说完的,上面几个小例子只是个引子,实际编程中,会逐渐发现运用指针所能带来的便利和高效率。3.C语言难点这篇文章主要是介绍一些在复习C语言的过程中笔者个人认为比较重点的地方,较好的掌握这些重点会使对C的运用更加得 心应手。此外会包括一些细节、易错的地方。涉及的主要内容包括:变量的作用域和存储类别、函数、数组、
27、字符串、指针、文件、链表等。一些最基本的概念在此 就不多作解释了,仅希望能有只言片语给同是C语言初学者的学习和上机过程提供一点点的帮助。变量作用域和存储类别:了解了基本的变量类型后,我们要进一步了解它的存储类别和变量作用域问题。变量类别子类别局部变量静态变量(离开函数,变量值仍保留)自动变量寄存器变量全局变量静态变量(只能在本文件中用)非静态变量(允许其他文件使用)换一个角度变量类别子类别静态存储变量静态局部变量(函数)静态全局变量(本文件)非静态全局/外部变量(其他文件引用)动态存储变量自动变量寄存器变量形式参数extern型的存储变量在处理多文件问题时常能用到,在一个文件中定义 exter
28、n型的变量即说明这个变量用的是其他文件的。顺便说一下,笔者在做课设时遇到out of memory的错误,于是改成做多文件,再把它include进来(注意自己写的*.h要用“”不用),能起到一定的效用。static 型的在读程序写结果的试题中是个考点。多数时候整个程序会出现多个定义的变量在不同的函数中,考查在不同位置同一变量的值是多少。主要是遵循一个原则,只 要本函数内没有定义的变量就用全局变量(而不是main里的),全局变量和局部变量重名时局部变量起作用,当然还要注意静态与自动变量的区别。函数:对于函数最基本的理解是从那个叫main的单词开始的,一开始总会觉得把语句一并 写在main里不是挺
29、好的么,为什么偏择出去。其实这是因为对函数还不够熟练,否则函数的运用会给我们编程带来极大的便利。我们要知道函数的返回值类型, 参数的类型,以及调用函数时的形式。事先的函数说明也能起到一个提醒的好作用。所谓形参和实参,即在调用函数时写在括号里的就是实参,函数本身用的就是形 参,在画流程图时用平行四边形表示传参。函数的另一个应用例子就是递归了,笔者开始比较头疼的问题,反应总是比较迟钝,按照老师的方法,把递归的过程耐心准确的逐级画出来,学习的效果还是比较好的,会觉得这种递归的运用是挺巧的,事实上,著名的八皇后、汉诺塔等问题都用到了递归。例子:long fun(int n)long s;if(n=1|
30、n=2) s=2; else s=n-fun(n-1);return s;main()printf(%ld,fun(4); 数组:分为一维数组和多维数组,其存储方式画为表格的话就会一目了然,其实就是把相同类型的变量有序的放在一起。因此,在处理比较多的数据时(这也是大多数的情况)数组的应用范围是非常广的。具体的实际应用不便举例,而且绝大多数是与指针相结合的,笔者个人认为学习数组在 更大程度上是为学习指针做一个铺垫。作为基础的基础要明白几种基本操作:即数组赋值、打印、排序(冒泡排序法和选择排序法)、查找。这些都不可避免的用到 循环,如果觉得反应不过来,可以先一点点的把循环展开,就会越来越熟悉,以后
31、自己编写一个功能的时候就会先找出内在规律,较好的运用了。另外数组做参数 时,一维的里可以是空的,二维的第一个里可以是空的但是第二个中必须规定大小。冒泡法排序函数:void bubble(int a,int n)int i,j,k;for(i=1,in;i+) for(j=0;jaj+1) k=aj; aj=aj+1; aj+1=k; 选择法排序函数:void sort(int a,int n)int i,j,k,t;for(i=0,in-1;i+) k=i; for(j=i+1;jn;j+) if(akaj) k=j; if(k!=i) t=ai; ai=ak; ak=t; 折半查找函数(原数
32、组有序):void search(int a,int n,int x)int left=0,right=n-1,mid,flag=0;while(flag=0)&(left=right) mid=(left+right)/2; if(x=amid) printf(%d%d,x,mid); flag =1; else if(x整型atoi(char *)整型-字符串型itoa(int,char *,int)做课设时挺有用的sprintf(char *,格式化输入)赋给字符串,而不打印出来。课设时用也比较方便注:对字符串是不允许做=或!=的运算的,只能用字符串比较函数指针:指针可以说是C语言中最关
33、键的地方了,其实这个“指针”的名字对于这个概念的理解 是十分形象的。首先要知道,指针变量的值(即指针变量中存放的值)是指针(即地址)。指针变量定义形式中:基本类型 *指针变量名 中的“*”代表的是这是一个指向该基本类型的指针变量,而不是内容的意思。在以后使用的时候,如*ptr=a时,“*”才表示ptr所指向的地址里放的内 容是a。指针比较典型又简单的一应用例子是两数互换,看下面的程序,swap(int c,int d)int t;t=c;c=d;d=t;main()int a=2,b=3;swap(a,b);printf(“%d,%d”,a,b);这是不能实现a和b的数值互换的,实际上只是形参
34、在这个函数中换来换去,对实参没什么影响。现在,用指针类型的数据做为参数的话,更改如下:swap(#3333FF *p1,int *p2)int t;t=*p1;*p1=*p2;*p2=t;main()int a=2,b=3;int *ptr1,*ptr2;ptr1=&a;ptr2=&b;swap(prt1,ptr2);printf(“%d,%d”,a,b);这样在swap中就把p1,p2 的内容给换了,即把a,b的值互换了。指针可以执行增、减运算,结合+运算符的法则,我们可以看到:*+s取指针变量加1以后的内容*s+取指针变量所指内容后s再加1(*s)+指针变量指的内容加1指针和数组实际上几乎
35、是一样的,数组名可以看成是一个常量指针,一维数组中ptr=&b0则下面的表示法是等价的:a3等价于*(a+3)ptr3等价于*(ptr+3)下面看一个用指针来自己实现atoi(字符串型-整型)函数:int atoi(char *s)int sign=1,m=0;if(*s=+|*s=-) /*判断是否有符号*/sign=(*s+=+)?1:-1; /*用到三目运算符*/while(*s!=0) /*对每一个字符进行操作*/ m=m*10+(*s-0); s+; /*指向下一个字符*/ return m*sign;指向多维数组的指针变量也是一个比较广泛的运用。例如数组a34,a代表的实际是整个二
36、维数组的首地址,即第0行的首地址,也就是一个指针变量。而a+1就不是简单的在数值上加上1了,它代表的不是a01,而是第1行的首地址,&a10。指针变量常用的用途还有把指针作为参数传递给其他函数,即指向函数的指针。看下面的几行代码:void Input(ST *);void Output(ST *);void Bubble(ST *);void Find(ST *);void Failure(ST *);/*函数声明:这五个函数都是以一个指向ST型(事先定义过)结构的指针变量作为参数,无返回值。*/void (*process5)(ST *)=Input,Output,Bubble,Find,F
37、ailure;/*process被调用时提供5种功能不同的函数共选择(指向函数的指针数组)*/printf(nChoose:n?);scanf(%d,&choice);if(choice=0&choice=4)(*processchoice)(a); /*调用相应的函数实现不同功能*;/总之,指针的应用是非常灵活和广泛的,不是三言两语能说完的,上面几个小例子只是个引子,实际编程中,会逐渐发现运用指针所能带来的便利和高效率。文件:函数调用形式说明fopen(路径,打开方式)打开文件fclose(FILE *)防止之后被误用fgetc(FILE *)从文件中读取一个字符fputc(ch,FILE
38、*)把ch代表的字符写入这个文件里fgets(FILE *)从文件中读取一行fputs(FILE *)把一行写入文件中fprintf(FILE *,格式字符串,输出表列)把数据写入文件fscanf(FILE *,格式字符串,输入表列)从文件中读取fwrite(地址,sizeof(),n,FILE *)把地址中n个sizeof大的数据写入文件里fread(地址,sizeof(),n,FILE *)把文件中n个sizeof大的数据读到地址里rewind(FILE *)把文件指针拨回到文件头fseek(FILE *,x,0/1/2)移动文件指针。第二个参数是位移量,0代表从头移,1代表从当前位置移,
39、2代表从文件尾移。feof(FILE *)判断是否到了文件末尾文件打开方式说明r打开只能读的文件w建立供写入的文件,如果已存在就抹去原有数据a打开或建立一个把数据追加到文件尾的文件r+打开用于更新数据的文件w+建立用于更新数据的文件,如果已存在就抹去原有数据a+打开或建立用于更新数据的文件,数据追加到文件尾注:以上用于文本文件的操作,如果是二进制文件就在上述字母后加“b”。我们用文件最大的目的就是能让数据保存下来。因此在要用文件中数据的时候,就是要 把数据读到一个结构(一般保存数据多用结构,便于管理)中去,再对结构进行操作即可。例如,文件aa.data中存储的是30个学生的成绩等信息,要遍历
40、这些信息,对其进行成绩输出、排序、查找等工作时,我们就把这些信息先读入到一个结构数组中,再对这个数组进行操作。如下例:#include#include#define N 30 typedef struct student /*定义储存学生成绩信息的数组*/char *name;int chinese;int maths;int phy;int total;ST;main()ST aN; /*存储N个学生信息的数组*/FILE *fp;void (*process3)(ST *)=Output,Bubble,Find; /*实现相关功能的三个函数*/int choice,i=0;Show();p
41、rintf(nChoose:n?);scanf(%d,&choice);while(choice=0&choice=2) fp=fopen(aa.dat,rb); for(i=0;iN;i+) fread(&ai,sizeof(ST),1,fp); /*把文件中储存的信息逐个读到数组中去*/ fclose(fp); (*processchoice)(a); /*前面提到的指向函数的指针,选择操作*/ printf(n); Show(); printf(n?); scanf(%d,&choice); void Show()printf(n*Choices:*n0.Display the data
42、 formn1.Bubble it according to the total scoren2.Searchn3.Quit!n);void Output(ST *a) /*将文件中存储的信息逐个输出*/int i,t=0;printf(Name Chinese Maths Physics Totaln);for(i=0;iN;i+) t=ai.chinese+ai.maths+ai.phy; ai.total=t; printf(%4s%8d%8d%8d%8dn,,ai.chinese,ai.maths,ai.phy,ai.total); void Bubble(ST *a)
43、/*对数组进行排序,并输出结果*/int i,pass;ST m;for(pass=0;passN-1;pass+) for(i=0;iN-1;i+) if(ai.totalai+1.total) m=ai; /*结构互换*/ ai=ai+1; ai+1=m; Output(a);void Find(ST *a)int i,t=1;char m20;printf(nEnter the name you want:);scanf(%s,m);for(i=0;iN;i+) if(!strcmp(m,) /*根据姓名匹配情况输出查找结果*/ printf(nThe result is:
44、n%s, Chinese:%d, Maths:%d, Physics:%d,Total:%dn,m,ai.chinese,ai.maths,ai.phy,ai.total); t=0; if(t) printf(nThe name is not in the list!n);链表:链表是C语言中另外一个难点。牵扯到结点、动态分配空间等等。用结构作为链表的结点是非常适合的,例如:struct nodeint data;struct node *next;其中next是指向自身所在结构类型的指针,这样就可以把一个个结点相连,构成链表。链表结构的一大优势就是动态分配存储,不会像数组一样必须在定义时确
45、定大小,造成不必要的浪费。用malloc和free函数即可实现开辟和释放存储单元。其中,malloc的参数多用sizeof运算符计算得到。链表的基本操作有:正、反向建立链表;输出链表;删除链表中结点;在链表中插入结点等等,都是要熟练掌握的,初学者通过画图的方式能比较形象地理解建立、插入等实现的过程。typedef struct nodechar data;struct node *next;NODE; /*结点*/正向建立链表:NODE *create()char ch=a;NODE *p,*h=NULL,*q=NULL;while(chdata=ch; if(h=NULL) h=p; else q-next=p; ch+; q=p; q-next=NULL; /*链表结束*/return h; 逆向建立:NODE *create()char ch=a;NODE *p,*h=NULL;while(chdata=ch; p-next=h; /*不断地把head往前挪*/ h=p; ch+; return h; 用递归实现链表逆序输出:void output(NODE *h)if(h!=NULL) output(h-next); printf(%c,h-data); 插入结点(已有升序的链表):NODE *insert(NODE *h
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年超声医学继续教育项目申报
- 2026年电能计量装置安装与接线工艺
- 2026年网络打印机安装与共享设置步骤
- 2026年模具制造精度保障体系设计与运行
- 2026年农村电商服务站运营与物流整合培训
- 2026年送配电线路工接地装置安装与测量培训
- 2026年新媒体运营数据分析与复盘方法
- 2026年大概念教学与多元智能整合实践
- 2026年儿童康复科罕见病康复支持年度计划
- 2026年员工志愿者活动组织与实施
- 2026年中国铁路兰州局集团有限公司招聘普通高校毕业生468人笔试考试备考试题及答案解析
- 2025年高中一年级下学期数学统计专项训练试卷(含答案)
- ISO9001-2026质量管理体系标准要求讲解、运用、推行培训教材
- 医院抗菌药物使用数据分析报告
- 2025中国五矿集团(黑龙江萝北石墨园区)石墨产业有限公司招聘考试历年参考题附答案详解
- (新版)中国联通政企智慧运营考试题库(含答案)
- 工业厂房通风系统设计方案
- 2025年卫生监督协管培训试题及答案
- 小儿颅内高压课件
- 精神科常见意外事件防范预案及应急处理流程
- 学平险介绍课件
评论
0/150
提交评论