自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(49)
  • 收藏
  • 关注

原创 C++数据结构重要知识点(3)(红黑树及其插入操作)

单旋的实现和AVL树的一样,虽然模型不一样,AVL树的旋转模型对子树的高度有讲究,红黑树没有,但它们本质上要处理的结点一样,要注意的nullptr也一样。,如果这时还有nodeU且为红,就一组一组向上更新,只要nodeP、nodeG为空,就会跳出循环,不用担心越界问题。根据上面插入节点的代码可知,每次插入后nodeC都指向新插入的结点,nodeP是它的父节点,我们可以从一个节点开始,慢慢地加节点,思考可能出现的情况,这是解决复杂难题的一个方式。其中,AVL树的左右子树的高度差不超过1,而。

2024-07-26 17:59:44 55

原创 C++数据结构重要知识点(2)(AVL树及其插入操作)

我们知道,插入只会使得平衡因子+1或-1,说明插入前只能是-1或1,意味着直接父结点的左边或右边已经有了一个节点了,新增的这个结点只是让它变平衡。这种情况下,在祖父看来,它的子树。其中,平衡因子用_bf来标识,在实现中,平衡因子的计算可以左树高度减右树高度,也可以右树减左树,随便选择,因为判断要不要旋转取决于平衡因子的绝对值,2和-2本质上没区别,如果上面的都理解了,我们自然也能理解每插入一个新的结点,对应父辈平衡因子的更新应当是从下往上走的,有的情况父辈会受影响,有的就不会,我们从直接父节点开始讨论。

2024-07-24 11:03:23 850

原创 C++相关概念和易错语法(24)(map、迭代器分类)

逻辑上也是必须的,因为map底层的平衡树就是依靠key的大小来建立的,改了key之后这个结点的位置就不对了,整棵树都被毁了。我们已经接触过了string、vector、list、deque、stack、queue、priority_queue、map、set、multiset、multimap这些基本容器,出现这样的原因是迭代器也有它的分类,不同的迭代器有不同的功能,有的算法库的函数只能用特定迭代器才能使用。multimap和map的区别类似于multiset和set的区别,都是支持多个key的存储,

2024-07-22 15:52:08 554

原创 C++相关概念和易错语法(23)(set、仿函数的应用、pair、multiset)

值得注意的是,multiset的大部分接口和set没什么两样,但是在set中有的接口设计会考虑去重,比如insert的返回值,而在multiset中这就没有必要了,所以存在一些不同之处。set的底层引入了红黑树,大致和key模型的二叉搜索树一样,是借助二叉树的特性来存放数据,达到排序和搜索的功能的。常用的是第二种,直接删除某个值,返回值是删除的值的个数。,在上面的代码中4虽然存在,但它会找比4大的值,返回的是5的迭代器,因此erase按左闭右开的规则会删掉4。前面的find是set容器里自带的,

2024-07-21 16:33:09 891

原创 C++数据结构重要知识点(1)(二叉搜索树、key和key-value模型)

首先我们要找到该插入的位置的父节点,用一个指针太麻烦了,我们需要一个指针在前面探路,用find类似的代码去找这个结点,另一个结点就是这个探路指针对应的父节点,当探路的走到空之后,另一个就指向了正确的父节点。,如1,2,3,4,5,6,7,8,9这几个数字,如果先插入1,那么根的左边就是空的,数据全部存到右子树了。搜索树中搜索是很重要的功能,根据左小右大的原则,我们可以很快写出相关代码,注意考虑空树,如果逻辑不完善,要补上。当根的左右都有结点时,逻辑是严密的,但如果根的左边或右边没有结点了,怎么办?

2024-07-18 16:30:37 612

原创 C++相关概念和易错语法(22)(final、纯虚函数、继承多态难点)

