- 博客(26)
- 收藏
- 关注
原创 【数据结构】动态顺序表的实现
顺序存储结构:把数据元素放到地址连续的内存单元里面,其数据间的逻辑关系和物理关系是一致的,比如我们常用的数组就是顺序存储结构。链式存储结构:是把数据元素存放在任意的存储单元里面,这组存储单元可以是连续的,也可以是不连续的。此时,数据间的物理关系不能反映其逻辑关系。所以每一数据元素均使用一个结点来存储,不仅需要存储数据元素,而且还要存储数据元素之间的逻辑关系(将结点分为两部分,一部分存储数据元素本身,称为数据域;一部分存储下一个结点的地址,称为指针域。)
2024-08-23 16:47:17
674
原创 预处理详解
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副用就是表达式求值的时候出现的永久性效果。宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。当我们把a替换到宏的体内时,就出现了#
2024-08-03 11:01:00
1127
1
原创 编译和链接
预处理阶段主要处理那些源文件中#开始的预编译指令。比如:#include, #define,处理的规则如下:将所有的 #define 删除,并展开所有的宏定义。处理所有的条件编译指令,如: #if、#ifdef、#elif、#else、#endif 。处理#include 预编译指令,将包含的头文件的内容插入到该预编译指令的位置。这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件。删除所有的注释。添加行号和文件名标识,方便后续编译器生成调试信息等。或保留所有的#pragma的编译器
2024-07-31 00:09:55
714
原创 C语言之文件操作(2)
从流中读取字符,并将它们作为C字符串存储到str中,直到读取了(num-1)个字符,或者到达了换行符或文件结尾,无论哪种情况先发生。换行符使fgets停止读取,但它被函数认为是有效字符,并包含在复制到str的字符串中。在复制到str的字符后会自动追加一个终止空字符。返回值:如果读取成功,该函数将返回str。如果在试图读取字符时遇到文件结尾或者遇到错误导致读取失败就会返回NULL。从内存向磁盘输出的数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。
2024-07-28 22:35:19
1278
原创 文件读取结束的判定
文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets ) 例如:fgetc 判断是否为 EOF(读取正常,返回读取到字符的ASCII码值;读取过程中发生错误或遇到文件末尾,返回EOF) 。fgets 判断返回值是否为 NULL (读取正常,返回存储字符串的字符数组的地址;读取过程中发生错误或遇到文件末尾,返回NULL)。feof 的作用:在文件读取已经结束的基础上,判断文件读取结束的原因是否是遇到文件末尾而结束(检测相应的标记)。
2024-07-28 20:02:04
318
原创 C语言柔性数组详解
2.柔性数组的特点结构体中的柔性数组成员前面必须至少有一个其他成员。sizeof 返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结构用malloc 函数进行内存的动态分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的预期大小。
2024-07-21 23:52:09
775
原创 动态内存经典笔试题分析
出了函数,局部变量p已经销毁,函数返回后,str依然为空指针,把hello world拷贝放到空指针指向的空间去,拷贝必然存在对空指针的解引用操作,程序就会崩溃。这部分代码要表达的意思其实是想把malloc开辟的100个字节的空间的地址传给str,接着拷贝内容。情况1:当跳出函数后,恰好p指向的空间没有被操作系统使用,就可以打印出来hello world。情况2:当跳出函数后,p指向的空间已经被覆盖了,就不能完成任务。请问运行Test 函数会有什么样的结果?请问运行Test 函数会有什么样的结果?
2024-07-21 15:57:10
345
原创 动态内存管理
我们已掌握的内存开辟方式:但是上述的开辟空间的方式有两个特点:这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。函数原型如下:malloc的申请和使用 到内存窗口观察开辟的空间是否能使用: C语言提供了另外一个函数free,是专门用来做动态内存的释放和回收的,函数原型如下:free的使用 4.callocC语言还提供了一个函数叫 calloc ,也是用来动态内存分配的。函数原型如下:那 realloc 函数就可以做到对动态开辟内存大小的调整,函数原型如下:
2024-07-21 00:38:23
833
原创 联合和枚举
目录1.联合体1.1联合体类型的声明1.2联合体的特点1.3相同成员的结构体和联合体对比1.4联合体大小的计算 1.5联合体的练习 2.枚举类型2.1枚举类型的声明2.2枚举类型的优点2.3枚举类型的使用运行结果: 运行结果:使用联合体是可以节省空间的。1.5联合体的练习 2.枚举类型2.1枚举类型的声明 运行结果:2.2枚举类型的优点1.增加代码的可读性和可维护性 以上代码可改写为:2.和#def
2024-07-19 21:57:51
852
原创 C语言内存函数
memcpy函数从source的位置开始向后复制num个字节的数据到destination指向的内存位置。虽然使用memcpy函数能完成任务,但是也需谨慎使用,memcpy不负责空间重叠问题。如果source和destination空间有任何的重叠,复制的结果都是未定义的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。这个函数在遇到 '\0' 的时候并不会停下来。以下程序会是我们期待的1 1 1 1 1吗?memmove和memcpy的。为单位设置成想要的内容。如果换成设置整型呢?
2024-07-17 20:02:48
738
原创 字符函数和字符串函数(2)
在不同的系统和C语言标准库的实现中都规定了一些错误码,一般是放在 errno.h 这个头文件中说明的,C语言程序启动的时候就会使用一个全面的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表示没有错误,,每一个错误码都有它对应的错误信息,而一个错误码是数字,很难理解是什么意思,strerror函数就可以将错误码对应的错误信息字符串的地址返回,利用字符串的地址就可以打印错误信息。当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码存放在errno中。
2024-06-29 15:51:53
1043
原创 字符函数和字符串函数(1)
C语言中有一系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的。这些函数的使用都需要包含一个头文件是islower 是能够判断参数部分的 c 是否是小写字母的。通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回 0。运行结果:练习写一个代码,将字符串中的小写字母转大写,其他字符不变。
2024-06-28 15:58:30
1021
原创 C语言sizeof与strlen详解
sizeof 计算的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。sizeof 只关注占用内存空间的大小,不在乎内存中存放什么数据。strlen 是C语言库函数,功能是求字符串长度。统计的是从 strlen 函数的参数 str 中这个地址开始向后,。strlen 函数会一直向后找 \0 字符,直到找到为止,所以可能存在越界查找。1. sizeof是操作符。2. sizeof计算操作数所占内存的大小,单位是字节。3. 不关注内存中存放什么数据。
2024-06-25 21:05:21
449
原创 qsort排序
我们发现函数参数部分整型数组接收,所以这个函数只能排序整型数据。而qsort是用来排序的库函数,,它可以对指定数组(包括字符串,二维数组,结构体等)进行排序,底层使用的是快速排序的方式。在使用冒泡排序的情况下,我们想要改造这个函数,让它能够排序任意类型的数据,我们发现两个整型元素的比较可以直接使用 '>',但是两个字符串,两个结构体的比较不能直接使用 '>'。我们可以封装成函数,然后把传递给排序函数。
2024-06-22 20:16:46
762
原创 C语言之指针(4)
需要注意的是常量字符串的内容不能被修改,所以我们用const来修饰,警示自己这个字符串不能被修改。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际上会指向同一块内存。解释:p先和 * 结合,说明p是一个指针变量,然后指针指向的是一个大小为10个整型的数组。我们知道,指针数组是一种数组,数组中存放的是地址(指针)。数组指针变量是指针变量?存放的是整型变量的地址,能够指向整型数据的指针。注意:[] 的优先级要高于 * 的,所以必须加上()来保证 p 先和 * 结合。
2024-06-17 18:44:24
80
原创 C语言之指针(3)
pp 操作是对pp进行解引用,pp里面存的是p的地址,然后解引用找到p,p中存的是a的地址,所以*pp等价于&a,**pp等价于对&a进行解引用,最终找到a。,数组元素的访问在编译器处理的时候,也是转换成首元素的地址+偏移量求出元素的地址,然后解引用来访问的。,这里的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)。,sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小, 单位是字节。除此之外,任何地方使用数组名,数组名都表示首元素的地址。
2024-06-16 11:41:58
670
原创 C语言之指针(2)
我们发现在main函数内部,创建了a和b,在调用swap1函数时,将a和b传递给了swap1函数,在swap1函数内部创建了形参x和y接受a和b的值,x和y是新的独立的内存空间,与a和b的地址不一样,那么在Swap1函数内部交换x和y的值, 自然不会影响a和b,当swap1函数调用结束后回到main函数,a和b没发生交换。这时就可以使用指针了,在main函数中将a和b的地址传递给swap函数,swap 函数里边通过地址间接的操作main函数中的a和b,达到交换的效果。这个宏常常被称为“断言”。
2024-05-09 21:34:18
684
1
原创 C语言之指针(1)
就是为了a不能被修改,如果p拿到a的地址就能修改a,这样就打破了const的限制,这是不合理的,所以应该让 p拿到a的地址也不能修改a,那接下来怎么做呢?这里如果目的仅仅就是把a改成0的话,写成 a = 0;一般 void* 类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,这样的设计可以 实现泛型编程的效果,使得一个函数来处理多种类型的数据。同理,64位机器,假设有64根地址线,一个地址就是由64个二进制位组成的二进制序列,存储起来就需要8个字节的空间,指针变量的大小就是8个字节。
2024-05-08 15:05:15
645
1
原创 结构体(1)
C语言已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类 型还是不够的,假设我想描述学生,描述⼀本书,这时单一的内置类型是不行的。仔细分析,其实这种思想不合理,因为一个结构体中再包含一个同类型的结构体变量,这样结构体变量的大小就会无穷的大,是不合理的。因为Node是对前面匿名结构体类型的重命名产生的,但是在匿名结构体内部提前使用Node类型来创建成员变量,这是不可行的。结构的每个成员可以是不同类型的变量,如: 标量、数组、指针,甚至是其他结构体。
2024-05-06 19:53:25
297
原创 结构体(2)
而对齐的内存访问仅需要一次访问。print1函数,函数传参的时候,s占多大内存空间,tmp就得创建多大内存空间,参数需要压栈,会有时间和空间上的系统开销,如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。下图是网络协议中,IP数据报的格式,我们可以看到其中很多的属性只需要几个bit位就能描述,这里使用位段,能够实现想要的效果,也节省了空间,这样网络传输的数据报大小也会较小一些,对网络的畅通是有帮助的。例如a中存放0,1,2,3的其中一个数,只需要两个比特位就够了。
2024-05-06 10:50:53
1503
原创 详解操作符
此时得到的是补码,要原码才能打印 ,原码为10000000 00000000 00000000 00000001,此时打印-1。此时得到的是补码,要原码才能打印 ,原码为10000000 00000000 00000000 00000011,此时打印-3。此时得到的是补码,要原码才能打印 ,原码为10000000 00000000 00000000 00001000,此时打印-8。此时得到的是补码,要原码才能打印 ,正整数的原码反码补码都相同,此时打印5。
2024-05-05 12:02:26
1362
1
原创 数据在内存中的存储
这可以应对char类型数据的存储要求,因为char类型长度刚好是1个字节,但是有些类型的长度是超过1个字节的(字符串虽然是多字节的,但它本质是由一个个char类型组成的类似数组的结构而已),比如C/C++中,short类型一般是2个字节,int类型一般4个字节等。计算机中数据是以二进制的形式存储在内存中的,整数在内存中的存储又分为原码、反码、补码三种,三种表示方法均有符号位和数值位两部分,符号位用0表示”正“,用1表示”负“,而数值位最高位的一位被当作符号位,剩余的都是数值位。
2024-04-04 14:45:19
1746
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人