贪吃蛇及相关知识点讲解

游戏效果演示

贪吃蛇游戏页面

为了完整呈现上述游戏效果,我将系统讲解贪吃蛇游戏的具体实现方案,包括开发步骤、设计理念及关键技术要点。

游戏准备工作

如果您使用的是VS2022编译器,可以参考以下修改方案。若使用其他开发环境,建议查阅确认是否需要类似调整。

按下 Ctrl+F5 后若出现上述界面,请按以下步骤进行修改

4.您可以在红框标注的选项中选择其一

5.修改后务必点击保存

游戏设计思路

我们以test.c文件作为游戏测试入口,通过snack.c实现核心游戏逻辑,并在snack.h中完成函数声明。接下来先介绍整体设计思路,随后再进行具体代码实现及关键技术要点。

第一:创建贪吃蛇

  • 定义蛇节点的数据结构,包含指针域和以坐标表示的数据域
  • 创建贪吃蛇游戏的核心功能模型
  1. 蛇头节点指针
  2. 食物位置指针
  3. 当前移动方向参数
  4. 游戏状态标识
  5. 食物分值设定
  6. 累计得分统计
  7. 移动速度控制参数

第二:初始化游戏

按照上面的的游戏效果演示,设计游戏介绍页面,让玩家在体验前就能对游戏形成初步认知。这有助于顺利完成游戏的初始引导流程。

  1. 隐藏光标
  2. 显示欢迎界面
  3. 介绍游戏功能
  4. 初始化游戏地图
  5. 生成蛇的初始位置
  6. 随机放置食物
  7. 实现贪吃蛇游戏的核心功能模块

第三:游戏运行

  1. 显示帮助信息
  2. 输出总分与当前食物得分
  3. 监听键盘输入
  4. 根据游戏状态判断是否继续运行

第四:游戏结束

  1. 定位
  2. 更新游戏状态
  3. 释放蛇身占用的链表空间

游戏核心代码实现

第一:创建贪吃蛇

枚举(enum)

定义枚举类型

cpp 复制代码
enum 枚举名 {
    枚举常量1,
    枚举常量2,
    ...
    枚举常量n
};

默认值:如果你不指定值,第一个枚举常量的值是 0,后面的依次递增 1

cpp 复制代码
enum Color { RED, GREEN, BLUE };
// RED 的值是 0
// GREEN 的值是 1
// BLUE 的值是 2

printf("%d, %d, %d\n", RED, GREEN, BLUE); // 输出: 0, 1, 2

代码实现

snack.h中

cpp 复制代码
//蛇的方向
enum DIRECTION
{
	UP,
	DOWN,
	LEFT,
	RIGHT
};

//游戏的状态
enum GAME_STATUS
{
	OK,
	EXIT,
	KILL_BY_WALL,
	KILL_BY_SELF
};

//相当于蛇的一个结点所包含的数据域和指针域
typedef struct SnackNode
{
	int x;
	int y;
	struct SnackNode* next;
}SnackNode,*psnacknode;//作用:声明变量和创建指针(结点)

//创建贪吃蛇(相当于整个游戏
typedef struct Snack
{
	psnacknode _psnack;//指向蛇头的指针
	psnacknode _pfood;//指向食物的指针
	enum DIRECTION _dir;//蛇的方向
	enum GAME_STATUS _status;//游戏的状态
	int _foodscore;//食物的分数
	int _score;//总分数
	int _sleep_time;//蛇的速度,休息的越短,蛇的速度越快
}Snack,*pSnack;

第二:初始化游戏

系统调用

system()函数可以执行命令行指令。

cpp 复制代码
system("mode con cols=100 lines=30"); 调用命令行指令来设置控制台窗口的大小。

system("title 贪吃蛇"); 设置窗口标题。

system("cls"); 清空屏幕。

system("pause"); 暂停程序,等待用户按键。

句柄

GetStdHandle:返回的句柄可供需要在控制台中进行读取或写入的应用程序使用

此参数的取值可为下列值之一。

cpp 复制代码
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值) 
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

GetConsoleCursorInfo:检索有关指定控制台屏幕缓冲区的游标大小和可见性的信息。

语法知识:

cpp 复制代码
BOOL WINAPI GetConsoleCursorInfo(
  _In_  HANDLE               hConsoleOutput,//控制台屏幕缓冲区的句柄
  _Out_ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
//指向 CONSOLE_CURSOR_INFO 结构的指针,该结构接收有关控制台游标的信息
);

实际应用中通常采用第一种HANDLE方式。

CONSOLE_CURSOR_INFO:包含有关控制台游标的信息。

cpp 复制代码
typedef struct _CONSOLE_CURSOR_INFO {
  DWORD dwSize;//由游标填充的字符单元格的百分比
  BOOL  bVisible;//游标的可见性。 游标可见,为 TRUE;不可见时,为FALSE;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
cpp 复制代码
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值) 
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息

SetConsoleCursorInfo:为指定的控制台屏幕缓冲区设置光标的大小和可见性。

cpp 复制代码
BOOL WINAPI SetConsoleCursorInfo(
  _In_       HANDLE              hConsoleOutput,//控制台屏幕缓冲区的句柄
  _In_ const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
//指向 CONSOLE_CURSOR_INFO 结构的指针,该结构为控制台屏幕缓冲区的光标提供新的规范
);
cpp 复制代码
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//影藏光标操作
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
 

SetConsoleCursorPosition:设置指定控制台屏幕缓冲区中的光标位置。

cpp 复制代码
BOOL WINAPI SetConsoleCursorPosition(
  _In_ HANDLE hConsoleOutput,//控制台屏幕缓冲区的句柄
  _In_ COORD  dwCursorPosition//指定新光标位置(以字符为单位)的 COORD 结构
);
cpp 复制代码
OORD pos = { 10, 5};
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值) 
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos 
SetConsoleCursorPosition(hOutput, pos);

1.隐藏光标代码实现

基于上述知识,我们可以编写隐藏光标的程序代码

cpp 复制代码
system("mode con cols=100 lines=30");
//设置窗口的行和列,可以选择自己喜欢的大小来更改,cols是行,lines是列
system("title 贪吃蛇");
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);//三种形式,这种是标准输出(句柄)
CONSOLE_CURSOR_INFO cursorinfo;
GetConsoleCursorInfo(output, &cursorinfo);//获得光标控制台信息
cursorinfo.bVisible = false;//隐藏光标
SetConsoleCursorInfo(output, &cursorinfo);//设置光标控制台信息

设置光标位置

控制台窗⼝的坐标如下所⽰,横向的是X轴,从左向右依次增⻓,纵向是Y轴,从上到下依次增⻓

cpp 复制代码
void setPos(int x, int y)
{
	COORD pos = { x,y };//COORD是SetConsoleCursorPosition中的类型
	HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出的句柄
	SetConsoleCursorPosition(output, pos);//更改标准输出的句柄
}

2.显示欢迎界面代码实现

cpp 复制代码
setPos(35,15);//定位,可根据行列选择自己认为合适的位置
printf("欢迎来到贪吃蛇小游戏!");
setPos(35, 28);
system("pause");//暂停,输出"点击任意键继续..."
system("cls");//清除屏幕

根据上面的代码会出现以下界面:

locale本地化

<locale.h>提供的函数⽤于控制C标准库中对于不同的地区会产⽣不⼀样⾏为的部分。

通过修改地区,程序可以改变它的⾏为来适应世界的不同区域。但地区的改变可能会影响库的许多部 分,其中⼀部分可能是我们不希望修改的。所以C语⾔⽀持针对不同的类项进⾏修改,下⾯的⼀个宏, 指定⼀个类项:

LC_COLLATE:影响字符串⽐较函数 strcoll() 和strxfrm()

LC_CTYPE:影响字符处理函数的⾏为。

LC_MONETARY:影响货币格式。

LC_NUMERIC:影响 printf() 的数字格式。

LC_TIME:影响时间格式 strftime() 和 wcsftime() 。

LC_ALL:针对所有类项修改,将以上所有类别设置为给定的语⾔环境。

每个类项的详细说明,请参考

setlocale函数

setlocale 函数⽤于修改当前地区,可以针对⼀个类项修改,也可以针对所有类项。