我们要理解访问限定符限制的是什么,是防止其它类调用private的函数,这里p是一个指针,本身就指向B对象的空间,只不过访问方式按A进行。如植物是一种抽象的类,而像苹果、香蕉就是具象的,单独讨论植物太过庞大,没有太大意义,因此我们的重心放在由植物具象出来的苹果,我们可以具体讨论它的成分、营养价值等。要理解这里,我们假设这个指针的类型是子类的,那如果子类又写了一个一模一样的函数构成隐藏,那么就会因为参数和假设的函数完全相同而报错,所以是行不通的。:多态调用函数的核心时动态绑定,也叫运行时绑定。

2024-07-15 18:09:49 848

原创 C++相关概念和易错语法(21)(虚函数、协变、析构函数的重写)

重写的意义在于子类也有一个新的虚函数表,虽然函数前没有加声明virtual(父类前必须加),当子类显式写了这个函数,就会存到常量区,虚函数表存函数的地址(第一句指令的地址)。至此,我们应该能够理解前面所说虚函数、虚函数表、重写存在的意义了,它们的出现都最终服务于实现一件事——多态,即根据不同类,在调用同一函数时体现出不同状态。也就是说,r无论接收的是A还是B还是C,最终都会被切割成A的模样(A中也有虚函数表),但是内容是不是都一样呢?联系到上面的重写,很快我们就会想到使用virtual修饰父类的析构函数,

2024-07-15 15:12:44 615

原创 C++相关概念和易错语法(20)(赋值兼容转换、多继承、继承与组合)

而一般来讲,protected成员更倾向于类功能的底层,函数更多,父类的书写者不可能去考虑子类调用的情况来适配,这对于书写子类功能的人来说无疑是一场灾难。,我们只能调用该类向外展示的函数接口,其余细节完全不知道,因此如果这个类出现了毛病,有人去维护,它们只需要修bug就行了,只需要保证对外提供的接口是安全的,功能是正常的就可以了。我们会发现,BCD都没有问题,但E就有问题了,E通过两条继承关系链继承了两次A,意味着E里面有两份A的成员变量,这是单继承永远碰不到的情况,这叫。这是子类给父类赋值的一种操作。

2024-07-14 00:34:57 1330

原创 C++相关概念和易错语法(19)(继承规则、继承下的构造和析构、函数隐藏)

很多人会以为能像函数重载的调用那样根据参数匹配程度来调用,但这个逻辑在继承里走不通,万一我就想利用隐式类型转换调用子的成员函数,但是参数却匹配了父的成员函数呢?父的成员是protected意味着这些成员对外是个秘密,但在自己家庭中不算个秘密,但家庭中的每个人都有义务对外保守这个秘密,即protected无论以何种方式继承对外都不可见。继承的本质是复用,是结构上的继承而不是内容上的继承,近似于在子类中声明了父类的成员变量。由于在父类的析构函数调用后间接使用了父类的成员,所以出现越界访问的情况。

2024-07-12 22:01:31 795 1

原创 C++相关概念和易错语法(18)(array、模板)

对于普通函数,就算我们不去调用它,编译器在编译阶段是会比较深入的去检查的,这里由于"a"是常量字符串,不能修改,所以交给arr的指针不能*arr,因此要用const char*,所以报错了。函数模板的特化和类模板的特化用法上都很好理解,实际就是针对一些很特殊的类型做特殊的处理,注意要写template<>,这其实是声明这是个模板,没有模板参数就不写,在函数名或类名后要写实例化的类型。在优先级上,如果已经定义了普通函数,就会最优先调用普通函数,其次找特化,如果实在没有,就会去实例化模板函数。

2024-07-11 18:07:37 1051

原创 C++相关概念和易错语法(17)(适配器模式、仿函数)

在queue中pop使用了pop.front(),在vector里没有这个接口,所以不能使用vector实现queue,但是我们如果用erase来实现pop也可以,这样就可以用vector实现queue了,但并不建议这么做,因为vector实现queue本就是效率极低的做法。构造时我们可能空构造,需要缺省值,也有可能带参构造,带参构造需要我们形参接收,这里展示的是拷贝构造的情况,析构的时候成员_con作为自定义类型会去调用自己的析构函数,不会存在内存泄露的情况,所以不需要我们显式的去写析构。

