郝斌数据结构自学笔记--知识点+程序源代码
郝斌数据结构自学笔记知识点+程序源代码
5_预备知识_指针_2
指针的重要性:
指针是C语言的灵魂
定义:
地址:
地址是内存单元的编号,从0开始的非负整数,范围:0-FFFFFFFF【0-4G-1】
CPU=====地址线,控制线,数据线=====内存
指针:
指针就是地址,地址就是指针。
指针变量是存放内存单元地址的变量。
指针的本质是一个操作受限的非负整数。
structStudent*pst=&st;
doublearr[3]={1.1,2.2,3.3};
double *q;
q=&arr[0];
printf(“%p\n”,q);//%p实际就是以十六进制输出
q=&arr[1];
q=printf(“%p\n”,q);//p,q相差8
无论指针指向的变量占多少个字节,指针变量统一都只占4个字节
7_如何通过函数修改实参的值
for (i=0;i<lem;i++)
printf(“%d\n”,p[i]);
}
指针变量的运算
指针变量不能相加,不能相乘,不能相除。
如果两指针变量属于同一数组,则可以相减。
指针变量可以加减一整数,前提是最终结果不能超过指针变量
p+i的值是p+i*(p所指向的变量所占的字节数)
p-i的值是p-i*(p所指向的变量所占的字节数)
//p=10;//error
ﻩj=*p;//等价于j=i;
ﻩprintf("i=%d,j=%d,*p=%d\n",i,j,*p);
ﻩreturn 0;
}
CASE2
#include<stdio.h>
程序员阿斌笔记
程序员阿斌笔记引言概述:程序员阿斌是一位经验丰富的软件开发人员,他在多年的工作中积累了大量的经验和知识。
本文将从五个大点出发,详细阐述阿斌的一些经验和心得,帮助读者更好地理解和应用软件开发的相关知识。
正文内容:1. 项目管理1.1 项目需求分析1.2 任务分配和时间规划1.3 团队协作与沟通1.4 项目风险评估1.5 项目进度控制2. 编码技巧2.1 代码规范与命名规则2.2 模块化与可重用性2.3 异常处理与错误日志2.4 单元测试与代码调试2.5 代码版本管理与协同开发3. 性能优化3.1 程序性能分析与瓶颈定位3.2 数据库优化与索引设计3.3 缓存技术与数据预加载3.4 并发控制与资源管理3.5 网络传输与数据压缩4. 安全防护4.1 用户身份认证与权限控制4.2 数据加密与防止SQL注入4.3 防止跨站脚本攻击(XSS)4.4 防止跨站请求伪造(CSRF)4.5 安全漏洞扫描与修复5. 技术学习与个人成长5.1 持续学习与技术追踪5.2 参与开源项目与技术社区5.3 阅读技术书籍与博客5.4 参加技术研讨会与培训课程5.5 分享与交流经验与心得总结:通过阿斌的经验分享,我们可以看到一个优秀程序员在项目管理、编码技巧、性能优化、安全防护以及技术学习与个人成长等方面的重要性。
良好的项目管理能够提高工作效率和质量,合理的编码技巧能够提高代码的可读性和可维护性,性能优化能够提升系统的响应速度和用户体验,安全防护能够保护用户数据的安全,而技术学习与个人成长则是保持竞争力和不断进步的关键。
作为一名程序员,我们应该不断学习和实践,提升自己的技术水平和综合能力,为软件开发领域的发展贡献自己的力量。
郝斌老师__数据结构
append_arr(&arr, -3);
append_arr(&arr, 6);
append_arr(&arr, 88);
append_arr(&arr, 11);
if ( delete_arr(&arr, 4, &val) )
{
printf("删除成功!\n");
bool delete_arr(struct Arr * pArr, int pos, int * pVal);
int get();
bool is_empty(struct Arr * pArr);
bool is_full(struct Arr * pArr);
void sort_arr(struct Arr * pArr);
void g(struct Student st)
{
printf("%d %s %d\n", st.sid, , st.age);
}
void g2(struct Student *pst)
{
printf("%d %s %d\n", pst->sid, pst->name, pst->age);
//p[i]就是主函数的a[i]
}
int main(void)
{
int a[5] = {1,2,3,4,5};
Show_Array(a, 5); //a等价于&a[0], &a[0]本身就是int *类型
//printf("%d\n", a[2]);
return 0;
郝斌C语言详细笔记(附源码)
郝斌教师的C语言:讲堂讲解全程动手敲代码,讲解细致,对于重要知识点的讲解诲人不倦,是一个可贵的C语言入门教程.在这里对教师的辛勤付出暗示感谢.之袁州冬雪创作郝斌c语言视频教程·概述:课程计划为什么学习c语言:Fortran语言主要用于迷信计算,在第三代语言中,以1980年为分水岭,分为布局化和面向对象语言.Basic语言是vb的前生,pascal语言一般是用于讲授.C语言是最重要的,其他的语言一般很少用了.布局化的代表语言是c 语言.布局化语言的数据和操纵是分离的,导致在写大项目标时候,会出现各种各样莫明其妙的问题.在面向对象的语言中c++是最复杂的语言.由于c++语言太复杂,sun公司对c++停止了改装,发生了java语言.而c#是由微软开辟的,和java相似,几乎一模一样.在高级语言的执行速度上,c是最快的,c++其次,而java和c#是最后的.Java和c#风行,主要的一个原因是可以跨平台.C语言的发展和过程:C语言的特点:·优点:代码量小,速度快,功能强大.·缺点:危险性高,开辟周期长,可移植性弱.危险性高:写同一个程序,在java中会报错,而在c中不会报错,为什么呢,因为c认为程序你想怎么写就怎么写,c语言认为你写的程序不是很离谱,他都认为你写的这个程序有特殊的含义.可以直接通过,而java则不成以.开辟周期长:c语言是面向过程的语言,面向过程的语言的特点就是在开辟大项目标时候,很容易崩溃,好比盖大楼,C语言还要造大量的砖块、钢筋等布局原资料,而C++ C# JAVA则停止了一定的继承封装等操纵,相当于原资料直接给你,你只需要用它盖楼即可.现在市场上的语言分三块C/c++:单纯的学习c是什么都做不了的.JavaC#可移植性不强:这是针对java来讲的,因为java的可移植性太强了,所以就感觉说c的可移植性不强.金山公司最主要是靠wps办公软件来发展的.Wps是c语言开辟的,其装置包比Office少了10多倍.三大操纵系统:windows,unix,linuxWindows内核是c语言写的,而外壳是c++写的.Java永远不成能写操纵系统.因为java运行速度太慢了.而linux和unix都是纯c写的.操纵系统节制了硬件,如果说操纵系统的运行速度慢,那末当我们在运行软件的时候,运行速度会更慢.为什么使用c语言写操纵系统呢,首先是因为c的运行速度快,然后是因为c可以直接节制硬件,而其他语言不成以.没有指针的语言是不克不及直接访问硬件的.C语言的应用范畴:驱动一般是用c和汇编来写的.数据库一般是用c和c++来写的C语言的重要性:虽然应用场合相对较窄,但贴近系统内核,较底层.病毒最基本的是要感染系统,数据布局,c,c++这三门语言是必须要学习的.牛人牛语:怎样学习c语言要将编程当成一项事业来运营,而不是糊口的工具.多思考,多上机. 不克不及光看,光听,而要排错,调试.在犯错误中成长.参考资料王爽写的c++也很不错学习的方针:掌握简单的算法--处理问题的方法和步调.熟悉语法规则.能看懂程序并调试程序.C语言的关键字:C语言程序的格式:一定要养成杰出的习惯:代码规范边写边保管,括号成对出现,应用空格VC6.0软件操纵:新建保管关闭(关闭空间).cpp是原始文件,可单独拷贝到其它电脑.第二讲:(14)c语言编程必备知识1.Cpu,内存条,硬盘,显卡,主板,显示器之间关系.Cpu不克不及直接处理硬盘上的数据,必须要先调入内存2.Helloword程序是如何运行起来的.3.什么是数据类型数据类型--数据的分类,对编程而言,首要思索问题是数据的输入和存储.可以分为A:基本数据类型:整型整型int --4字节一字节byte = 8 位bit 短整型short int -2长整型long int -8浮点型单精度浮点数float:存储范围小-4双精度浮点数double:存储范围大 -8Float 和 Double 都不克不及包管将小数完全准确保管.字符char:c语言中是没有字符串string -1(区别于JAVA、C#中有string且C#中 char为2字节)B:复合类型:就是把基本类型拼凑在一起布局体列举 --- 实用共用体—基本淘汰4.什么是变量变量的实质是内存中一段存储空间.Int I; i=5; I 是变量,程序向系统申请了一个内存单元,在程序运行中,i的值可以改变,但程序竣事后,其所占的空间不是释放,而是被系统收回权限.5Cpu,内存条,,操纵系统之间的关系.6变量为什么必须初始(即赋值)软件运行与内存关系(渣滓数据-9868598658)1.软件在运行前需要向操纵系统申请存储空间,在内存空间足够闲暇时,操纵系统将分配一段内存空间并将该外存中软件拷贝一份存入该内存空间中,并启动该软件运行.2.在软件运行期间,该软件所占内存空间不再分配给其他软件.3.当该软件运行完毕后,操纵系统将回收该内存空间(注意:操纵系统其实不清空该内存空间遗留下来的数据),以便再次分配给其他软件使用.《操纵系统》一门课中系统分配表中会讲到,用1标识表记标帜暗示内涵是被占用的,用0标识表记标帜暗示是闲暇的.综上所述,一个软件所分配到的空间中极可以存在着以前其他软件使用过后的残留数据,这些数据被称之为渣滓数据,所以通常情况下我们为一个变量,为一个数组,分配好存储空间之前都要对该内存空间初始化.7如何定义变量数据类型变量称号 = 赋予的值;等价于数据类型变量名;变量名 = 要赋予的值;举例子:int i = 3; 等价于 int i;i = 3;Int i,j;等价于 int i;int j;Int i,j=3 等价于 int i; int j;j=3;Int I =3, j = 5;等价于 int i; int j; I = 3;j = 5;8什么是进制–逢几进一我们规定八进制前面加0(零),十六进制前面加0x.常常使用计数制对照表:Printf的基本用法:9常量在c中是如何暗示的当个字符使用单引号括起来,多个字符串使用双引号括起来(指针、数组).在c中,默许是double类型的.在后面加F暗示当做float来处理,否则会有正告提示 --丢失部分字节.10常量以什么样的二进制代码存储在计算机中?编码:整数是以补码的形式转换为二进制代码存储在计算机浮点数是以ieee754尺度转换为二进制代码存储字符实质实际是与整数的存储方式相同,ASII码尺度.第三次课:代码规范化·可以参考林锐《高质量c/c++编程》·代码的规范化非常的重要,是学习一门编程语言的基础,代码可以允许错误,但不克不及不规范.例如:成对敲括号{} ()加空格于运算符和数字之间 I = 1 + 2;加缩进分清上下级地位.换行--停止功能区域分隔 or { }括号单独成一行.·代码规范化的好处1:整齐,他人和自己都容易看懂.2:代码规范了,代码不容易出错.3:一般的程序可以分为三块:a: 定义变量b:对变量停止操纵c: 输出值什么是字节·存储数据的单位,而且是硬件所能访问的最小单位.内存中存储的最小单位是位bit(0或1),但是硬件节制的时候不克不及切确到位,只能切确到字节(8位),是通过地址总线来节制的,而切确到位是通过软件来节制的,叫做位运算符来切确到位的.1字节 = 8 位 1K = 1024 字节1M = 1024 K 1G =1024 M 1T = 1024 G2G的内存条的总空间:2 *1024 * 1024 *1024 * 8 =4*1032分歧类型数据之间相互赋值的问题分歧数据类型之间最好不要相互转换.如果需要大白这个知识点,那末需要大白补码.什么是ASCII码以char定义变量的时候,只能使用单引号括起一个字符才是正确的.在上图中注释的最后一样是重复定义了ch的值,是错误的,而下面的ch = ‘c’是指把c赋值给ch,是正确的.上图中输出的值是98(将字符以整数%d的形式输出)Ascll码规定了ch是以哪一个值去保管,ascii码不是一个值,而是一种规定,规定了分歧的字符是以哪一个整数值去暗示.其它规定还有GB 2312 UTF-8等.字符实质上与整数的存储方式相同【字符的存储】基本的输入和输出函数的用法:第三次课Printf()将变量的内容输出到显示器上.四种用法输什么是输出节制符,什么是非输出节制符输出节制符包含如下:Printf为什么需要输出节制符:·01组成的代码可以暗示数据也可以暗示指令.必须要有输出节制符告诉他怎么去解读.·如果01组成的代码暗示的是数据的话,那末同样的01代码组合以分歧的格式输出就会有分歧的输出成果,所以必须要有输出节制符.在上图中,int x =47,如果前面加0(零)048暗示的是八进制,如果前面加0x(零x)0X47则暗示的是十六进制,而在输出的时候,则是o(字母o)暗示八进制,ox(字母o,x)暗示十六进制.非输出节制符:非输出节制符在输出的时候会原样输出.Scanf()通过键盘将数据输入到变量中有两种用法:示例:非输入节制符:在输入的时候也会原样输入.但是强烈建议:在使用scanf的时候,不使用非输入节制符.给多个变量赋值:需要记住,非节制符需要原样输入.如何使用scanf编写出高质量代码运算符:算术运算符:加(+),减(—)乘(*)除(/)取余(%)关系运算符:>, >=, <, <=, !=,逻辑运算符:!(非),&&(且),||(或)赋值运算符:=, +=,*=, /=例如:a+=3是等价于a=a+3,a/=3等价于a=a/3其优先级别是算术>关系>逻辑>赋值.取余的成果的正负只和被除数有关.第四节流程节制(第一个重点):1.什么是流程节制程序代码执行的顺序.2.流程节制的分类顺序执行选择执行定义:某些代码可以执行,可以不执行,有选择的执行某些代码.分类:ifIf最简单的用法:如果想节制多个语句的执行或者不执行,那末需要使用{}括起来.3.if…else…的用法:if…elseif…else的用法:C错误的if…elseif…else语句:在上图中,当执行到哈哈那句时,下面的else将会被算作别的一个语句来执行,而在我们的c语言中,没有以else开首的语句.所以会出错.If 实例:If罕见的问题:变量的替换:求三个数字的大小:C语言罕见误区:纸山君素数:只能被1和自己整除的数,如1,5,9等.回文数:正着写和倒着写一样的数.如1221,121,等编程实现求一个十进制数字的二进制形式:求一个数字的每位是奇数的数字取出来组合形成的新数字.求一个数字到过来的数字.1:如果不懂,那末就看答案.看懂答案在敲.没错误了,在测验测验改.如何看懂一个程序:1.流程:2.每一个语句的功能:3.试数:对一些小算法的程序:1.测验测验自己编程终局.2.处理不了,看答案.3.关键是把答案看懂.4.看懂之后测验测验自己修改程序,且知道修改之后程序的分歧输出成果的含义.5.照着答案去敲6.调试错误7.不看答案,自己独立把程序编出8.如果程序实在是完全无法懂得,就把他背会.空语句的问题:在上图中,最终的成果会是AAAA,BBBB,程序也不会报错,为什么呢,因为在程序执行的时候,会在;哪里认为是一个空语句.也就是说,如果if成立,那末执行空语句.If罕见错误解析(重点)上面这个程序是错误的,为什么呢,在该程序中,总的有4个语句,而在以else开首的阿谁语句中是有错误的,因为在c语言中是没有以else开首的这种语法.在上面这个程序中,最终的值是AAAA,虽说后面的3>1也知足条件,但是当3>2知足条件后,该if语句就会终止,后面的语句是不会在执行的.既然7行要写表达式,就要写if.循环的定义、分类.定义:某些代码会被重复执行.分类:for while do……while在上图中,先执行1,在执行2,2如果成立,标记着循环成立,那末在执行4,最后在执行3,3执行完后代表一次循环完成,然后在执行2.以此类推.1永远只执行一次.++I 等价于 i+1求1-10的所有奇数的和:求1-12之间的所有能被3整除的数字之和:For所节制的语句:在上图中,for默许只能节制一个语句,但是如果要节制多个语句时候,那末需要使用{}把语句括起来.求1+1/2+1/3….1/100的和在上图中,重点是强制数据类型转换也就是(float)(i)那句:如果把print那句换为下面这句会怎么样呢:也是错的,为什么呢,因为i是整型,1也是整型,所以不管你怎么转换也是整型啊,如果想要这样写的话,那末我们需要把1改成也可以的.也就是:试数详细步调举例:浮点数存取:求1-100之间所有奇数的和:求1-100之间的奇数的个数:求1-100之间奇数的平均值:求1-100之间的奇数之和,在求1-100之间的偶数之和:多个for循环的嵌套使用:整体是两个语句.上图中,先执行1,在执行2,如果2成立,执行4,在执行5,如果5成立执行A,在执行6,在执行5,如果5不成立,意味着外面的循环竣事,然后执行3,在执行2,如果2成立又执行4,在执行5,如果5成立在执行6,在执行5,如果5不成立,在执行3,在执行2,如果2不成立,意味着本次循环竣事,在执行B,在上图中,需要注意的是,如果2成立的话,那末每次4都需要执行.进制之间的转换:如234为5进制,那末转换成10进制是多少:2x5x5+3x5+4的值就是转换成的10进制.234e是16进制,转换成2进制是多少:2x16x16x16+3x16x16+4x16+12的值就是转换成10进制的值.注意上面的规律.那末把十进制转换成r进制呢,其实很简单,就是把10进制数除以r,直到商是0的时候.然后取余数,余数倒序摆列:琐碎的运算符:自增:自减:和自增一样.三目运算符:最终的输出成果是1.逗号表达式:最终成果是6.上图中,逗号是个顺序点,即所有的副作用必须在下个语句前生效,其最后成果为1,j+2只是发生姑且值,并没有把j+2的值赋个j.如果写成j+=2,那最后的值则变成5.For的嵌套使用举例:上例中输出的成果是9个哈哈,1个嘻嘻.在上图中,整个程序分成3个语句,输出的成果是3个嘿嘿,3个哈哈,1个嘻嘻.其成果是:While(先付钱后吃饭)1:执行的顺序:2:与for的相互比较:用for来求1-100之和:用while实现1-100之和.只需要把for语句替换为:For和while是可以相互转换的,可以用下面的表达式来暗示:While和for在逻辑上完全等价,但是for在逻辑上更强.更容易懂得,更不容易出错.推荐多使用for.3:while举例:试数:通过上面的试数,应该能很快的懂得回文数的算法.4:什么时候使用while,什么时候使用for:没法说,用多了就自然而然知道了Do…while(先吃饭后付钱)一元二次方程:Switch的用法:电梯程序:Case是程序的入口,当进入程序后,程序会从上往下执行,如果有break,那末会中断程序,如果没有,那末会一直执行.Break的用法:在多层循环中,Break只能终止他最近的循环.在多层switch中,break也是只能终止间隔他最近的switch.Break只能用于循环和switch,不克不及用于if.如果用于if,必须要当循环中嵌套if的时候.Continue的用法:上图中,如果执行continue,那末C,D将不会被执行,会执行3.在上图中,如果执行了continue,那末后面的C,D将不再执行,而会去执行表达式.数组:--非重点数组的使用:为什么需要数组1:为了处理大量同类型数据的存储和使用问题.2:用数组可以摹拟现实世界.Int a[25]:一维数组,可以当做一个线性布局.Int a[8][6]:可以当做一个平面,意思是8行6列.有48个元素.Int a[3][4][5]:可以当做一个三维平面.Int a[3][4][5][6]:可以当做一个四维空间.数组的分类一维数组怎样定义一维数组:·为n个变量分配存储空间:数组内存空间是持续的.·所有的变量类型必须相同:数组不成能第一个元素是整形,第二个元素是浮点型.·所有变量所占用的字节必须相等.例子:int [5]数组不是学习重点的原因?数组一旦定义,其长度是死的.有关一维数组的操纵 --都需要自己别的编程序实现而我们通常常使用第三方软件(工具)如数据库等方便直接地实现.对数组的操纵:初始化赋值排序求最大/小值倒置查找拔出删除·初始化:上图中a[5]前面如果没有加上数据类型,那末这里的a[5]不是指一个数组,其中的5只的是下标.上图中,数组的5个元素不是用a来代表的,是用a0,a1…a4来代表的,所以说数组名a代表的不是数组的5个元素,数组名代表的是数组的第一个元素的地址.·赋值把一个数组元素给全部倒过来:·排序·求最大/小值·倒置·查找·拔出·删除二维数组:二维数组的初始化:输出二维数组内容:多维数组:是否存在多维数组:不存在因为内存是线性一维的,在内存中是不分行不分列的.N维数组可以当做每一个元素是n-1维数组的一维数组.函数(第二个重点):为什么需要函数:·防止了重复性操纵.·有利于程序的模块化.(自上而下,逐步细化,大问题分解成小问题)用它作为参照,可以对比 JAVA 和C#面向对象的思想.C语言基本单位是函数,C#、C++和JAVA基本单位是类.什么叫做函数·逻辑上:可以完成特定功能的独立的代码块.物理上:可以接纳数据【也可以不接纳数据】,可以对接纳的数据停止处理【也可以分歧错误数据停止处理】,可以将数据处理的成果返【也可以没有返回值】.·总结:函数是个工具,他是为了处理大量近似问题而设计的,函数可以当做黑匣子(外部原理不必管).如何定义函数·函数的返回值,函数的名字(函数的形参列表){函数的执行体}·函数定义的实质:详细描绘函数之所以可以实现某个特定功能的详细方法.函数中的变量叫做形参;数组中的变量叫元素.一旦函数执行完毕,其外部的形参所占空间就被收回.·return表达式的含义:Return是终止被调函数,向主调函数返回表达式的值,如果表达式为空,则只终止函数,不向被主函数返回任何值.Break是用来终止(就近的)循环和switch语句.而return是用来终止被调函数的.·函数返回值的类型,也称为函数的类型,因为如果函数名前的返回值类型和函数执行体中的return表达式中表达式的类型分歧的话,则最终函数返回值的类型以函数名前的返回值类型为准.例:在上图中,函数的返回值以函数前的数值类型为准.函数的分类·有参函数和无参函数.·有返回值和无返回值.·库函数和用户自定义函数.·普通函数和主函数(main函数)1:一个程序有且只有一个主函数.2:主函数可以调用普通函数,普通不克不及调用主函数.3:普通函数可以相互调用.4:主函数是程序的入口,也是函数的出口.5:值传递函数和地址传递函数.断定一个数是否是素数:使用函数断定一个数是否是素数:函数和程序的调用应该注意的地方:函数的声明:当函数没有返回值时,那末规范的写法是要在函数中写明void的.在上图中,第一个void暗示没有返回值,而第二个void暗示不接纳形参,也就是函数不接纳数据.如果想把函数写在程序的后面,那末需要写函数声明:函数声明的含义是告诉编译器f()是个函数名.如果不加函数声明,那末编译器在编译到f的时候,不知道f是个什么,如果加了函数声明,那末编译器编译到f的时候,就知道f是个函数.·需要注意的是,调用语句需要放在定义语句的后面,也就是说,定义函数的语句要放在调用语句的前面.如果函数调用写在了函数定义的前面,则必须加函数前置声明,函数前置声明的作用是:1:告诉编译器即将可以出现的若干个字母代表的是一个函数.“打招呼”2:告诉编译器即将可以出现的若干个字母所代表的函数的形参和返回值的详细情况.3:函数声明必须是一个语句,也就是在函数声明后需加分号.4:对库函数的声明也就是系统函数.是通过#include<库函数所在的文件的名字.h>形参和实参要求:1:形参和实参个数是一一对应的.2:形参和实参的位置也是一一对应的.3:形参和实参的数据类型需要相互兼容.·如何在软件开辟中合理的设计函数来处理实际问题.求1到某个数字之间的数是否是素数,并将他输出:合理设计函数1合理设计函数2:合理设计函数3:合理的设计函数4:。
郝斌c语言详细笔记
郝斌c语言详细笔记郝斌C语言详细笔记C语言是一门广泛应用于系统编程、嵌入式系统和游戏开发等领域的高级编程语言。
郝斌老师的C语言详细笔记是一份非常优秀的学习资料,它详细介绍了C语言的基础知识和高级应用,对于初学者和进阶者都非常有帮助。
一、基础知识1. 数据类型C语言中的数据类型包括基本数据类型和派生数据类型。
基本数据类型包括整型、浮点型、字符型和布尔型,而派生数据类型包括数组、结构体、共用体和指针等。
在使用数据类型时,需要注意它们的取值范围、精度和存储空间等方面的问题。
2. 运算符C语言中的运算符包括算术运算符、关系运算符、逻辑运算符、位运算符和赋值运算符等。
在使用运算符时,需要注意它们的优先级和结合性等方面的问题。
3. 控制语句C语言中的控制语句包括条件语句、循环语句和跳转语句等。
在使用控制语句时,需要注意它们的语法和逻辑结构等方面的问题。
二、高级应用1. 函数函数是C语言中的重要概念,它可以将程序分解为多个模块,提高程序的可读性和可维护性。
在使用函数时,需要注意它们的参数传递、返回值和作用域等方面的问题。
2. 数组和指针数组和指针是C语言中的重要数据结构,它们可以用于处理复杂的数据类型和数据结构。
在使用数组和指针时,需要注意它们的声明、初始化和访问等方面的问题。
3. 文件操作文件操作是C语言中的重要应用之一,它可以用于读写文件、处理文本和二进制数据等。
在使用文件操作时,需要注意文件的打开、关闭和读写等方面的问题。
总之,郝斌老师的C语言详细笔记是一份非常优秀的学习资料,它涵盖了C语言的基础知识和高级应用,对于初学者和进阶者都非常有帮助。
在学习C语言时,我们需要认真阅读笔记中的内容,理解其原理和应用,同时还需要进行实践和练习,以提高自己的编程能力。
郝斌老师c语言笔记
互换两个数子:
#include <stdio.h>
#include <stdlib.h>
void huhuan(int a,int b)
{
int t;
t = a;
b = t;
return ;
}
int main()
{
int a = 3;
int b = 5;
huhuan (a,b);
printf ("a = %d,b = %d\n",a,b);
Register寄存器return返回short短的signed有符号的sizeof运算符static静止的struct结构体switch开关typedef定义类型
Unsigned无符号整数union联合void空的;无效的volatile不稳定的易失的易变的while当directive指示符fatal致命的precompiled预编译;先行编译
huhuan (&a,&b);
printf ("a = %d,b = %d\n",a,b);
return 0;
}
void huhuan(int * a,int * b)
{
int * t;//如果要互换,t必须定义成int*类型。
t = p;
p = q;
q = t;
}//这个程序依然不是正确的,因为只是改变了p和q的内容对实参依然没有实际的作用效果。
int main(void)
{
int a[2][3] = {{12,34,45},{423,2342,24}};
int i,j;
for (i = 0;i<2;++i)
郝斌 数据结构
链表new1# include <stdio.h># include <malloc.h># include <stdlib.h>struct node{int data; //存放数据本身struct node *next;};struct node *CreateList( void ){struct node *pH = NULL;int len; //存放节点的个数int i;int temp; //存放用户暂时存入的节点的值域的值struct node *pNew = NULL;//存放临时分配好的节点本身的内容struct node *pTail = NULL;//pTail永远指向链表的尾节点//创建一个头节点pH = ( struct node * )malloc( sizeof( struct node ) );if( NULL == pH ){puts( "动态内存分配失败" );exit( -1 );}pH ->next = NULL;pTail = pH;printf( " 请输入节点的个数:len = " );scanf( " %d ", &len );for( i = 0; i < len; ++ i ){printf( " 请输入第%d 节点的值: ", i + 1 );scanf( " %d ", &temp );//临时构造一个节点pNew = ( struct node * )malloc( sizeof( struct node ) );if( NULL == pNew )//如果p所指向的节点存在{}}}int main ( void ){struct node *pH = NULL;pH = CreateList();//通过CreateList()函数创建一个链表,j将该链表的首地址发松给pH TraverseList( ph );//遍历整个单链表return 0;}跨函数使用内存malloc//2012年9月9日晚上# include <stdio.h># include <malloc.h>struct Student{int sid;int age;};struct Student *CreateStudent( void );void ShowStudent( struct Student * );int main( void ){struct Student *ps;ps = CreateStudent();ShowStudent( ps );return 0;}struct Student *CreateStudent( void ){struct Student *p = ( struct Student * )malloc( sizeof( struct Student ) );p->sid = 99;p->age = 88;return p;void ShowStudent( struct Student *pst ){printf( " %d %d\n ", pst->sid, pst->age );}快速排序# include <stdio.h>void QuickSort( int *a, int low, int high );int FindPos( int *a, int low, int high );int main( void ){int a[6] = { 2, 1, 0, 5, 4, 3 };int i;QuickSort( a, 0, 5 );//第二个参数表示第一个元素的下标,第三个参数表示最后一个元素的下标for( i = 0; i < 6; ++ i )printf( "%d ", a[i] );printf( "\n" );return 0;}void QuickSort( int *a, int low, int high ){int pos;if( low < high ){pos = FindPos( a, low, high );QuickSort( a, low, pos - 1 );QuickSort( a, pos + 1, high );}}int FindPos( int *a, int low, int high ){int val = a[low];while( low < high ){while( low < high && a[high] > val )-- high;a[low] = a[high];while( low < high && a[low] <= val )++ low;a[high] = a[low];}//终止while循环之后low和high一定相等的a[low] = val;return low;//或者return high;}连续存储数组的算法1//2012年9月10日晚上# include <stdio.h># include <malloc.h># include <stdlib.h>//使用exit( -1 );需要定义的头文件//定义了一个数据类型,没有定义变量struct Arr{int *pBase;//存储的是数组第一个元素的地址int len;//数组所能容纳的最大元素的个数int cnt;//当前所在有效的个数};void init_arr( struct Arr *pArr, int length );//分号不能省bool append_arr();//追加bool insert_arr();bool delete_arr();int get();bool is_empty( struct Arr *pArr );bool is_full();bool sort_arr();void sort_arr();void show_arr( struct Arr *pArr );void inversion_arr();int main( void ){struct Arr arr;init_arr( &arr, 6 );//地址只占四个字节show_arr( &arr );//printf( " %d\n ", arr.len );return 0;}void init_arr( struct Arr *pArr, int length ){pArr->pBase = ( int * )malloc( sizeof( int )*length );//pArr->len = 99;if( NULL == pArr->pBase ){printf( "动态内存分配失败!\n" );exit( -1 );//终止整个程序}else{pArr->len = length;pArr->cnt = 0;}return;}bool is_empty( struct Arr *pArr ){if( 0 == pArr->cnt ){return true;}elsereturn false;}void show_arr( struct Arr *pArr ){/*if( 数组为空)提示用户数组为空else输出数组有效内容*/if( is_empty( pArr ) )printf( "数组为空!\n" );}else{for( int i = 0; i < pArr->cnt; ++i )printf( " %d ", pArr->pBase[i] );printf( "\n" );}}连续存储数组的算法2//2012年9月11日早上# include <stdio.h># include <malloc.h># include <stdlib.h>//使用exit( -1 );需要定义的头文件//定义了一个数据类型,没有定义变量struct Arr{int *pBase;//存储的是数组第一个元素的地址int len;//数组所能容纳的最大元素的个数int cnt;//当前所在有效的个数};void init_arr( struct Arr *pArr, int length );//分号不能省bool append_arr( struct Arr *pArr, int val );//追加bool insert_arr( struct Arr *pArr, int pos, int val );//pos的值从1开始bool delete_arr( struct Arr *pArr, int pos, int *pVal );int get();bool is_empty( struct Arr *pArr );bool is_full( struct Arr *pArr );void sort_arr( struct Arr *pArr );void show_arr( struct Arr *pArr );void inversion_arr( struct Arr *pArr );//倒置int main( void ){struct Arr arr;int val;init_arr( &arr, 6 );//地址只占四个字节show_arr( &arr );append_arr( &arr, 1 );append_arr( &arr, 2 );append_arr( &arr, 3 );append_arr( &arr, 4 );if ( delete_arr( &arr, 1, &val ) ){printf("删除成功\n");printf("你删除的元素是:%d\n", val);}elseprintf("删除失败\n");/*append_arr( &arr, 2 );append_arr( &arr, 3 );append_arr( &arr, 4 );append_arr( &arr, 5 );insert_arr( &arr, 6, 99 );append_arr( &arr, 6 );append_arr( &arr, 7 );//这个也是追加不成功的,因为是只是分配了6个数if( append_arr( &arr, 8 ) ){printf( "追加成功\n" );}else{printf( "追加失败\n" );}*/show_arr( &arr );inversion_arr( &arr );printf("倒置之后的内容是:\n");show_arr( &arr );sort_arr( &arr ); //呜呜,这里哪里是出错了呢??printf("排列\n");show_arr( &arr );//printf( " %d\n ", arr.len );return 0;}void init_arr( struct Arr *pArr, int length ){pArr->pBase = ( int * )malloc( sizeof( int )*length );//pArr->len = 99;if( NULL == pArr->pBase ){printf( "动态内存分配失败!\n" );exit( -1 );//终止整个程序}else{pArr->len = length;pArr->cnt = 0;}return;}bool is_empty( struct Arr *pArr ){if( 0 == pArr->cnt ){return true;}elsereturn false;}bool is_full( struct Arr *pArr ){if( pArr->cnt == pArr->len )return true;elsereturn false;}void show_arr( struct Arr *pArr ){/*if( 数组为空)提示用户数组为空else输出数组有效内容*/if( is_empty( pArr ) ){printf( "数组为空!\n" );}else{for( int i = 0; i < pArr->cnt; ++i )printf( " %d ", pArr->pBase[i] );printf( "\n" );}}bool append_arr( struct Arr *pArr, int val ){//满时返回falseif( is_full( pArr ) )return false;//不满时追加elsepArr->pBase[pArr->cnt] = val;( pArr->cnt ) ++;return true;}bool insert_arr( struct Arr *pArr, int pos, int val ){int i;//第一中情况,数组里面全满时if( is_full( pArr ) )return false;//第二种情况,数组里面不为满时if( pos < 1 || pos > pArr->cnt + 1 )return false;//把原来的第pos的位置和之后的数都向前移动for( i = pArr->cnt - 1; i >= pos - 1; --i ){pArr->pBase[i + 1] = pArr->pBase[i];}//把第pos位置插入新的值pArr->pBase[pos - 1] = val;( pArr->cnt ) ++;//个数加一return true;}bool delete_arr( struct Arr *pArr, int pos, int *pVal ){int i;if( is_empty( pArr ) )return false;if( pos < 1 || pos > pArr->cnt )return false;*pVal = pArr->pBase[pos - 1];for( i = pos; i < pArr->cnt; ++i ) //cnt表示数组有效的个数{pArr->pBase[i - 1] = pArr->pBase[i]; //这里要前移一个数,所以上面的可以i <= pArr->cnt - 1}pArr->cnt --; //删除了一个数组个数,所以有效个数要相应的减一return true;}void inversion_arr( struct Arr *pArr ){int i = 0;int j = pArr->cnt - 1;int t;while( i < j ){t = pArr->pBase[i];pArr->pBase[i] = pArr->pBase[j];pArr->pBase[j] = t;++ i;-- j;}return;}void sort_arr( struct Arr *pArr ){int i, j, t;for( i = 0; i < pArr->cnt; ++i ){for( j = j + 1; j < pArr->cnt; ++ j ){if( pArr->pBase[i] > pArr->pBase[j] ){t = pArr->pBase[i];pArr->pBase[i] = pArr->pBase[j];pArr->pBase[j] = t;}}}}链表//2012年9月12日早上离散存储[链表]定义:n个节点离散分配彼此通过指针相连每个节点只有一个前驱节点,每个节点只有后续节点首节点没有前驱节点,尾节点没有后续节点术语:首节点:第一个有效的节点尾节点:最后一个有效的节点头节点:头节点额数据类型和首节点类型一样首节点前一个没有存放有效数据加头节点的目的主要是为了方便链表的操作头指针:指向头节点的指针变量尾指针:指向尾节点的指针如果希望通过一个函数来对链表进行处理,我们至少需要接受链表的哪些参数因为我们通过头指针可以推算出链表的其他信息分类:单链表双链表:每一个节点有两个指针域循环链表:能通过任何一个节点找到所有的节点非循环链表算法:遍历查找清空销毁求长度排序删除节点插入节点typedef struct node{int data;struct node *pNext;}NODE, *PNODE;PNODE p = ( PNODE )malloc( sizeof( NODE ) );free( p );//删除p指向节点所占的内存,不是删除p本身所占的内存p->pNext;//p所指向结构体变量中的pNext成员本身删除p所节点的后面节点先临时定义一个指向p后面节点的指针rr = p->pNext;//r所指向后面的那个节点p->pNext = r->pNext;free(r);链表创建和链表遍历算法的演示//2012年9月12日早上# include <stdio.h># include <malloc.h># include <stdlib.h>typedef struct Node{int data;struct Node *pNext;}NODE, *PNODE;//函数的声明PNODE create_list(void);void traverse_list( PNODE pHead );int main( void ){PNODE pHead = NULL;//等价于struct Node *pHead = NULL;pHead = create_list();//创建一个非循环单链表,并将该链表的头节点的头结点的地址赋给pHeadtraverse_list( pHead );return 0;}PNODE create_list(void){int len;//用来存放节点有效节点的个数int i;int val;//用来临时存放用户输入的节点的值//分配了一个不存放有效数据的头节点PNODE pHead = ( PNODE )malloc( sizeof( NODE ) );if( NULL == pHead ){printf( " 分配失败,程序终止" );exit( -1 );}PNODE pTail = pHead;//pTail指向链表的尾指针,刚开始时尾指针后头指针指向的相同pTail->pNext = NULL;printf( " 请输入你需要生成的链表节点的个数:len = " );//scanf( " %d ", &len ); //注意了,这里要先打一个空格,在输入一个数字,因为%d前面有个空格,所以......scanf( "%d", &len );for( i = 0; i < len; ++i ){printf(" 请输入第%d个节点的值: ", i + 1);scanf( "%d", &val );PNODE pNew = ( PNODE )malloc( sizeof( NODE ) );if( NULL == pNew ){printf( " 分配失败,程序终止" );exit( -1 );}//把新生成的节点挂在尾节点的后面pNew->data = val;pTail->pNext = pNew;pNew->pNext = NULL;pTail = pNew;//}return pHead;}void traverse_list( PNODE pHead ){PNODE p = pHead->pNext;while( NULL != p ){printf( " %d ", p->data );p = p->pNext;}printf( " \n " );return;//意思是告诉别人程序已经结束}每一个链表节点的数据类型该如何处理的问题//2012年9月11日晚上# include <stdio.h>typedef struct Node{int data;//数据域struct Node *pNext;//指针域}NODE, *PNODE;int main( void ){return 0;}排序:冒泡出入选择快速排序归并排序排序和查找的关系排序是查找的前提排序重点Typedef的用法1# include <stdio.h>//typedef int lisi; //为int再重新多取一个名字,lisi等价于inttypedef struct Student{int sid;char name[100];char sex;}ST;int main( void ){struct Student st; //等价于ST st;struct Student *ps = &st; //等价于ST *PS;ST st2;st2.sid = 200;printf("%d\n", st2.sid);return 0;}Typedef的用法2# include <stdio.h>typedef struct Student{int sid;char name[100];char sex;}*PST; //PST等价于struct Student *int main( void ){struct Student st;PST ps = &st;ps->sid = 99;printf( "%d\n", ps->sid );return 0;}Typedef的用法3# include <stdio.h>typedef struct Student{int sid;char name[100];char sex;}*PSTU, STU;//等价于STU代表struct Student, PSTU代表了struct Student *int main( void ){STU st;//struct Studtn st;PSTU ps = &st;//struct Student *ps = &st;ps->sid = 99;printf( "%d\n", ps->sid );return 0;}1到100相加# include <stdio.h>long sum( int n ){//用递归实现if( 1 == n )return 1;elsereturn sum( n - 1 ) + n;/*//用循环实现long s = 0;int i;for( i = 1; i <= n; ++i )s += i;return s;*/}int main( void ){printf( "%d\n", sum(100) );return 0;}//2012年9月17日早上到2012年9月18日早上递归定义:一个函数自己直接或间接调用自己举例:1)1 + 2 + 3 + ...100的和2)求阶乘3)汉诺塔4)走迷宫递归满足三个条件1)递归必须得有一个明确的中止条件2)该函数所处理的数据规模必须在递减3)这个转化必须是可解的递归和循环递归:1)易于理解2)速度慢3)存储空间大循环:1)不易理解2)速度快3)存储空间小递归的应用数和森林就是以递归的方式定义的数和图很多算法都是以递归来实现的很多数学公式就是以递归的方式定义的菲波拉契//2012年9月18日早上# include <stdio.h>void hannuota( int n, char A, char B, char C ){/*如果是1个盘子直接将A柱子上的盘子从A移动到C否则先将A柱子上的n-1个盘子借助于C移动到B直接将A柱子上的盘子从A移到C最后将B柱子上的n-1借助A移动到C*/if( 1 == n ){printf( "将编号为%d的盘子直接从%c柱子%c柱子\n", n, A, C );}else{hannuota( n-1, A, C, B );printf( "将编号为%d的盘子直接从%c柱子%c柱子\n", n, A, C );hannuota( n-1, B, A, C );}}int main( void ){char ch1 = 'A';char ch2 = 'B';char ch3 = 'C';int n;printf( "请输入要移动的盘子个数:" );scanf( "%d", &n );hannuota( n, 'A', 'B', 'C' );}阶乘的递归实现# include <stdio.h>//假定是1或大于1的值long f( long n ){if( 1 == n )return 1;elsereturn f( n - 1 ) * n;}int main( void ){printf( "%d\n", f(3) );return 0;} 阶乘的循环使用//程序实现不了功能噢# include <stdio.h>int main( void ){int val;int i, mult;printf( "请输入一个数字:" );printf( "val = " );scanf( "%d", &val );for( i = 1; i <= val; ++i )mult = mult * i;printf( "%d的阶乘是:%d\n", val, mult );return 0;}队和列//2012年9月14日早上到2012年9月17日早上队列定义:一种可以实现"先进先出"的存储结构分类链式队列用链表实现静态队列用数组实现静态队列通常都必须是循环队列循环队列1.静态队列为什么必须是循环队列2.循环队列需要几个参数确定及其含义两个参数来确定(front和rear)2个参数不同场合有不同的含义建议初学者先记住,然后慢慢体会1)队列初始化front和rear的值都是零2)队列非空front代表的是队列的第一个因素rear代表的是队列的最后一个有效元素的下一个元素3)队列空front和reard的值相等,单不是零3.循环队列各个参数含义建议初学者先记住,然后慢慢体会1)队列初始化front和rear的值都是零2)队列非空front代表的是队列的第一个因素rear代表的是队列的最后一个有效元素的下一个元素3)队列空front和reard的值相等,单不是零4.循环队列入队伪算法讲解两部完成:1)将值存入r所代表的位置2)rear = ( rear+1 ) % 数组的长度5.循环队列出队伪算法讲解front = ( front+1 ) % 数组的长度6.如何判断循环队列是否为空如果front与rear的值相等则该队列就一定为空7.如何判断循环队列是否已满预备知识:( front和rear没有任何关系)front的值可能比rear大也完全有可能比rear小当然也可能相等两种方式:1)多增加一个标志参数2)少用一个元素[通常使用第二种方式]用c伪算法表示就是:如果r和f的值紧挨着,则队列已满if( (r + 1)%数组长度== f )已满else不满队列算法入队出队队列的具体应用所有和时间有关的操作都与队列有关循环队列程序的演示/2012年9月17日早上# include <stdio.h># include <malloc.h>typedef struct Queue{int *pBase;int front;int rear;}QUEUE;void init( QUEUE * );bool en_queue( QUEUE *, int val );//入队void traverse_queue( QUEUE * );bool full_queue( QUEUE * );bool out_queue( QUEUE *, int * );//出队bool empty_queue( QUEUE * );int main( void ){QUEUE Q;int val;init( &Q );en_queue( &Q, 1 );en_queue( &Q, 2 );en_queue( &Q, 3 );en_queue( &Q, 4 );en_queue( &Q, 5 );en_queue( &Q, 6 );en_queue( &Q, 7 );en_queue( &Q, 8 );en_queue( &Q, 9 );traverse_queue( &Q );if ( out_queue( &Q, &val ) ){printf( "出队成功,队列出队的元素是%d\n", val );}else{printf( "出队失败!\n" );}traverse_queue( &Q );return 0;}void init( QUEUE *pQ ){pQ->pBase = ( int * )malloc( sizeof( int )*6 );pQ->front = 0;pQ->rear = 0;}bool full_queue( QUEUE *pQ ){if( ( pQ->rear + 1 ) % 6 == pQ->front ){return true;}elsereturn false;}bool en_queue( QUEUE *pQ, int val ){if( full_queue( pQ ) ){return false;}else{pQ->pBase[pQ->rear] = val;pQ->rear = ( pQ->rear + 1 ) % 6;return true;}}void traverse_queue( QUEUE *pQ ){int i = pQ->front;while( i != pQ->rear ){printf( "%d ", pQ->pBase[i] );i = ( i + 1 ) % 6;}printf("\n");return;}bool empty_queue( QUEUE *pQ ){if( pQ->front == pQ->rear )return true;elsereturn false;}bool out_queue( QUEUE *pQ, int *pVal ) {if( empty_queue( pQ ) ){return false;}else{*pVal = pQ->pBase[pQ->front];pQ->front = (pQ->front + 1) % 6;return true;}树测试# include <stdio.h># include <stdlib.h>int main ( void ){int i;charchar *ptr1[4]={"china","chengdu","sichuang","chongqin"};for( i = 0; i < 4; i ++ ){printf( "%s\n", ptr1[i] );}}树非线性结构数树定义专业定义:1)有且只有一个称为根的节点2)有若干个互不相交的子树,这些子树本身也是一课树通俗的定义:1)树是由节点和边组成2)每个节点只有一个父节点但可以有多个子节点3)但有一个节点例外,该节点没有放节点,此节点称为根节点专业术语节点父节点子节点子孙堂兄弟深度:从根节点到底层节点的层数称之为深度根节点是第一层叶子节点:没有子节点的节点非终端节点:实际就是非叶子节点(有子节点的节点)度:子节点的个数称为度树分类一般树任意一个子节点的个数都不受限制二叉树任意一个节点的子节点的个数最多两个,且子节点的个数不可以更改分类:一般二叉树满二叉树在不增加树的层数的前提下,无法再添加一个节点的二叉树就是满二叉树完全二叉树如果只是删除满二叉树最底层最右边的连续若干个节点,这样形成的二叉树就是完全二叉树森林n个互不相交的树的集合树的存储森林的存储二叉树的存储连续存储[完全二叉树](只能是这样子存储)优点:查找某个节点的父节点和子节点(也包括有没有子节点)很快缺点:耗用内存空间过大链式存储一般树的存储双亲表示法求父节点方遍孩子表示法求子节点方便双亲孩子表示法求父节点和子节点都很方便二叉树表示法把一个普通的树转化成二叉树来存储具体的转化方法:设法保证任意一个节点的左指针域指向它的第一个孩子右指针域指向他的下一个兄弟只要能满足此条件,就可以把一个普通树转化成二叉树一个普通树转化成的二叉树一定没有右子树森林的存储先把森林转化成二叉树,在存储二叉树操作遍历先序遍历[先访问根节点]先访问根节点再先序访问左子树再先序访问右子树中序遍历[中间访问根节点]中序遍历左子树再访问根节点再中序遍历右子树后续遍历[最后访问根节点]中序遍历左子树中序遍历右子树再访问根节点已知二中遍历序列求原始二叉树通过先序和中序或者中序和后序我们可以还原原始的二叉树但是通过先序和后序是无法还原原始的二叉树的换种说法:只有通过先序和中序,或者中序和后序我们才可以唯一的确定的二叉树应用树是数据库中数据组织一种重要形式操作系统子父进程的关系本身就是一颗树面向对象语言中类的继承关系本身就是一棵树赫夫曼树数操作链式二叉树遍历具体程序演示# include <stdio.h># include <malloc.h>struct BTNode{int data;struct BTNode *pLchild;//p是指针L是左child是孩子struct BTNode *pRchild;};void PreTraverseBTree( struct BTNode * pT );void InTraverseBTree( struct BTNode * pT );void PostTraverseBTree( struct BTNode * pT );struct BTNode *CreateBTree( void );int main( void ){struct BTNode *pT = CreateBTree();printf( "先序\n" );PreTraverseBTree( pT );//先序printf( "中序\n" );InTraverseBTree( pT );//中序printf( "后序\n" );PostTraverseBTree( pT );//后序return 0;}void PreTraverseBTree( struct BTNode * pT ) {/*伪算法先访问根节点再先序访问左子树再先序访问右子树*/if( pT != NULL ){printf( "%c\n", pT->data );if( NULL != pT->pLchild ){PreTraverseBTree( pT->pLchild );}if( NULL != pT->pRchild ){PreTraverseBTree( pT->pRchild );//pT->pLchild可以代表整个左子树}}}void InTraverseBTree( struct BTNode * pT ){if( pT != NULL ){if( NULL != pT->pLchild ){InTraverseBTree( pT->pLchild );}printf( "%c\n", pT->data );if( NULL != pT->pRchild ){InTraverseBTree( pT->pRchild );//pT->pLchild可以代表整个左子树}}}void PostTraverseBTree( struct BTNode * pT ) {if( pT != NULL ){if( NULL != pT->pLchild ){InTraverseBTree( pT->pLchild );}if( NULL != pT->pRchild ){InTraverseBTree( pT->pRchild );//pT->pLchild可以代表整个左子树}printf( "%c\n", pT->data );}}struct BTNode *CreateBTree( void ){struct BTNode *pA = ( struct BTNode * )malloc( sizeof( struct BTNode ) );struct BTNode *pB = ( struct BTNode * )malloc( sizeof( struct BTNode ) );struct BTNode *pC = ( struct BTNode * )malloc( sizeof( struct BTNode ) );struct BTNode *pD = ( struct BTNode * )malloc( sizeof( struct BTNode ) );struct BTNode *pE = ( struct BTNode * )malloc( sizeof( struct BTNode ) );pA->data = 'A';pB->data = 'B';pC->data = 'C';pD->data = 'D';pE->data = 'E';pA->pLchild = pB;pA->pRchild = pC;pB->pLchild = pB->pRchild = NULL;pC->pLchild = pD;pC->pRchild = NULL;pD->pLchild = NULL;pD->pRchild = pE;pE->pLchild = pE->pRchild = NULL;return pA;}线性结构和非线性结构逻辑结构线性数组链表栈和队列是一种特殊线性结构非线性树图物理结构快速排序图表链式二叉树二叉树表示方法后序遍历普通二叉树转化为二叉树普通二叉树转化为完全二叉树(正方形为要删除的)森林转化成二叉树先序遍历先序遍历2已知先序和中序求后序已知先序和中序求后序2已知中序和后序求先序中序遍历中序遍历2栈定义一种可以实现"先进后出"的存储结构栈类似于箱子分类静态栈动态栈算法出栈压栈应用函数调用中断表达式求值内存分配缓冲处理迷宫凡是静态分配的的都是栈里面分配(有操作系统帮你分配的)凡是动态分配的都是堆里面分配(由程序员手动分配的)//编译器编译成功,但是运行不是程序所需要的功能?# include <stdio.h># include <malloc.h># include <stdlib.h>typedef struct Node{int data;struct Node *pNext;}NODE, *PNODE;typedef struct Stack{PNODE pTop;PNODE pBottom;//pBottem是指向栈底下一个没有实际意义的元素}STACK, *PSTACK;void init( PSTACK );void push( PSTACK, int );void traverse( PSTACK );bool pop( PSTACK, int * );bool empty( PSTACK pS );int main( void ){STACK S;//STACK等价于struct Stackint val;init( &S );//目的是造出一个空栈push( &S, 1 );//压栈push( &S, 2 );push( &S, 3 );push( &S, 4 );push( &S, 5 );push( &S, 6 );push( &S, 7 );traverse( &S );//遍历输出clear( &S ); //清空数据traverse( &S );//遍历输出if( pop( &S, &val ) )printf( "出栈成功,出栈的元素是&d\n", val );}else{printf( "出栈失败" );}traverse( &S );//遍历输出return 0;}void init( PSTACK pS ){pS->pTop = ( PNODE )malloc( sizeof( NODE ) );if( NULL == pS->pTop ){printf( "动态内存分配失败!\n" );exit( -1 );}else{pS->pBottom = pS->pTop;pS->pTop = NULL;//或是pS->pBottom = NULL;}}void push( PSTACK pS, int val ){PNODE pNew = ( PNODE )malloc( sizeof( NODE ) );pNew->data = val;pNew->pNext = pS->pTop;//pS->Top不能改为pS->pBottom pS->pTop = pNew;return;}void traverse( PSTACK pS ){PNODE p = pS->pTop;while( p != pS->pBottom ){printf( "%d ", p->data );p = p->pNext;printf( "\n" );return;}bool empty( PSTACK pS ){if( pS->pTop == pS->pBottom )return true;elsereturn false;}//把pS所指向的栈出栈一次,并把出栈的元素存入pVal形参所指向的变量中,如果出栈失败,则返回false,否则truebool pop( PSTACK pS, int *pVal){if( empty( pS ) )//pS本身存放的就是S的地址{return false;}else{PNODE r = pS->pTop;*pVal = r->data;pS->pTop = r->pNext;free( r );r = NULL; //为什么要把r赋给NULL呢??return true;}}//clear清空void clear( PSTACK pS ){if( empty( pS ) ){return ;}else{PNODE p = pS->pTop;PNODE q = p->pNext;while( p != pS->pBottom ){q = p->pNext;free( p );p = q;}pS->pTop = pS->pBottom;}}。
数据结构学习笔记(郝斌老师)
(控制线用来控制 cpu 对于内存条,是只读还是只写,还是可读或可写)
两个指针变量之间只可以相减,不可以相加,相乘或相除,因为这样的运算无意义 对于单个指针可以进行加法或者减法运算(自增,自减) “指向同一块连续空间的不同存储单元”这个要求存在,是因为不同类型的指针变量,相
减无意义,例如,一个保存的是整型的地址,另一个保存的是实型的地址,相减干啥?
数据结构研究的就是个体的存储和个体与个体之间关系的存储问题,算法研究的是对数据的 操作问题,并且不同的存储结构会影响算法的使用,举个简单的例子,要想实现一个功能, 你首先需要把数据拿出来,对于数组来说用 for 循环就可以实现,但对于链表就不可以了, 所以说算法依附于存储数据的结构,结构不同算法必定会有差异
指针的变量值是人赋予的那些数据,其变化范围就是数学上所定义的那个范围。 语法程序举例 1: # include <stdio.h> int main(void) {
int * p; //p 是变量的名字, int * 表示 p 变量存放的是 int 类型变量的地址 int i = 3;
p = &i; //OK //p = i; //error,因为类型不一致,p 只能存放 int 类型变量的地址,不能存放 int 类
指针与一维数组 # include <stdio.h>
int main(void) {
int a[5]; //a 是数组名 5 是数组元素的个数 元素就是变量 a[0] // int a[3][4]; //3 行 4 列 a[0][0]是第一个元素 a[i][j]第 i+1 行 j+1 列
int b[5];
-- a[4]
//a = b;//error a 是常量
郝斌老师C大纲笔记
郝斌老师C大纲笔记C语言概述1、为什么学习C语言1)C的起源和发展第一代语言:机器语言01代码第二代语言:汇编语言就是简单的助记符ADD第三代高级语言:结构化语言(面向过程)C,Fortran用于科学计算Basic演变为VB,Pascal用于教学。
面向对象(OO)C++,java(SUN改造过),C#(微软改造的),后两种都是针对C++改造的。
因为C++比较复杂。
结构化语言有缺陷:数据和操作分离。
如果你学会C++那么剩下都不用学了。
因为它都包括了面向过程和对象2)C的特点优点:代码量小(WPS)速度快功能强大(写操作系统)缺点:危险性高:(同样的程序java中就会报错)可以随便写开发周期长:因为它是面向过程语言,10万行代码以上容易崩溃可移植性不强:因为java的可移植性太强了。
C的话两台机器跑起来可能不一样。
3)C的应用领域系统软件开发:操作系统:三大驱动程序:主板驱动、显卡驱动、摄像头驱动数据库:DB2,Oracle,Sql server应用软件:办公软件:WPS图形图像多媒体:ACDSee,PS,MediaPlayer嵌入式软件开发:智能手机,掌上电脑游戏开发:2D,3D游戏(CS整个引擎都是纯C。
魔兽不是4)C的重要性有史以来最重要的语言所有大学工科理科学生必修课程系统软件都是用它开发合格黑客必须掌握程序员必须熟练大企业、外企招聘必考为数据结构,C++,java,c#做准备2、怎样学习C语言每一讲分四次课前两节课为理论课,讲授理论知识后两节课为上机课,在机房完成当堂练习要去:当堂练习必须在两节上机课中完成机房随时有辅导老师辅导老师检查后方可离开途径:多思考,多上机目标:能看懂程序,能调试程序,自学能力要很强其实就是犯错误的过程,肯定会有错误,全都出完了,就学好了。
参考资料:谭浩强《C语言程序设计》清华绝对入门经典(就是自己能看懂)《C Primer Plus》人民邮电 60元语法《C和指针》人民邮电 65元在想变成高手看:《C专家编程》绝版《C陷阱与缺陷》人民邮电 30元3、学习的目标了解程序语言及发展历史熟练掌握C语言的语法规则掌握简单的算法理解面向过程的思想,这非常有助于将来对面向对象思想的学习能看懂程序会调试程序掌握将大问题转化为一系列小问题来求解的思想为将来学习C++,数据结构,C#,java打下良好的基础4、常见问题答疑1、学习java为什么建议先学C语言a)学习C就是学java,因为C语言至少80%的语法知识都被java继承过来了。
郝斌数据结构学习笔记1
郝斌c语言学习笔记这篇文本我写过后做很多次修改,虽然感觉还是无法做到最合理的解释,但也希望能对想真正理解c语言的人有所帮助,这里我只写了一部分,往后我会定时上传。
正在看郝斌的数据结构,看到了指针,觉得讲的很不错的,int *p;定义一个整形的指针变量int i=10;定义一个整形变量i=10;p=&i;将i取地址给p(也叫做p指向i)我们叫做p指向i,p中装载的是i的地址,而*p与i是属于一体的,也就是说此时无论i变为何值*p也就是为何值。
指针与一维数组列如:int a[5]={1,2,3,4,5};我们可以写成a[3]=*(a+3);那么为什么a[3]这个元素可以等价于*(a+3)呢?答案:因为a所指向的是这个数组的第一个地址,这个是需要记住的,也就是说内部库这么定义的,*a是一个指针变量,而指针a中也就是第一个元素的地址,那么(a+3)就说明了一维数组的第一个元素的地址向后推移了3位,也就是数组的第四位a[3]的地址,此时a[3]的地址也就是指针,所以*(a+3)对应的是a[3]的数值4,当然也可以有另一种写法*a+3,*a代表的是第一个元素的数值也就是a[0]=1;1+3=4;所以也可以代表a[3]的值。
以上是看了郝斌数据结构指针与一维数组的理解。
指针与内存以及指向对象的类型关系?答案:一般指针占用四个字节,那么指针与数组类型的关系?列如:double arry[3]={1.1,2.2,3.3}这是一个double类型的数组每个元素占有8个字节,我们在定义两个指针:Int *p; int *q;p=arry[0];q=arry[1];我们把数组的第一个与低二个元素给指针pq那么p,q内部装载的是什么,可知p,q为指针所以存储应该是元素的地址,因为double类型的数组是八个字节,但是指针只存储这个元素的第一个字节,因为一个字节也就是一个地址,而指针只存储一个元素的首地址所以只存储一个字节。
郝斌老师数据结构大纲word版
一、连续存储[数组]
1.什么叫做数组
元素类型相同,大小相等
2.数组的优缺点(相对于链表)
优点:存取速度快
缺点:实现必须知道数组的长度
需要大块连续的内存块
插入和删除元素很慢
空间通常是有限制的
二、离散存储[链表]
1.定义
N 个结点离散分配
彼此通过指针相连
每个结点只有一个前驱结点,每个结点只有一个后续结点
front 代表的是队列的第一个元素 rear 代表的是队列的最后一个有效元素的下一个元素 ③队列空
front 和 rear 的值相等,但不一定是零 ④循环队列入队伪算法讲解(在尾部入队)
第一步:将值存入 rear 所指向的位置 第二步:rear = (rear + 1)%数组的长度 ⑤循环队列出队伪算法讲解(在头部出队)
首结点没有前驱结点,尾结点没有后续结点
专业术语:
首结点:第一个存放有效数据的结点
尾结点:最有一个存放有效数据的结点
头结点:头结点的数据类型和首结点的类型是一样的
首结点之前的结点
头结点并不存放有效数据
-4-
数据结构资料
加头结点的目的是为了方便对链表的操作 头指针:指向头结点的指针变量 尾指针:指向尾结点的指针变量 确定一个链表需要几个参数: (如果希望通过一个函数来对链表进行处理,我们至少需要接受链表的那些参 数) 一个参数,即头指针,因为我们通过头指针可以推算出链表的其它所有的信息 2.分类 单链表 双链表:每一个结点有两个指针域
return 0; }
scanf ("%d",&val); printf("%d 的阶乘是%ld", val, mult(val));
我写的郝斌 C语言笔记
变量按存储方式分:静态变量、自动变量、寄存器(cpu内存数据的硬件设备)变量
# include <stdio.h>
3)函数返回值的类型也称为函数的类型,如果与return 表达式;的类型发生冲突,以 函数返回值的类型为准。
例如: int f()
{
return 10.5;//因为函数的返回值类型是int,所以最终f函数返回的是10,而不是10.5。
}
109. return和break的区别
{
printf("%-5d",a[i][j]);//-表示左对齐,5表示每个元素占5个光标
}
printf("\n");
}
对二维数组排序
求每一行的最大值
判断矩阵是否对称
矩阵的相乘
103.是否存在多维数组
不存在,因为内存是线性一维的,n维数组可以当做 每个元素是n-1维数组的 一维数组。
函数是一个工具,它是为了解决大量类似问题而设计的,函数可以当做一个黑匣子。
#include <stdio.h>
int f(void) // 括号里的void表示该函数不能接受数据,int表示函数返回值是int类型的数据
{
return 10; // 向被调函数返回10
}
void g(void)
for(i=0;i<5;+.二维数组的使用
[郝斌]数据 结构c语言-前导知识
[郝斌]数据结构c语言-前导知识
数据结构是计算机科学中非常重要的一个概念。
它是指将数据组织成特定的形式,以方便访问和处理。
数据结构可以分成两类:线性结构和非线性结构。
线性结构包括数组、链表、栈、队列等,而非线性结构包括树、图等。
在学习数据结构前,我们需要掌握一些前导知识,主要包括以下几个方面:
1. C语言基础:C语言是数据结构的基础语言,我们需要熟悉C 语言的基本语法、运算符、流程控制语句、函数等知识点。
同时,我们还需要学会使用C语言编写基本的数据结构算法。
2. 算法基础:数据结构和算法是密不可分的,我们需要掌握一些基本的算法,如排序算法、查找算法等。
同时,我们还需要学会分析算法的时间复杂度和空间复杂度。
3. 数学基础:数据结构涉及到一些数学知识,如概率论、离散数学等。
这些知识可以帮助我们更好地理解数据结构的原理和应用。
4. 计算机组成原理:学习数据结构还需要了解计算机的基本组成原理,如内存、CPU等。
这可以帮助我们更好地理解数据结构的存储方式和访问方式。
5. 数据库基础:数据结构是数据库系统的基础,了解数据库的基本知识,如关系型数据库、非关系型数据库等,可以帮助我们更好地应用数据结构。
总之,掌握好数据结构需要系统学习和不断实践,只有在不断的编写和优化程序中,我们才能更好地掌握数据结构的运用。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
郝斌数据结构自学笔记--知识点+程序源代码By-HZM1_什么叫做数据结构数据结构概述定义我们如何把现实中大量而复杂的问题以特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上为实现某个功能(比如查找某个元素,删除某个元素,对所有元素进行排序)而执行的相应操作,这个相应的操作也叫算法。
~数据结构=个体的存储+个体的关系存储算法=对存储数据的操作2_衡量算法的标准算法解题的方法和步骤~衡量算法的标准1)时间复杂度:大概程序执行的次数,而非执行的时间2)空间复杂度:算法执行过程中大概所占用的最大内存3)难易程度4)健壮性3_数据结构的特点【数据结构的地位数据结构是软件中最核心的课程程序=数据的存储+数据的操作+可以被计算机执行的语言4_预备知识_指针_15_预备知识_指针_2*指针的重要性:指针是C语言的灵魂定义:地址:地址是内存单元的编号,从0开始的非负整数,范围:0-FFFFFFFF【0-4G-1】CPU=====地址线,控制线,数据线=====内存指针:…指针就是地址,地址就是指针。
指针变量是存放内存单元地址的变量。
指针的本质是一个操作受限的非负整数。
分类:1.基本类型的指针2.指针和数组的关系?变量并不一定连续分配,随机分配内存。
内存:内存是多字节组成的线性一维存储空间。
内存的基本划分单位是字节。
每个字节含有8位,每一位存放1个0或1个1.内存和编号是一一对应的。
(软件在运行前需要向操作系统申请存储空间。
在软件运行期间,该软件所占空间不再分配给其他软件。
当软件运行完毕后,操作系统将回收该内存空间(操作系统并不清空该内存空间中遗留下来的数据)。
NOTE:1)指针变量也是变量,普通变量前不能加*,常亮和表达式前不能加&。
2)局部变量只在本函数内部使用。
如何通过被调函数修改主调函数中普通变量的值。
1)实参为相关变量的地址;<2)形参为以该变量的类型为类型的指针变量;3)在被调函数中通过 *形参变量名的形式的形式就可以修改主函数。
CASE 1#include<>int main(void){|int *p; id,而(*pst).sid等价于,所以pst->sid等价于Return 0;}注意事项:结构体变量不能加减乘除,但可以相互赋值普通结构体变量和结构体指针变量作为函数传参的问题CASE 2,#include<>struct Student{int sid;char name[200];int age;};{void f(struct Student *pst);void g(struct Student st);void g2(struct Student *pst);int main (void){struct Student st; id=99;strcpy(pst->name,”zhagnsan”);-pst->age=22;}9_malloc()动态分配内存概述动态内存的分配和释放CASE 1#icclude<>,#include<>int main(void){int a[5]={1,2,3,4,5}; .}int fun (int **q){】int s; .}int fun(int **q){*q=(int *)malloc(4); 1=2+3+4+...100的和2. 求阶乘3. 汉诺塔^4. 走迷宫模块二:非线性结构树图连续存储[数组].1. 什么叫数组元素类型相同,大小相同2. 数组的优缺点:CASE 1#include<>#include<> en=99;pArr->pBase = (int*)malloc(sizeof(int)*length); %if(NULL==pArr->pBase){printf("动态内存分配失败!\n");exit(-1);值存入r所代表的位置2.错误的写法:r=r+1;正确写法是:r=(r+1)%数组的长度"42 _ 队列8 _ 循环队列出队伪算法讲解f=(f+1)%数组的长度43 _ 队列9 _ 如何判断循环队列是否为空如果front于rear的值相等,则该队列就一定为空。
44 _ 队列10 _ 如何判断循环队列是否已满<若f、r相等,不知道队列到底是空还是满。
预备知识:front的值可能比rear大,也可能比rear小,也可能两者相等。
如何判断循环队列是否已满两种方式:1.多增加一个标志参数2.少用一个元素【通常使用第二种方式】\如何判断队列已满:如果f和r的值紧挨着,则队列已满用C语言伪算法表示就是:if((r+1)%数组长度==f)已满else不满。
45 _ 复习 _ 求链表的长度46 _ 复习上节课队列知识队列定义:一种可以实现先进先出的存储结构分类:静态队列链式队列…47 _ 循环队列程序演示队列算法:入队出队#include<>#include<>`typedef struct Queue{int *pBase;int front;int rear;}QUEUE;》void init(QUEUE *);bool en_queue(QUEUE *,int);+100的和2,求阶乘3,汉诺塔4,走迷宫#include<>@void f();void g();void k();int main(void){f();}return 0;}void f(){printf("FFFF\n");g();<printf("1111\n");}void g(){printf("GGGG\n");k();printf("2222\n");};void k(){printf("KKKK\n");printf("3333\n");}!51 _ 递归2 _ 一个函数自己调自己程序举例#include<>void f(int n){if(n==1)printf("自己调自己\n");else—f(n-1);}int main(void){f(7);return 0;}:52 _ 递归3 _ 1+2+3+....+100之和用递归来实现CASE 1#include<>int main(void){~int val;int i,mult=1,s;printf("请输入一个数字:");printf("val=");scanf("%d",&val);}for(i=1;i<=val;++i)mult=mult*i;printf("%d的阶乘是:%d\n",val,mult);return 0;!}CASE 2#include<>.+100的和是:\n%d\n",sum(100));return 0;},53 _ 递归4 _ 布置作业_汉诺塔54 _ 递归5 _ 一个函数为什么可以自己调用自己CASE 1#include<>归必须得有一个明确的终止条件-2.该函数所处理的数据规模必须在递减3.这个转化必须是可解的CASE 1#include<>历:先序遍历,中序遍历,后序遍历2.已知两种遍历序列求原始二叉树先序遍历:【先访问根节点】先访问根节点,再先序访问左子树,再先序访问右子树。
:68_树9_二叉树的中序遍历【中间访问根节点】中序遍历左子树,再访问根节点,再中序遍历右子树69_树10_二叉树的后序遍历【最后访问根节点】序遍历左子树,后序遍历右子树后序遍历根节点)70_树11_已知两种遍历序列求原始二叉树概述通过先序和中序或者中序和后序我们可以还原出原始的二叉树,但是通过先序和后序是无法还原出原始的二叉树的。
换种说法,只有通过先序和中序,或通过中序和后序,我们才能唯一的确定一个二叉树。
71_树12_已知先序和中序求后序-72_树13_已知中序和后序求先序73_树14_树的应用简单介绍树是数据库数据组织的一种重要形式。
操作系统子父进程的关系本身就是一棵树。
面向对象语言中类的继承关系本身就是一棵树。
赫夫曼树【74_树15_复习上节课知识75_树16_链式二叉树遍历具体程序演示//程序执行有问题。
#include<>#include<>struct BTNode{int data;struct BTNode *pLchhid;//p是指针,L是左,child是孩子…struct BTNode *pRchhid;};void PreTraverseBTree( struct BTNode * pT);void InTraverseBTree( struct BTNode * pT);void PostTraverseBTree( struct BTNode * pT);struct BTNode * CreateBTree(void);"int main(void){struct BTNode * pT=CreateBTree();printf("前序遍历:\n");`PreTraverseBTree(pT);printf("中序遍历:\n");InTraverseBTree(pT);printf("后序遍历:\n");PostTraverseBTree(pT);return 0;]}struct BTNode * CreateBTree(void){struct BTNode * pA=(struct BTNode *)malloc(sizeof(struct BTNode ));struct BTNode * pB=(struct BTNode *)malloc(sizeof(struct BTNode ));struct BTNode * pC=(struct BTNode *)malloc(sizeof(struct BTNode ));struct BTNode * pD=(struct BTNode *)malloc(sizeof(struct BTNode )); {struct BTNode * pE=(struct BTNode *)malloc(sizeof(struct BTNode ));pA->data='A';pB->data='B';pC->data='C';pD->data='D';pE->data='E';?pA->pLchhid=pB;pA->pRchhid=pC;pB->pLchhid=pB->pRchhid=NULL;pC->pLchhid=pD;pC->pRchhid=NULL;pD->pLchhid=NULL;&pD->pRchhid=pE;pE->pLchhid=pE->pRchhid=NULL;return pA;}void PreTraverseBTree( struct BTNode * pT);{if(pT!=NULL){printf("%c\n",pT->data);if(NULL!=pT->pLchhid){PreTraverseBTree(pT->pLchhid); &}if(NULL!=pT->pLchhid){PreTraverseBTree(pT->pRchhid);}//pT->pLchhid可以代表整个左子树}>}void InTraverseBTree( struct BTNode * pT){if(pT!=NULL){if(NULL!=pT->pLchhid){InTraverseBTree(pT->pLchhid);}printf("%c\n",pT->data);if(NULL!=pT->pLchhid){InTraverseBTree(pT->pRchhid);}//pT->pLchhid可以代表整个左子树}}void PostTraverseBTree( struct BTNode * pT) {if(pT!=NULL){if(NULL!=pT->pLchhid){PostTraverseBTree(pT->pLchhid);}if(NULL!=pT->pLchhid){PostTraverseBTree(pT->pRchhid);}printf("%c\n",pT->data);//pT->pLchhid可以代表整个左子树}}76_树17_5种常用排序概述和快速排序详细讲解排序:冒泡插入选择快速排序归并排序排序和查找的关系:排序是查找的前提,排序是重点77_树18_再次讨论什么是数据结构研究的是数据的存储和数据的操作的一门学问。