setlocale 的第⼀个参数可以是前⾯说明的类项中的⼀个,那么每次只会影响⼀个类项,如果第⼀个参 数是LC_ALL,就会影响所有的类项。

C标准给第⼆个参数仅定义了2种可能取值:"C"(正常模式)和""(本地模式)。

cpp 复制代码
char* setlocale (int category, const char* locale);

在任意程序执⾏开始,都会隐藏式执⾏调⽤:

cpp 复制代码
setlocale(LC_ALL, "C");

当地区设置为"C"时,库函数按正常⽅式执⾏,⼩数点是⼀个点。

当程序运⾏起来后想改变地区,就只能显⽰调⽤setlocale函数。⽤""作为第2个参数,调⽤setlocale 函数就可以切换到本地模式,这种模式下程序会适应本地环境。

⽐如:切换到我们的本地模式后就⽀持宽字符(汉字)的输出等。

cpp 复制代码
setlocale(LC_ALL, " ");//切换到本地环境

宽字符

宽字符的字⾯量必须加上前缀"L",否则C语⾔会把字⾯量当作窄字符类型处理。

前缀"L"在单引 号前⾯,表⽰宽字符,对应 wprintf() 的占位符为 wprintf() 的占位符为 %ls 。

cpp 复制代码
#include <stdio.h>
#include<locale.h>
int main() 
{
    setlocale(LC_ALL, "");
    wchar_t ch1 = L'●'; 
    printf("%c%c\n", 'a', 'b');
    wprintf(L"%lc\n", ch1);
    return 0;
}

从输出的结果来看,我们发现⼀个普通字符占⼀个字符的位置 但是打印⼀个汉字字符,占⽤2个字符的位置,那么我们如果 要在贪吃蛇中使⽤宽字符,就得处理好地图上坐标的计算。

无法通过键盘直接输入宽字符中的特殊符号,需借助搜狗输入法的符号大全功能进行输入。

3.介绍游戏功能代码实现

cpp 复制代码
setPos(30, 14);
wprintf(L"用↑↓←→分别控制蛇的移动");
setPos(30, 15);
wprintf(L"用F3表示加速,F4表示减速");
setPos(35, 28);
system("pause");
system("cls");

4.初始化游戏地图代码实现

需要注意的是:宽字符占据两个字符宽度。因此在绘制贪吃蛇游戏墙面时,必须特别注意宽字符的显示位置。为确保准确定位,x轴坐标应设为偶数(假设坐标从0开始计数)。

cpp 复制代码
void CreatMap()
{
	//绘制地图的上方
	setPos(0, 0);
	for (int i = 0; i < 30; i++)
	{
		wprintf(L"□");
	}
	
	//绘制地图的下方
	setPos(0, 29);
	for (int i = 0; i < 30; i++)
	{
		wprintf(L"□");
	}
	
	//绘制地图的左方
	for (int i = 1; i < 29; i++)
	{
		setPos(0, i);
		wprintf(L"□");
	}

	//绘制地图的右方
	for (int i = 1; i < 29; i++)
	{
		setPos(58, i);
		wprintf(L"□");
	}
}

5.生成蛇的初始位置代码实现

如需了解随机数生成方法,请点击此处获取帮助

cpp 复制代码
void InitSnack(pSnack ps)
{
	int i = 0;
	int pos_x = 0;
	int pos_y = 0;
	do
	{
		pos_x = rand() % 48 + 8;
		pos_y = rand() % 27 + 1;
	} while (pos_x % 2 == NULL );//pos_x不能是奇数,否则容易有一半身体在游戏里,一半在墙内
	psnacknode cur = NULL;
	for (int i = 0; i < 4; i++)
	{
		psnacknode cur = (psnacknode)malloc(sizeof(SnackNode));
		if (cur == NULL)
		{
			perror("InitSnack::maalloc");
			return;
		}
		cur->next = NULL;
		//头插法(建议用头插法,头插法比较容易理解)
		cur->x = pos_x - i * 2;
		cur->y = pos_y;
		if (ps->_psnack == NULL)
		{
			ps->_psnack = cur;
		}
		else
		{
			cur->next = ps->_psnack;
			ps->_psnack = cur;
		}
	}
	//打印蛇身
	cur = ps->_psnack;
	for (int i = 0; i < 4; i++)
	{
		setPos(cur->x, cur->y);
		wprintf(L"●");
		cur = cur->next;
	}
}