2024-07-09 20:52:25 1191

原创 C++相关概念和易错语法(16)(list)

_data是结构体类型,我们直接先指向这个结构体内容本身,即_curnode->_data,这个表达式的返回值是一个结构体,也就是我们想要访问的结构体,但是我们是要模拟指针的操作,要使用->而不是.,所以我们要再对它取地址,即&(_curnode->_data),这样返回的就是一个指向_data的指针了,当我们。当我们调用insert(lt.begin(), 1, 3)时,是想在首位置插入1个3,但是编译器会将1,3识别成迭代器(注意看我们之前已经实现了模板函数,1和3同类型是会匹配的),

2024-07-08 11:17:12 975

原创 C++相关概念和易错语法(15)(sort、vector模拟实现)

因此它的本质是vector支持一种构造,auto il = {1,2,3,4,5}将任意个数的数据(常量数组)给initializer_list,这个对象里有两个指针,分别指向开始和结束的下一个位置,它也支持迭代器,范围for。当开辟空间后,_start首位置,_finish存储位置的下一个位置,_end_of_storage都更新了,pos迭代器也要去更新,_start首位置,_finish存储位置的下一个位置,_end_of_storage开辟空间的最后一个下标下一个。其余接口都算简单,就不再介绍了。

2024-06-03 19:11:15 921

原创 C++相关概念和易错语法(14)(初始化注意事项、vector、编译器向上查找规则)

string可以一次性加入一个串,而vector只能单独加字符,string不管怎么操作,数据最后一定有个\0,而vector尾插不会有这个功能,需要自己去处理\0的情况,很不方便。图1展开命名空间的语句在展开头文件的下面,因此在向上查找的情况下,并不会读取using namespace std,也就不会在std命名空间里找,所以找不到。因此我们可知,string是专门针对字符数组的需求设计的,而vector是广泛适应的,vector不能替代string,需要根据不同的场景有不同的选择。

2024-05-24 08:58:30 953

原创 C++相关概念和易错语法(13)(string的模拟实现)

借助复用我们可以进一步实现erase,当从pos开始全部删除时用swap,其余情况分成两段insert,最后加起来,这里我提前用了operator+,operator+很好实现,只是我这里讲解的顺序不一样。当存储字符少于15个的时候(实际开了16个字节,预留一个给\0),就存到_buff里,多了就全部移到_str中。比较运算符重载我们其实只需要实现其中的一两个,其它全部用上层逻辑联系起来,可以很快实现。利用复用,我们的代码可以非常简约,但是实际上执行的复杂度是没有改变的,大部分的代码是很简单的,

2024-05-20 18:06:45 494 2

原创 C++相关概念和易错语法(12)(迭代器、string容量调整)

这个区别和指针的const规则类似,只不过指针是根据const和*的相对位置来区分的,迭代器iterator就一个单词,不存在相对位置的概念,所以使用const_放在iterator前面表示区分。,虽然我们知道\0也是字符串的一部分,本质上说也不算越界,但是考虑到实际使用没正常人会去对这个\0动手脚(如果单独改了这个\0,就会导致字符串没有\0,会引发一系列隐患),我们发现扩容后,size直接跳到100,意味着0~99的数据都能被正常访问,在默认情况下,扩容后的空位补\0,你也可以指定字符。

2024-05-07 11:42:42 741 1

原创 C++相关概念和易错语法(11)(npos、string的基本使用)

但由于string的设计相对来说很复杂(string设计在STL之前,时间太早不太成熟,设计出现了很多冗余的接口),平时使用的时候就主要使用关键的几个,保证功能的实现即可,所以这篇文章会分享一些基础的有用的接口。用来查询字符串允许的最大长度,几乎没什么用,因为一般情况不会触及到这个最大值,下面是在x64下允许存储的最大长度,相当于有符号long int能存的最大值,需要8589934592G的空间,这是不可能达到的。但是我们要注意的是这里面有很多的构造函数,在使用的时候是去找最匹配的。

2024-05-05 08:51:19 902 3

