打鱼又晒网
不幻想, 不侥幸。冷静,理智地应对变化。
展开
-
预处理指令——一些比较少见的概念
define可以定义常量, 具体做法如下#define MAX 10//定义常量int main()i < MAX;这里就是#define定义常量, 常量值应该在常量名后边。#define定义常量的本质其实就是一种替换, 预处理阶段, 编译器会将源代码中的#define定义的常量进行替换。什么意思?如下:现在我们还是看上面一串代码:int main()i < 10;这里的MAX进行了替换。原创 2024-04-01 12:05:23 · 1915 阅读 · 73 评论 -
程序的编译和链接
前言:C语言的源代码到我们在屏幕上输出结果要经过两大环境,一个是翻译环境,一个是执行环境。其中翻译环境是由编译器控制, 执行环境是由操作系统控制。本篇内容指向我们的C语言源代码是如何到在屏幕上输出结果,通过解析两大环境来进行说明。两大环境要做的大致内容如下我们自己写的C语言源代码是.c文件。翻译环境有两大工序, 一个是编译, 一个是链接。然后就生成了我们的可执行程序, 也就是.exe文件,注意, 这些都是帮我们做的。原创 2024-03-30 23:38:14 · 1050 阅读 · 27 评论 -
排序——堆排序
在复习堆排序之前, 首先我们需要回顾一下什么是堆。堆的本质其实是一个数组。它的物理结构本质上是一个数组。但是它的逻辑结构是一棵完全二叉树。我们在判断一个数组是否是一个堆的时候根据的就是它的逻辑结构。那么怎么根据它的逻辑结构判断是否是一个堆。首先堆的逻辑结构的二叉树的每一个孩子节点都大于它的每一个父亲, 就是堆。这种堆叫做小堆。如果它的逻辑结构的每一个孩子节点都小于它的父亲节点。它同样是个堆, 同时这种堆叫做大堆。原创 2024-03-04 19:45:55 · 1030 阅读 · 5 评论 -
文件操作知识点
这节主要复习文件操作的知识。首先我们应该知道文件操作有利于我们储存信息, 假如我们运行程序计算出数据但是没有保存, 那么这些数据就丢失了, 而使用文件我们就能让数据进行长久的保存。原创 2024-02-29 20:47:26 · 904 阅读 · 1 评论 -
指针的运算
这节主要解析几个指针运算的题加深对指针的理解。原创 2024-02-28 12:11:56 · 925 阅读 · 0 评论 -
柔性数组知识点
什么是柔性数组?柔性数组其实也是动态内存管理部分的内容。这节主要来复习柔性数组的知识点。当结构体的最后一个成员为数组, 且这个数组的大小未确定时, 我们就称它是柔性数组。如:struct stuint age;这里的adress就是一个柔性数组。(写成char adress[0] 可能报错)原创 2024-02-21 23:02:27 · 455 阅读 · 4 评论 -
动态内存管理(下)
(malloc,, calloc, free函数的用法以及注意事项等知识点)(常见的内存出错问题)---------------------------------------------------------------------------------------------------------------------------------前两节复习了动态内存函数和常见内存出错的问题。这节主要分析几个容易出错的问题加深印象。原创 2024-02-21 22:03:25 · 986 阅读 · 0 评论 -
动态内存管理(中)
(malloc, realloc, calloc, free函数的用法以及注意事项等知识点)另外动态内存管理因为涉及到了内存的问题, 所以很容易出错,本节回顾容易出错的点。原创 2024-02-20 22:08:40 · 372 阅读 · 0 评论 -
动态内存管理(上)
这节主要复习动态内存管理中的malloc, realloc, calloc, 以及free。原创 2024-02-20 21:40:27 · 861 阅读 · 0 评论 -
const 知识点解析
这个方法我们绕过了a变量, 直接操作地址,虽然没有语法错误, 但是不建议这样写, 因为容易出错。这个方法可以理解为,使用const 修饰 a, 虽然对于a这个变量名来说, 不能直接使用a这个变量名直接进行修改。当我们在c语言中碰到这么一种情况:我们现在有一个变量, 这个变量呢,我们指向访问它, 但不会修改它。p2是const在int* 后修饰, const修饰在int* 后的意思是p2这个变量不能修改指向。p1是const 在int* 前修饰, const 修饰在int* 前意思是p1指向的值不能修改。原创 2024-02-18 23:26:57 · 460 阅读 · 0 评论 -
c语言实现扫雷
1.对于扫雷游戏,我们首先应该思考一下扫雷可能是怎么实现的,我们在网页上玩的扫雷,我们对某一个坐标进行排查,如果这个坐标后面是雷,那么游戏失败,而如果不是雷,那么就会展开。那么,我们就可以想到,这里可能会用到两个棋盘,一个是展示给我们看的游戏棋盘,一个是棋盘背后的雷区。这里我们就可以想到,这个游戏我们最基本的应该创建两个棋盘,一个用来展示,一个用来判断是否触发了雷。2.然后,我们要想,我们应该怎么创建这两个棋盘,其次,创建完这两个棋盘之后要做什么。怎么创建这两个棋盘?原创 2024-02-17 23:43:21 · 1496 阅读 · 0 评论 -
结构体实现位段
下面是一个定义的位段这里成员后面的数字代表比特位。int a : 1;代表a只占一个比特位。位段中的元素只能是int, char, 或者unsigned char 等等。原创 2024-02-16 23:54:19 · 727 阅读 · 0 评论 -
枚举知识点解析
枚举是什么?枚举就是列举, 将东西一一列举出来。生活中有许多地方需要用到枚举, 比如一年有12个月,一星期有7天, 这些都需要进行枚举。那么, 如何进行枚举的定义呢?如下枚举中的值是一种常量。而这个常量的值可以修改, 规则如下:枚举中的元素如果不进行赋值的话, 第一个默认为0, 第二个元素为1, 以此类推。但是如果将第一个元素进行赋值, 假如复制成为1, 那么第二个元素就会是2, 以此类推。如果枚举中的每个元素都不是连续的话, 那么也可以将其进行分别赋值。原创 2024-02-14 23:32:13 · 791 阅读 · 0 评论 -
联合体知识点解析
联合体:联合体也是一种自定义类型, 特点是成员变量公用一块空间。所以也叫共用体。原创 2024-02-09 22:58:17 · 692 阅读 · 0 评论 -
结构体的大小以及内存对齐问题
结构体的对齐 就是 结构体类型数据在内存中按照一定的对齐规律储存。结构体的对齐归根结底其实就是用空间换取时间的做法。至于为什么可以用空间换取时间呢?请看这么一张图:假如一个结构体的数据像图中这样摆放。如果一个cpu读取数据, 是按照8个字节8个字节的规律进行读取。那么他从a的首地址开始读取,第一次读取可以将int读完, 但是此时只读取了一半的double 类型的b, 想要完全读取b还要再多读取一次,这就造成了时间的浪费。但是, 如果按照结构体对其规律进行数据存储呢?原创 2024-02-08 23:26:35 · 1482 阅读 · 0 评论 -
结构体的特殊声明和自引用
结构体我们通常是这么声明的:int age;int num;或者int age;int num;}s1, s2;这是我们正常的声明方式, 也是正规的声明方式, 第二种是声明的同时创建了变量s1, s2。但是结构体的声明方式也包括一种特殊的声明方式——不完全声明。下面是不完全声明:structint a;int b;int c;}a, b, c;这种结构体只能在创建该结构体蓝图时创建变量。之后这个蓝图就再也无法使用。原创 2024-02-06 22:11:25 · 735 阅读 · 0 评论 -
typedef
而P_int就不会发生这种情况, 因为typedef重定义int* 后, 已经将P_int类型作为新的一种类型, 这个类型的类型名是P_int,类型和int* 一样。我们可以看到, 这里的pd并不是int * 类型, 而是一个int类型, 那么为什么会是这样呢, 因为宏会在预处理阶段将定义重现转化为原来的东西。在预处理阶段,P_INT被转换成立int*, 但是我们直到, 这个int* 是不能作用于pd的, 想要令pd也是指针必须在pd前面加*。增加了程序的可维护性。P_int_ 5就是我们要的类型名。原创 2024-02-03 22:28:03 · 768 阅读 · 0 评论 -
转移表实现计算器
通过函数指针数组, 可以将需要计算的函数地址保存下来, 这样就算多加许多需要计算的函数,也能使代码显得不是过于荣冗余。以上就是一个简易的计算机。函数主体部分可见有些冗余。如果使用转移表的话,就会优化很多。do while循环是为了多次进行计算,只有输入为0时才会推出。而switch有利于这种选择类问题。原创 2024-02-02 21:32:08 · 429 阅读 · 0 评论 -
指针的深入理解(四)
sizeof(&arr) : 上面已经说过,arr只有在两种情况下表示的不是首地址(首地址是个常量,常量无法进行取地址),一种sizeof,一种&arr, &arr的值仍旧是arr常量的值, 但是类型不同。可以理解为arr本身就是一个数组的首地址,可以进行整数加减运算,进行加一运算后仍是一个地址,这个时候的arr + 1只是一个地址,没有别的特别意义。) : arr只有在两种情况下不是数组的首地址,一种情况就是sizeof运算符操作时,也就是这种情况,这总情况下arr代表的是整个数组, 是一个对象。原创 2024-02-01 20:32:56 · 1110 阅读 · 0 评论 -
指针的深入理解(三)
这一节主要使用复习回调函数, 利用冒泡模拟实现qsort函数。原创 2024-01-31 21:20:17 · 555 阅读 · 0 评论 -
函数递归的总结回顾
函数递归的本质就是其名字——递与归。先递出去, 再收回来。而递归的思想就是为了让一个复杂的问题变成一个简单的问题按照我目前的理解,函数递归有两点很重要。一个是它的,另一个就是函数体内“限定条件很好理解,一个函数递归,如果没有限定条件,将会陷入死递归。而“自调”的位置对于整体的函数逻辑有巨大的影响。为了能够更加理解这种影响,我在这里放上一个例子:这两张图分别是printf 在“自调”前后的运行图。可以看到结果有很大的差异。原因就是因为逻辑问题,下面是这两个程序的逻辑图。原创 2024-01-23 22:43:28 · 637 阅读 · 1 评论 -
指针的深入理解(二)
这节主要复习函数指针。原创 2024-01-30 20:49:21 · 564 阅读 · 1 评论 -
指针的深入理解(一)
这一节主要复习数组指针,int (* )[ ] 就是数组指针类型的标志。因为有()将*括起来,所以(*)表示一个指针。[ ] 表示数组,所以(*)[ ]就表示一个指向数组的指针, int是数据的类型。所以int (*) [ ]表示指向一个数组的指针,元素类型是int, 个数是[ ]里面的数。原创 2024-01-29 22:15:47 · 752 阅读 · 0 评论 -
结构体的增删查改
结构体,是为了解决生活中的一些不方便利用c语言自带数据类型来表示的问题。例如表示一个学生,那么学生这个个体假如用c语言自带数据类型怎么表示呢。可以使用名字,也就是字符数组;也可以使用学号,也就是int类型。但是这些都不太准确,因为一个学生,他不但有学号或者名字,还应该要有性别,年龄,年级。如果想要更加准确,还需要加上出生年月以及地址等等。那么这时候很难使用c语言自带类型来表示。这样可以创建一个结构体。如图:这样我们就是创建了一个学生的结构体蓝图,数据类型是结构体struct类型。原创 2024-01-28 18:01:29 · 555 阅读 · 0 评论 -
函数传参数组时,使用数组形参的本质
传送数组函数进行接收时,必定要创建一个形参,假如创建一个相同的数组,这个空间就占用太大了,而如果是一个指针的话,空间花费就少了太多。首先,数组名是首地址,是一个常量,一个指针常量。第一:使用sizeof计算数组大小时,此时数组名不是首地址,数组名此时就是一个抽象的变量名,类似于int a = 10 中的a这个变量名, 而它所代表的空间就是数组一整块空间。在学校中,我们的老师给我们讲的是:我们可以理解为因为数组名等于首地址,将数组名传送过去之后,形参数组名接受到这个地址,那么两者就共用同一块空间。原创 2024-01-22 20:47:02 · 593 阅读 · 0 评论 -
常用内存函数的用法和模拟实现
这一节主要讨论是:memcpy函数的使用以及模拟实现。memmove函数的使用以及模拟实现。memset函数的使用。memcmp函数的使用。原创 2024-01-21 19:10:07 · 444 阅读 · 1 评论 -
字符串函数的模拟实现
在这一节之前已经讨论了常用的字符串函数的功能,这一节将要进行常用字符串函数的模拟实现。原创 2024-01-20 15:52:45 · 461 阅读 · 0 评论 -
c语言操作符详解(三)
本节主要分析赋值操作符,算术操作符,关系操作符,逻辑操作符,逗号表达式,下标引用操作符以及函数调用、结构体调用操作符。原创 2024-01-18 14:48:30 · 1344 阅读 · 1 评论 -
字符串函数以及字符函数的用法
下图为这些字符串的主要功能。原创 2024-01-19 16:48:46 · 1026 阅读 · 1 评论 -
c语言操作符详解(一)
这一节主要分析单目操作符,条件操作符。原创 2024-01-16 21:54:48 · 586 阅读 · 1 评论 -
c语言操作符详解(二)
本节主要讨论位操作符:包括按位与&、按位或|、按位异或^。以及讨论移位操作符:左移位原创 2024-01-17 10:13:19 · 676 阅读 · 0 评论 -
指针的类型
但是如果对这个数组取地址,那么得到的虽然也是首地址,但本质上是一个数组的地址,接受这个地址就不能单纯的用一个int* 类型或者char* 类型指针接收,而是需要用到数组指针。数组指针的类型写法是(这里用整形数组演示),整形数组指针写法:int (* p)[10],表示p是一个指向元素个数是10,元素类型是int的数组的数组指针。而实现方式就是,我们将一个函数(我们这里叫做函数1)的指针传给另一个函数(我们这里叫作函数2),当函数2在执行过程中,可能会用到这个函数,调用时,我们就称为函数回调。原创 2023-12-28 00:47:51 · 763 阅读 · 1 评论 -
c语言各个数据类型在内存中的存储方式
主要有数组类型、结构体类型、枚举类型、联合体类型。数组也是一种构造的数据类型。例如我们定义int a [5] = { 0 };这里int [5]就是一种数据类型,他表示一块内存空间,这块内存空间里面有五个元素,每个元素是int。下面再定义一种类型:int b [6] = { 0 };这一种类型和上一种数据类型就不一样了,尽管他们的元素都是int, 但是这里的数据类型是int [6], 而上面的是int [5]。原创 2024-01-11 21:33:57 · 1552 阅读 · 0 评论 -
个人对c语言利用变量名对数据进行存储的理解
打印的时候因为打印的是浮点类型,且取出数据的时*pb(也是浮点类型)。我一开始对这个问题很迷茫。但是,之后我利用数据存储的知识与指针方面的理解,让我自己理解了这个问题(注意,是让我自己理解。而不是我理解了,只是我自己说服了我自己)。这也是我之前的理解,但是遇到了上面的问题之后,我开始从另一方面思考问题。结果,这两次打印的结果是完全不一样的。我这里的是否可以这样解释:我在main函数的栈空间里面为a开辟了一处四字节的空间,然后又。我认为这个问题的核心就是内存和怎么看待变量名的问题。原创 2024-01-12 17:07:42 · 481 阅读 · 1 评论 -
函数栈帧的创建与销毁(这里使用vs2022进行演示)
我们在开始学习函数栈帧的创建与销毁之前,要先了解一下这几个寄存器:这里面eax, ebx, ecx是通用寄存器,保存临时数据;eip是指令寄存器,保存当前指令的下一条指令的地址。这里面最重要的是esp,ebp这两个寄存器。我们要了解函数栈帧,就必须了解esp,ebp这两个寄存器。esp,ebp两个寄存器里面存放的都是地址。这里面esp是栈顶寄存器,保存的是函数栈帧的栈顶地址。ebp是栈底寄存器,保存的是函数栈帧的栈底地址。esp与ebp共同维护着函数的栈帧空间。原创 2024-01-01 23:23:54 · 660 阅读 · 0 评论 -
关于&的简单用法
2转换为二进制为10, 3转换为二进制为11,2与3进行与的运算,就是10,与11进行运算,二位处两个数都为1,则运算结果的二位为1,个位处两个数为1与0, 则运算结果个位为0.则运算结果的二位为1,个位为0,即10。另外,&也可以做与的计算。此时&是一个双目运算符。该计算方式是一个二进制运算,意思是对应的二进制每一比特位都进行计算,如果两个比特位都是1,则计算机结果对应的1。在应用&&时应注意短路问题,如果&&左边已经可以确定整个表达式的值,就不会再运算&&右边的式子。&是取地址符,可以取出变量的地址。原创 2023-12-12 12:58:35 · 366 阅读 · 0 评论 -
数组的简单介绍
初始化时可以直接按照数组的总个数直接将数组内的元素初始化,如:nums【2】【2】 = { 1, 2, 3, 4 };则,其中1,2是第一行的,3,4是第二行的。也可以利用第二种初始化方式,int nums【2】【2】 = { {1 }, {1,3}};这样第一个括号里面的就是第一行的元素,而第二个括号就是第二行的元素,不管第一行是否被排满,都会跳到第二行。另外,在二维数组之中,二维数组的列是不能被省略的,因为二维数组在内存中的存储方式其实也是以列的方式进行储存,在列不能确定的情况下,行也不能确定。原创 2023-12-04 22:28:21 · 337 阅读 · 0 评论 -
关于c语言的分支与循环
if语句之中还有两个配套使用的功能,else和else if,如果if判断结果为假,后面就可以跟上else以及所要执行的语句。do while语句先执行语句,再进行判断。如果有符合的case语句,那就从符合的case语句进入,然后一条一条地执行下去,如果想要停下来,那就必须加上break,意思就是说,case语句决定了入口,但是break决定了出口。c语言之中一共有9种控制语句,其中判断语句也就是分支选择语句为if语句和swich语句,循环语句为for语句,while语句,do while语句。原创 2023-12-04 19:16:16 · 397 阅读 · 0 评论