6.随机放置食物代码实现

cpp 复制代码
//创建食物
void CreatFood(pSnack ps)
{
	int i = 0;
	int pos_x = 0;
	int pos_y = 0;
	//生成食物节点的位置
	again:
	pos_x = rand() % 48 + 8;
	pos_y = rand() % 27 + 1;
	if (pos_x % 2 == NULL)
	{
		goto again;
	}
	psnacknode cur = ps->_psnack;
	for (int i = 0; i < 4; i++)
	{
		if (pos_x == cur->x && pos_y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	}
	setPos(pos_x, pos_y);
	wprintf(L"★");
	//创建食物节点
	psnacknode pFood = (psnacknode)malloc(sizeof(SnackNode));
	if (pFood == NULL)
	{
		perror("CreatFood::maalloc");
		return;
	}
	pFood->x = pos_x;
	pFood->y = pos_y;
	pFood->next = NULL;
	ps->_pfood = pFood;
}

7.实现贪吃蛇游戏的核心功能模块代码实现

cpp 复制代码
ps->_status = OK;
ps->_foodscore = 10;
ps->_score = 0;
ps->_sleep_time = 200;//单位是毫秒
ps->_dir = RIGHT;

sleep函数的头文件是<windows.h>

第三:游戏运行

1.显示帮助信息代码实现

cpp 复制代码
void PrintHelpInFo(pSnack ps)
{
	setPos(70, 15);
	printf("蛇头方向向左");
	setPos(70, 16);
	wprintf(L"用↑↓←→分别控制蛇的移动");
	setPos(70, 17);
	wprintf(L"用F3表示加速");
	setPos(70, 18);
	wprintf(L"用F4表示减速");
	setPos(70, 19);
	printf("不能穿墙,不能撞到自己");
	setPos(70, 20);
	printf("SPACE:暂停游戏");
	setPos(70, 21);
	printf("ESC:退出游戏");
}

2.输出总分与当前食物得分代码实现

cpp 复制代码
setPos(70, 10);
printf("总分数是:%2d", ps->_score);
setPos(70, 11);
printf("当前食物的分数是:%2d", ps->_foodscore);

获取按键情况

获取按键情况,GetAsyncKeyState将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态

cpp 复制代码
SHORT GetAsyncKeyState(
  [in] int vKey
);

GetAsyncKeyState 的返回值是short类型,在上⼀次调⽤ GetAsyncKeyState 函数后,如果 返回的16位的short数据中,最⾼位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬 起;如果最低位被置为1则说明,该按键被按过,否则为0。 如果我们要判断⼀个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1

cpp 复制代码
#define KEY_PRESS(VK)  ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )

虚拟键码(Winuser.h)-Win32apps

在当前贪吃蛇所需要的代码中,需要的虚拟按键的罗列:

  • 上:VK_UP
  • 下:VK_DOWN
  • 左:VK_LEFT
  • 右:VK_RIGHT
  • 空格:VK_SPACE
  • ESC:VK_ESCAPE
  • F3:VK_F3
  • F4:VK_F4

3.监听键盘输入代码实现

cpp 复制代码
#define KEY_PRESS(VK)  ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
if (KEY_PRESS(VK_UP) && ps->_dir != DOWN)
{
	//向上
	ps->_dir = UP;
}
else if (KEY_PRESS(VK_DOWN) && ps->_dir != UP)
{
	//向下
	ps->_dir = DOWN;
}
else if (KEY_PRESS(VK_LEFT) && ps->_dir != RIGHT)
{
	//向左
	ps->_dir = LEFT;
}
else if (KEY_PRESS(VK_RIGHT) && ps->_dir != LEFT)
{
	//向右
	ps->_dir = RIGHT;
}
else if (KEY_PRESS(VK_SPACE))
{
	//暂停
	Pause(ps);
}
else if (KEY_PRESS(VK_ESCAPE))
{
	//退出游戏
	ps->_status = EXIT;
}
else if (KEY_PRESS(VK_F3))
{
	//加速
	if (ps->_foodscore <= 20)
	{
		ps->_sleep_time = ps->_sleep_time - 20;
		ps->_foodscore = ps->_foodscore + 2;
	}
}
else if (KEY_PRESS(VK_F4))
{
	//减速
	if (ps->_foodscore >= 5)
	{
		ps->_sleep_time = ps->_sleep_time + 10;
		ps->_foodscore = ps->_foodscore - 1;
	}
}

请根据实际情况调整速度,我的数据仅供参考

根据游戏状态判断是否继续运行代码实现

cpp 复制代码
void SnakeMove(pSnack ps)
{
	//申请一个节点(用于记录下一步走的位置的节点)
	psnacknode pNext = (psnacknode)malloc(sizeof(SnackNode));
	if (pNext == NULL)
	{
		perror("SnakeMove::maalloc");
		return;
	}
	psnacknode cur = ps->_psnack;
	if (ps->_dir == UP)
	{
		pNext->x = cur->x;
		pNext->y = cur->y-1;
	}
	else if (ps->_dir == DOWN)
	{
		pNext->x = cur->x;
		pNext->y = cur->y+1;
	}
	else if (ps->_dir == LEFT)
	{
		pNext->x = cur->x-2;
		pNext->y = cur->y;
	}
	else if (ps->_dir == RIGHT)
	{
		pNext->x = cur->x+2;
		pNext->y = cur->y;
	}

	//更改蛇的状态
	KillBySelf(pNext, ps);
	KillByWall(pNext, ps);

	//判断下一个位置是否是食物的位置
	if (NextIsFood(pNext,ps))
	{
		EatFood(pNext,ps);
	}
	else
	{
		NoFood(pNext,ps);
	}
}

接下来我们将实现上述代码中的封装代码块

cpp 复制代码
//撞到自己
void KillBySelf(psnacknode pNext, pSnack ps)
{
	psnacknode cur = ps->_psnack;
	while (cur)
	{
		if (pNext->x == cur->x && pNext->y == cur->y)
//不能写成pNext==cur,pNext是一个新的不同于cur的地址,只能通过坐标判断
		{
			ps->_status = KILL_BY_SELF;
			return;
		}
		cur = cur->next;
	}
}
cpp 复制代码
//撞到墙
void KillByWall(psnacknode pNext, pSnack ps)
{
	if (pNext->x == 0 || pNext->x == 58 ||pNext->y == 0 || pNext->y == 29)
//这里根据你写的代码的实际情况判断墙的位置
	{
		ps->_status = KILL_BY_WALL;
		return;
	}
}
cpp 复制代码
//吃到食物
void EatFood(psnacknode pNext,pSnack ps)
{
	//将食物进行头插法
	ps->_pfood->next = ps->_psnack;
	ps->_psnack = ps->_pfood;

	//打印蛇身
	psnacknode cur = ps->_psnack;
	while (cur)
	{
		setPos(cur->x, cur->y);
		wprintf(L"●");
		cur = cur->next;
	}
	//释放食物所在节点
	free(pNext);
	pNext = NULL;

	//总分数改变,重新创造食物
	ps->_score = ps->_score + ps->_foodscore;
	CreatFood(ps);
}

//未吃到食物
void NoFood(psnacknode pNext, pSnack ps)
{
	//采用前插后删的方法
	pNext->next = ps->_psnack;
	ps->_psnack = pNext;

	//打印蛇
	psnacknode cur = ps->_psnack;
	while (cur->next->next)
	{
		setPos(cur->x, cur->y);
		wprintf(L"●");
		cur = cur->next;
	}
	setPos(cur->next->x, cur->next->y);
	printf("  ");//目的:为了掩盖之前蛇的打印

	//释放节点
	free(cur->next);//释放最后一个节点
	cur->next = NULL;//将倒数第二个节点的指针域设为空
}

第四:游戏结束

代码实现

cpp 复制代码
void GameEnd(pSnack ps)
{
	setPos(70, 5);
	switch (ps->_status)
	{
	case EXIT:
		printf("您主动退出游戏");
		break;
	case KILL_BY_SELF:
		printf("您撞到了自己,游戏结束");
		break;
	case KILL_BY_WALL:
		printf("您撞到了墙,退出游戏");
		break;
	}
	psnacknode cur = ps->_psnack;
	//释放蛇身
	while (cur)
	{
		cur = cur->next;
		free(ps->_psnack);
		ps->_psnack = cur;
	}
	ps->_psnack = NULL;
}

增强游戏互动体验

代码实现

在这里,由玩家自行决定是否继续新的一局游戏

cpp 复制代码
int main()
{
	setlocale(LC_ALL, "");//表示的是本地模式
	srand((unsigned int)time(NULL));//创建随机变量
	char ch = 0;
	do
	{
		//创建贪吃蛇
		Snack snack = { 0 };//此时Snack是一个结构体

		//初始化游戏
		GameStart(&snack);

		//运行游戏
		GameRun(&snack);

		//游戏的善后工作
		GameEnd(&snack);

		setPos(30, 15);
		printf("再来一局吗(Y/N):");
		ch=getchar();


	} while (ch == 'Y' || ch == 'y');
	return 0;
}

总结

经过对本次游戏开发项目的完整剖析与实践,我们不仅完成了一个功能完整的贪吃蛇游戏,更重要的是掌握了控制台游戏开发的核心思想和方法论。

🎯 核心收获总结

技术层面,我们系统性地学习了:

  • 游戏循环与状态机的构建

  • 实时键盘输入处理机制

  • 链表数据结构在动态游戏对象管理中的应用

  • Windows控制台API的实际运用

  • 模块化编程与代码组织技巧

思维层面,我们培养了:

  • 从需求到实现的系统性思考能力

  • 边界条件与异常处理的严谨性

  • 用户体验为导向的开发意识

  • 代码可维护性与扩展性的设计思维

💡 给学习者的建议

  1. 先模仿,后创新:完全理解现有代码后再尝试修改

  2. 小步快跑:每次只添加一个小功能,确保稳定运行

  3. 善用调试:学会使用调试工具观察程序运行状态

  4. 文档驱动:关键逻辑要写注释,便于回顾和分享

🚀 下一步学习方向

  • 深入学习图形库(如EasyX、SDL)

  • 研究游戏物理引擎基本原理

  • 了解简单的AI算法在游戏中的应用

  • 探索跨平台游戏开发框架


游戏开发的魅力在于创造。这个小小的控制台贪吃蛇,就像一颗种子,包含了游戏开发的所有基本要素。希望这个项目能成为你游戏开发之旅的起点,从这里出发,去创造更大、更精彩的世界。

编码不止,创造不息。愿每一位开发者都能在代码的世界中找到乐趣与成就感!


📌 项目完整源码及相关资源已整理至Gitee,欢迎交流学习。如果本文对你有帮助,别忘了点赞收藏哦!

Gitee链接:贪吃蛇原版/snack.c · 烟花落/data structure - 码云 - 开源中国

相关推荐
头发还没掉光光2 小时前
Linux 高级 IO 深度解析:从 IO 本质到 epoll全面讲解
linux·服务器·c语言·c++
晚霞的不甘2 小时前
Flutter for OpenHarmony专注与习惯的完美融合: 打造你的高效生活助手
前端·数据库·经验分享·flutter·前端框架·生活
kogorou0105-bit2 小时前
前端设计模式:发布订阅与依赖倒置的解耦之道
前端·设计模式·面试·状态模式
止观止2 小时前
像三元表达式一样写类型?深入理解 TS 条件类型与 `infer` 推断
前端·typescript
No0d1es2 小时前
电子学会青少年软件编程(C语言)等级考试试卷(一级)2025年12月
c语言·青少年编程·等级考试·电子学会·一级
爱编码的小八嘎2 小时前
C语言对话-18.我为你准备一切
c语言
雪芽蓝域zzs2 小时前
uniapp 省市区三级联动
前端·javascript·uni-app
Highcharts.js2 小时前
Next.js 集成 Highcharts 官网文档说明(2025 新版)
开发语言·前端·javascript·react.js·开发文档·next.js·highcharts
总爱写点小BUG2 小时前
探索 vu-icons:一款轻量级、跨平台的 Vue3 & UniApp SVG 图标库
前端·前端框架·组件库