原创 C++相关概念和易错语法(10)(定位new、模板)

当我们向内存池申请空间,使用malloc时无法直接调用构造函数,我们需要主动去调用构造函数,那应该怎么办呢?定位new的使用场景很少,如果我们想将一个已使用对象初始化,我们就可以使用这种办法,同时,它在内存池(池化技术)中使用比较多,,我们只有多依靠复制粘贴实现多个极为相似的函数,这样会使代码变得冗长,而且使得效率低下,因此C++中引入了模板的概念,注意格式中new后面的括号内的是指针,之后跟初始化信息,单参数用小括号,多参数要用花括号。如果普通函数的参数不能匹配,就会去匹配更符合的函数模板,

2024-05-01 11:51:03 1034 1

原创 C++相关概念和易错语法(9)(变量的存储、new和delete混用分析)

我们发现如果这个时候直接去调用operator delete[]、operator delete、delete、free就会导致释放的内存起始位置发生了位移,这就会导致报错,而delete[]就会先从前4个字节开始,先读取个数,然后。注意数组是开辟了空间的,会发生复制操作,就算是常量字符串储存在代码段,也要拷贝过来。如果类没有显式实现析构函数,那么就意味着不会多开辟那4个字节,也就不会报错,这个时候混用不会导致程序崩溃。当我们创建类的数组时,使用new[],因为使用它可以在开辟空间的时候。

2024-04-28 21:34:52 852 2

原创 C++相关概念和易错语法(8)(匿名对象、构造+拷贝构造优化、构造析构顺序)

当我们实例化对象后,有的对象可能只使用一次,之后就没用了。我们可以发现,匿名对象的生命周期就在那一行,在调用之后就会立马销毁。(4)除了static修饰的局部对象以外,所有对象(局部、全局)先构造的后析构。对于优化问题,我们常常讨论的是构造次数,因为析构和构造成对出现。(2)局部static对象在第一次调用才构造,第二次就不构造了。一般来说采用后者的写法,毕竟要写的代码量更小,而且提高可读性。(1)全局对象最先构造,在程序开始时就按顺序构造。,完成匿名对象的初始化;但是,有的情况并不会优化,主要是看。

2024-04-21 17:37:09 1015 1

原创 C++相关概念和易错语法(7)(初始化列表、隐式类型转换、友元)

假设我们在成员变量声明处写了int _a = 1,如果我们没有自己写初始化列表,而是在函数体内写了_a = 2,那么当_a创建时会自动创建一个初始化列表,其中_a初始化时在初始化列表中赋的值就是缺省值,也就是_a(1),后续再进入函数体,将_a赋值为2。如果我们显式实现了初始化列表,如在初始化列表中写了_a(1),在成员变量声明处写了缺省值int _a = 2,这个时候在编译器创建变量并初始化时就会。就在上面的那段代码,我们会注意到A的_a和_b是共有的,如果是私有的,那么如何处理呢?

2024-04-21 00:03:52 864

原创 C++相关概念和易错语法(6)(运算符重载)

由上面我们就可以知道为什么C++相比较C要多设计cin和cout了,其主要目的是为了适配自定义类型的输入输出,这在C语言中的printf和scanf实现起来非常困难,需要借助函数来实现。因此,在学习C++的过程中,我们要仔细思考为什么C++要设计一个类似的语法,C语言一定存在相对应的局限性。69.默认成员函数:取地址的运算符重载,这个函数也可以用const修饰,我们不写也可以,一般而言不自己写。如果所有的函数都在.h定义,有两个或以上源文件包含这个头文件的时候,这份定义会分别出现在两个源文件里,

2024-04-20 15:17:56 290 1

原创 C/C++易错知识点(4):static修饰变量和函数

在.h声明Fun()函数的地方使用static,如果有n个.c都包含了这个.h,那就告诉我们有n个完全独立的Fun()存在。在类中定义的static函数和static变量类似,它相当于类的公共区域,这个函数的特殊之处在于它的第一个参数没有this指针,这也就意味着。注意区分“包含它的文件”和“它包含的文件”,上面我举例的.h中无法调用static函数就是“它包含的文件”这种情况。我们可以在一个.c定义函数,然后在.h中声明这个函数,如果有很多.c都包含了这个.h,那就相当于告诉它们在。

2024-04-20 12:18:38 1938 2

原创 C++相关概念和易错语法(5)(析构函数、拷贝构造、运算符重载、赋值重载)

内置类型的变量是自动变量,是编译器自动开辟的,不需要人为销毁,因此也不需要写析构函数。没有资源管理(堆空间开辟)的情况可以不写拷贝构造,内部有指针或有一些值指向堆,需要显式写析构函数,也要写拷贝构造,如栈、队列、二叉树等数据结构。在这里可以看出,在C这个类中的函数可以访问调用该函数的对象的私有成员,也可访问同类型的参数对应的私有成员。要解决这个无穷递归的情况,可以选择传址或传引用,因为这两者本质相同,而传引用不用显式地写&,从而实现C c2 = c1这样方便的写法,所以规定拷贝构造都是传引用。

2024-04-18 18:40:14 694

原创 C/C++易错知识点(3):字符数组的修改、sscanf、sprintf

对于这个变量有一个特殊操作就是&arr,这个操作是取出整个数组的地址,整个数组的地址是首元素的地址,所以&arr和arr得到的值是相同的。arr这个指针还有个常属性,即arr存储的值不能被修改,类似于const int* p,这就导致arr的指向的空间区域在一开始就确定了,不能被修改了。在上面这张图中,我们可以看到如果我们想要将"Hello"存到数组,直接赋值操作是不行的,因为就像上面所说的,这个临时变量同样具有常属性,这个临时变量我们是看不到的,如果有变量接收就把这个临时变量的值赋给这个变量。

2024-04-08 21:32:23 2047 1

原创 C++相关概念和易错语法(4)(构造函数、析构函数)

解释:c3没有自定义构造函数,所以自动生成构造函数。_p和_q都是内置类型所以不会初始化,_r是自定义类型,所以调用_r的自定义构造函数。_r有自定义构造函数,将_x和_y都初始化为2,_z是自定义类型,所以调用_z的自定义构造函数。需要注意的是,析构函数不能带有参数,包括全缺省,所以也不需要考虑传参的各种情况。我们发现,_x和_y并没有初始化,而_a和_b初始化了,如何解释?_z有自定义构造函数,将_a和_b都初始化为2。因此,在我们平时自定义构造函数的时候,最好使用。

2024-04-05 13:03:49 994 1

原创 C++相关概念和易错语法(3)(类的声明和定义、空指针分析、this指针)

但是,在成员函数内部,可以显式写出this指针,因为this指针其实是类的指针,而类又和struct同源,所以用的是this->形式。this指针可能存在栈中,也可能存在寄存器中,不同编译器有不同的做法。它是隐含在类中的一种指针,在对该类实例化出多个对象时,this指针就用来给每个对象贴上标签。这些成员变量、函数的作用于这个类域,将功能集成在一起,这体现出封装的思想。为形象理解,可以将类的声明视为图纸,这个图纸可以实例出多个对象。预处理是将所有的宏和头文件展开,生成的文件我们仍然能读懂。

2024-04-05 13:02:47 686 1

原创 C++相关概念和易错语法(2)(引用、内联函数、auto类型)

因为如果一个函数有成百上千代码,而这个函数被数百次调用,那么在预处理阶段被展开的代码量是极为恐怖的,所以为了防止这种事情发生,引用作为一种对变量取别名的用法,对别名和本体的访问权限必须一致,有的情况下比较容易出错。但引用的安全并不是绝对的,如果引用的指针存在越界的情况,语法层面也无法检测出来。这相当于对数组里面的内容取别名,再在后面的代码中对x操作就可以影响数组的值。注意甄别权限的放大,有的情况下只是赋值操作,不存在放大的情况。,就当成正常函数使用,这个时候的开支也一定是最合理的。

2024-04-02 23:48:41 329 5

原创 C++相关概念和易错语法(1)(命名空间域、缺省参数、函数重载)

但是在大型的项目中一般用局部展开,因为如果当同时展开多个命名空间时,根据访问规则,如果展开的这些命名空间有重名的情况,就会报错。调用函数时,函数地址是执行第一句汇编指令的地址,要有定义才有这个地址。但是区别在于函数里的变量只有在进入函数后在函数里面访问,而namespace定义的变量可以在任何地方调用(生命周期所致)。一般情况下,命名空间域不会被访问,在使用using被展开后会在先局部再全局访问后,访问这个命名空间。时就会先访问局部域,在任何函数里面定义的变量,你在函数外面都访问不了,因为。

2024-03-30 17:47:19 754 1

原创 C语言数据结构易错知识点(6)(快速排序、归并排序、计数排序)

至于需要注意的点,就是当key在左侧时,一定要右侧先动,左侧再动,这样才能保证相遇点的值小于等于arr[key](这个结论可以画图证明,这里就不展开了),当然,逆序同理。最后交换arr[key]和arr[prev]达到一样的效果,使右侧大于arr[key],左侧小于等于arr[key]。需要注意入栈顺序是从右向左,右下标先入,左下标后入,右递归先入,左递归后入。快速排序属于交换排序,交换排序还有冒泡排序,这个太简单了,这里就不再讲解。计数排序属于非比较排序,在数据集中的情况下可以考虑使用。

2024-03-29 09:57:00 753 2

原创 C语言数据结构易错知识点(5)(插入排序、选择排序)

上述排序都是需要掌握的,但原理不会讲解,网上有很多详尽地解释,本文章主要分享一下代码实现上应当注意的事项,我写代码时易错的细节。希尔排序其实是直接插入排序的一种变形。引入gap保证数组更快地变得有序。

2024-03-25 08:33:13 280 2

原创 C语言数据结构易错知识点(4)(二叉树、分治思想)

我们刚刚的分析是以根为起点来进行分析的,根的左子树和根的右子树的高度最大值+根所占的1个高度 == 树的高度。我们发现,当k == 1时比较特殊,如果在k == 1时再向下递归似乎就无意义了,而此时访问到的结点都是我们想要统计的结点,如果访问到了就返回1给上一层函数。二叉树的各种功能实现基本上都绕不开递归,解决这些问题需要用到递归,但递归的抽象程度很容易让人被绕进去,所以我们可以通过最小子问题和递归条件来理解、写代码。前序遍历可以被拆分为:当前树的根的值打印+左子树的根的值打印+右子树的根的值打印。

2024-03-23 14:50:22 509 3

原创 C/C++易错知识点(2):二级指针、数组指针、函数指针

我们知道,数组指针是对整个数组取地址,即&arr,假设这个指针表示为int (*parr) [10] = &arr,那么*parr得到的就是*(&arr)即arr,相当于首元素地址,也就是int*,所以首元素的地址也可表示为int* p = *parr。注意数组指针的本质是指针,它存储的值是数组的首元素地址,象征着它指向的对象是一个数组。&arr是对整个arr取地址,是二维数组的指针,第一次解引用得到arr,首元素(数组)的地址,即一维数组指针,第二次解引用是对元素数组解引用,得到首元素(整型)的地址。

2024-03-21 22:38:11 1036 1

原创 C语言数据结构易错知识点(3)(堆、堆排序)

当我们通过大堆找到最大值后,将其与尾元素交换,然后size--达到伪删除的目的(顺序表的删除也可视为一种伪删除,即数据没有被销毁,只是访问不到),重复建堆并交换,次大的数据在最大的数据之前,以此类推......我们需要用到的知识点就只有:(子节点-1) / 2 == 父节点,父节点 * 2 + 1 == 左孩子结点,父节点 * 2 + 2 == 右孩子结点,堆删除的思路,向下调整。对于这个小堆,这里新插入了一个0,需要进行调整,我们这时选择向上调整,即沿着祖先向上调整,其余部分不调整。

2024-03-16 11:30:36 324 1

原创 C/C++易错知识点(1):scanf函数

在控制台中,如果用EOF来作为循环条件的话,那么程序会被卡住,因为scanf会一直等我们输入,这个时候用0作为返回值的循环条件更好,因为下一个循环如果读不到想要的值,scanf的返回值就是0,这个时候循环就结束了。我们输入数据后敲的回车都是\n,相当于光标换行并回到起始位置,而\r只是回到起始位置,如果进行后续操作,会进行覆盖。在循环读取时,scanf会跳过每次按的\n(回车),所以这里不会因为\n不匹配%d而中断。scanf会根据占位符的类型到缓冲区去取相应的数据,其中%c什么都能取,包括空格等符号。

2024-03-13 22:57:55 361 1

原创 C语言数据结构易错知识点(2)

(指针的指针),而后续的接口就不需要二级指针,因为访问后续的结点只需要找到第一个节点即可,第一个节点可以通过new1存储的值找到,所以拿到new1的值就可以对后续结点实行操作,传值即可。在主函数中创建了new这个结构体,里面包含了两个指针和一个整型变量,其中那两个指针是野指针,需要被处理,这个时候初始化直接传结构体指针,将里面的值改为0和NULL。使用这种方式的话,我们在栈区创建的是一个指针,但此时这个指针相当于野指针,不能使用,要让它指向一片ListNode的空间,这个空间会在堆上开辟。

2024-03-03 17:42:56 730

原创 C语言数据结构易错知识点(1)

如果使用new1,一定要注意指针之间的关系,要通过两个malloc来创建顺序表,其中new1存储的值是堆区里SeqList的地址(初始化时要传二级指针,传址,这样才能改变new1存储的值),arr又作为DataType*类型的指针维护DataType数据。但难点在于当有2个甚至更多.h文件时,很多人并不知道把声明和库函数的引用放在哪个文件里,从而出现相互引用的情况,例如在test1.h里引用test2.h,又在test2.h中引用test1.h,这在逻辑上是一种死循环,肯定是行不通的。

2024-03-03 14:22:59 801

原创 C语言相关概念和易错语法(9)

= 4,而a = (2 + 2, a * 5, a + 10, 4 + 5) 表达式的值是9, a == 9。4.含++,--的表达式的值取决于++或--的位置,前置则先执行++,--操作,再返回值;,而char arr[10] = 'H'不可行,因为'H'表达式的值是H的ASCII码值而不是地址。也可防止在解读代码时先入为主,如 1

2024-02-23 13:03:25 878 1

原创 C语言贪吃蛇初步实现、思路

在相应状态下,蛇进行相应的操作,只有按下改变方向的按键,蛇的状态就会被改变。同时,或许我们还会注意到我这个函数传了Score_All, Score_Per这两个参数,这是因为蛇可以加速或减速,针对不同的速度有不同的分数,传过来这两个参数并在地图上展示出来,让玩家能实时看到自己的单个食物得分、总分。首先我们要知道一个光标格子是矩形,水平方向x坐标间距离是竖直方向y的一半,因此要打印一个正方形的地图需要自己算清楚横坐标和纵坐标的界限,以及你打算打印的墙的层数,x轴建议都以偶数为基本单位,否则会出现错位的现象。

2024-02-04 15:59:37 530 2

原创 C语言相关概念和易错语法(8)(预处理、编译、链接)

第二种是"xxx.h",先在我们所写的.c文件的同级目录下找是否有相应的头文件,如果没有,再到标准库里去找,再没有就报错。在指针的章节我就分享过:*在不同的地方应该有不同的理解,有的时候int*要合在一起理解,有的时候要拆开随着变量作为一个整体去理解。编译生成的是.s文件,它主要是将我们写的代码进行进一步检查(词法,语法,语义等分析),词法语法问题会在这个阶段被发现。具体处理方法是删去没必要的(如#if判断为假的代码块和注释),展开引用的头文件,生成.i文件,.i文件的内容还是C语言,我们依然能够看懂。

2024-01-22 23:57:32 849 2

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除