C语言实战项目:贪吃蛇(2)

前言:

通过持续数月的C语言系统学习,我们已经掌握了包括指针操作、结构体使用、文件IO等核心编程能力。为了检验学习成果并提升实战经验,在本篇技术博客中,我将带领大家开发一个具有里程碑意义的经典游戏项目 -- 贪吃蛇。

我们将采用模块化开发方式,从游戏框架搭建开始,逐步实现蛇身移动、食物生成、碰撞检测等核心功能,最终完成一个可玩性强的完整游戏。

一、贪吃蛇游戏的设计

对于贪吃蛇游戏我们通过三个文件进行设计:

1.snake.h 文件 -用于函数的声明等

2.sanke.c 文件 -用于函数的实现

3.test.c 文件 -用于测试,且为程序的主入口

对于贪吃蛇游戏的逻辑设计,请参考上文贪吃蛇核心逻辑

贪吃蛇游戏演示效果:

贪吃蛇演示

二、贪吃蛇游戏核心数据

思维导图概括

2.1贪吃蛇节点的定义

代码示例:通过链表实现蛇节点

cpp 复制代码
//蛇节点的属性
typedef struct SnakeNode
{
	int x, y;
	struct SnakeNode* next;
}SnakeNode, * pSnakeNode;

代码分析:

1.定义整形变量int x ,int y 进行保存蛇节点的位置信息。

2.定义struct SnakeNode* next ,用于查找下一个节点

3.将结构体struct SnkaeNode 重命名为SnkaeNode ,将结构体指针struct SnkaeNode* 重命名为pSnakeNode

2.2贪吃蛇方向的定义

代码示例:通过枚举定义蛇的方向

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

2.3贪吃蛇状态的定义

代码示例:通过枚举定义蛇的状态

cpp 复制代码
//蛇的状态
//正常退出 撞墙 撞到自己 正常运行 暂停  初始状态
enum SnakeStatus
{
	Norm_Run = 1,
	KiLL_By_Self,
	KiLL_By_Wall,
	End_Norm,
	Exit,
	Start

};

2.4食物的属性

代码示例:通过结构体定义食物信息

cpp 复制代码
//食物的属性
typedef struct SnakeFood
{
	//食物的坐标信息
	int x, y;

	//当前食物的分数
	int foodscore;

	//食物的总成绩
	int totalscore;

}SnakeFood, * pSnakeFood;

代码详解:

1.通过定义整形变量 int x, y 记录食物的坐标信息

2.通过定义整形变量 int foodscore 记录当前食物的分数

3.通过定义整形变量 int totalscore 记录食物的总成绩

4.将struct SnakeFood 重命名为SnakeFood ,将结构体指针struct SnakeFood * 重命名为pSnakeFood

2.5贪吃蛇信息的定义(核心)

代码示例:通过结构体定义蛇的信息

cpp 复制代码
//蛇的信息
typedef struct SnakeInformation
{
	//定义维护头节点的指针
	pSnakeNode _phead;

	//定义指向食物的指针
	pSnakeFood _pFood;

	//蛇的方向-通过枚举定义
	enum SnakeDirection _dir;

	//蛇的状态
	enum SnakeStatus _status;

	//蛇的速度,通过休眠时间控制
	int _speed;

	int vel_grade;
}SnakeInfo, * pSnakeInfo;

代码详解:

1.定义一个维护头节点的指针 pSnakeNode _phead;

2.定义一个指向食物的指针 pSnakeFood _pFood;

3.通过枚举定义蛇的方向 enum SnakeDirection _dir;

4.通过枚举定义蛇的状态 enum SnakeStatus _status;

5.通过整形变量定义蛇的速度 int _speed;

6.通过整形变量定义蛇速度的等级 int vel_grade;

7.将结构体struct SnakeInformation重命名为SnakeInfo ,将结构体指针struct SnakeInformation * 重命名为pSnakeInfo

温馨提示:这个结构体设计使得游戏逻辑清晰,易于扩展和维护蛇的各种行为状态。

2.6定义蛇、食物和墙体的形状

cpp 复制代码
#define WALL L'□'

#define BODY L'●'

#define FOOD L'★'

三、贪吃蛇游戏初始化

思维导图概括

3.1GameInit函数的声明

cpp 复制代码
void GameInit()
{
	//设置控制台属性
	SetProperty();

	//欢迎界面
	WelcomeToGame();

}

3.2GameInit函数的实现

3.2.1SetPos函数的实现

cpp 复制代码
void SetPos(short x, short y)
{
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);

	COORD pos = { x, y };

	SetConsoleCursorPosition(houtput, pos);
}

通过封装一个SetPos函数,定义坐标位置 ,对于不太了解win32API的可以看一下前文贪吃蛇前言

3.2.2SetProperty函数的实现

cpp 复制代码
void SetProperty()
{
	setlocale(LC_ALL, "");

	//设置窗口的大小
	system("mode con cols=100 lines=30");

	//设置窗口的名称
	system("title 贪吃蛇");

	//获得控制台窗口,进行使用
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);

	//定义储存控制台光标信息的结构体
	CONSOLE_CURSOR_INFO cursor_info = { 0 };

	//获得与houtput句柄相关的控制台光标的信息
	GetConsoleCursorInfo(houtput, &cursor_info);

	//修改光标是否可见
	cursor_info.bVisible = false;

	//设置光标大小和光标可见度的函数
	SetConsoleCursorInfo(houtput, &cursor_info);
}

本段代码:对控制窗口进行设置

1.进行本地化处理。

2.对控制台进行设置大小。

3.对控制台窗口进行重命名。

4.隐藏控制台上的光标 。

3.2.3WelcomeToGame函数的实现

cpp 复制代码
void WelcomeToGame()
{
	SetPos(36, 12);
	wprintf(L"欢迎来到贪吃蛇小游戏\n");

	SetPos(36, 16);
	system("pause");

	system("cls");
	SetPos(30, 10);
	wprintf(L"用↑.↓.←.→分别控制蛇的移动\n");

	SetPos(30, 14);
	wprintf(L"按F3进行加速,F4进行减速,加速能够得到更高的分数\n");

	SetPos(30, 20);
	system("pause");
	system("cls");
}

本段代码:打印贪吃蛇游戏的两个界面

1.第一个界面,通过宽字符打印 " 欢迎来到贪吃蛇小游戏 " 的提示信息。

并通过system("pause")进行暂停,实现了按任意键继续,跳过该界面到下一个界面

2.第二个界面,通过宽字符打印 "游戏移动" 的提示信息。

并通过system("pause")进行暂停,实现了按任意键继续,跳过该界面到下一个界面

四、贪吃蛇游戏启动

思维导图概括

4.1GameStart函数的声明

cpp 复制代码
void GameStart(pSnakeInfo psnake)//psnake 指向了主调函数创建的蛇信息
{
	//地图的打印
	CreateMap();

	//初始化蛇的身体
	InitSnake(psnake);

	//创建食物
	CreateFood(psnake);

	PrintHelpInfo();
}

4.2GameStart函数的实现

4.2.1CreateMap函数的实现

地图如图所示:对于一个宽字符而言"□",横坐标的值x与纵坐标的值y大概为2:1的关系,所以对于这个58*27的矩形方格而言,x轴可以放29个'□' ,而对于纵轴y轴而言可以放27个'□'。

cpp 复制代码
void CreateMap()
{
	SetPos(0, 0);
	for (int i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}

	SetPos(0, 26);
	for (int i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}

	for (int i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc\n", WALL);
	}

	for (int i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc\n", WALL);
	}
}

代码详解:本段代码为对墙体打印

1.通过SetPos定位到(0,0),通过循环打印墙体的顶部。

2.通过SetPos定位到(0,26),通过循环打印墙体的底部。

3.通过循环不断调整SetPos(0,i)定位,打印墙体的左面。

4..通过循环不断调整SetPos(56,i)定位,打印墙体的右面

4.2.2SetSnakeNode函数的实现

本段代码涉及到链表相关知识,如果不了解链表的知识可以移步看博主写的单链表详解

cpp 复制代码
SnakeNode* SetSnakeNode()
{
	SnakeNode* newnode = (SnakeNode*)malloc(sizeof(SnakeNode));
	if (newnode == NULL)
	{
		perror("SetSnakeNode fail");
	}
	return newnode;
}

4.2.3SnakePushFront函数的实现

本段代码涉及到链表相关知识,如果不了解链表的知识可以移步看博主写的单链表详解****

cpp 复制代码
void SnakePushFront(SnakeNode** pphead)
{
	//头节点的地址不能为空
	assert(pphead);
	SnakeNode* newnode = SetSnakeNode();

	newnode->next = *pphead;
	*pphead = newnode;
}

4.2.4InitSnake函数的实现

cpp 复制代码
#define POS_X 24
#define POS_Y 5

void InitSnake(pSnakeInfo psnake)
{
	//默认蛇身有五个节点
	psnake->_phead = NULL;

	//头插五个节点
	for (int i = 0; i < 5; i++)
	{
		SnakePushFront(&psnake->_phead);
		psnake->_phead->x = POS_X + i * 2;
		psnake->_phead->y = POS_Y;
	}

	pSnakeNode pcur = psnake->_phead;

	while (pcur)
	{
		SetPos(pcur->x, pcur->y);
		wprintf(L"%lc", BODY);
		pcur = pcur->next;
	}

}

代码详解:

1.定义蛇的起始位置POS_X 和 POS_Y

2.通过for循环,为贪吃蛇初始化5个节点

3.通过while循环遍历蛇的节点,打印贪吃蛇的形状。

代码演示:

4.2.5CreateFood函数的实现

cpp 复制代码
void CreateFood(pSnakeInfo psnake)
{
	//1.保证食物随机出现
	//2.保证食物在有效的位置
	int x = 0, y = 0;
again:

	do
	{
		x = rand() % 52 + 2;
		y = rand() % 24 + 1;
	} while (x % 2 != 0);

	psnake->_pFood->x = x;
	psnake->_pFood->y = y;


	//获得当前头节点
	pSnakeNode pcur = psnake->_phead;

	//遍历头节点确保,食物的位置不与蛇身重合
	while (pcur)
	{

		if (psnake->_pFood->x == pcur->x && psnake->_pFood->y == pcur->y)
		{
			goto again;
		}

		pcur = pcur->next;
	}

	SetPos(psnake->_pFood->x, psnake->_pFood->y);
	wprintf(L"%lc", FOOD);
}

代码详解:

1.通过rand()函数生成随机数,保证了食物坐标的随机生成。

2.通过while循环遍历整个贪吃蛇的节点,确保食物的位置不与蛇身重合。

3.通过坐标设置,打印食物的位置

温馨提示:食物的横坐标必须为2的倍数,因为对于宽字符而言,横坐标要为2个单位长度,如果出现奇数坐标,就会出现食物在墙体中。

代码演示:

4.2.6PrintHelpInfo函数的实现

为了提示用户相关游戏信息,我们在控制台的右边部分提供信息,提醒用户游戏规则和打印游戏提示。

cpp 复制代码
void PrintHelpInfo()
{
	SetPos(70, 4);
	wprintf(L"温馨提示:\n");
	SetPos(64, 8);
	wprintf(L"不能咬到自己!不能撞到墙壁!\n");
	SetPos(64, 10);
	wprintf(L"用↑ ↓ ← →分别控制蛇的移动\n");
	SetPos(64, 12);
	wprintf(L"按F3进行加速 按F4进行减速\n");
	SetPos(64, 14);
	wprintf(L"按ESC退出游戏 按空格暂停游戏\n");

}

代码示例:

五、贪吃蛇游戏属性设置

cpp 复制代码
void GameSetInfo(pSnakeInfo psnake)
{
    //默认方向向右
    psnake->_dir = RIGHT;
    psnake->_pFood->foodscore = 10;
    psnake->_pFood->totalscore = 0;
    psnake->_speed = 200;
    psnake->_status = Start;
    psnake->vel_grade = 0;

}

代码详解:

1.设置贪吃蛇的默认方向为右

2.设置初始食物分数值为10,食物总分数为0

3.设置蛇的初始速度为200,通过Sleep函数进行调整,初始速度等级为0

4.初始状态设置为Star。

六、贪吃蛇游戏运行

思维导图概括

6.1GameRun函数的声明

cpp 复制代码
void GameRun(pSnakeInfo psnake)
{
	//防止按任意键时,因为ESC而提前退出程序
	CheckKeyboard(psnake);
	psnake->_status = Norm_Run;
	do
	{
		//打印当前分数和游戏等级
		PrintScore(psnake);

		//检测按键
		CheckKeyboard(psnake);

		//输出当前运行状态
		PrintSnakeStatus(psnake);
		
		//蛇走一步的过程
		SnakeMove(psnake);

		Sleep(psnake->_speed);

		//判断蛇是否撞到墙
		KillByWall(psnake);
		
		//判断蛇是否撞到自己
		KillBySelf(psnake);

	} while (psnake->_status == Norm_Run || psnake->_status==Exit);

}

代码解析:

1.在整体逻辑上,采用do-while循环,根据贪吃蛇的状态判定是否结束运行,如果蛇的状态为Norm_Run 或 Exit 正常运行循环,否则退出循环。

2.在进行按键判定时,防止在按任意键继续的时候,因为提前按Esc键,贪吃蛇的状态被设置为Norm_End而退出,所以我们先调用一次,再将状态设置为NORM_Run。

6.2GameRun函数的实现

6.2.1PrintScore函数的实现

cpp 复制代码
void PrintScore(pSnakeInfo psnake)
{
	SetPos(64, 18);
	printf("当前食物的分数:%2d", psnake->_pFood->foodscore);

	SetPos(64, 20);
	printf("当前的总分数:%2d", psnake->_pFood->totalscore);

	SetPos(64, 24);
	printf("当前速度等级:%2d", psnake->vel_grade);
}

代码演示:

6.2.2PrintSnakeStatus函数的实现

cpp 复制代码
void PrintSnakeStatus(pSnakeInfo psnake)
{
	SetPos(64, 26);
	if (psnake->_status == Exit)
	{
		printf("当前游戏状态:游戏暂停");
	}
	else if (psnake->_status == Norm_Run)
	{
		printf("当前游戏状态:游戏正常");
	}
}

代码演示:

6.2.3CheckKeyboard函数的实现

cpp 复制代码
void CheckKeyboard(pSnakeInfo psnake)
{
	//检测向上按键时,对蛇向下走不做出反应
	if (KEY_PRESS(VK_UP) && psnake->_dir != DOWN)
	{
		psnake->_dir = UP;
	}
	//检测向下按键时,对蛇向上走不做出反应
	else if (KEY_PRESS(VK_DOWN) && psnake->_dir != UP)
	{
		psnake->_dir = DOWN;
	}
	//检测向左按键时,对蛇向右走不做出反应
	else if (KEY_PRESS(VK_LEFT) && psnake->_dir != RIGHT)
	{
		psnake->_dir = LEFT;
	}
	//检测向右按键时,对蛇向左走不做出反应
	else if (KEY_PRESS(VK_RIGHT) && psnake->_dir != LEFT)
	{
		psnake->_dir = RIGHT;
	}
	//检测到空格
	else if (KEY_PRESS(VK_SPACE))
	{
		psnake->_status = Exit;

		//进行暂停
		ExitMove(psnake);

		//在暂停的时候按下ESC键,直接返回,避免后续状态修改
		if (psnake->_status == End_Norm)
		{
			return;
		}
		//结束暂停
		psnake->_status = Norm_Run;
	}
	//检测到ESC
	else if (KEY_PRESS(VK_ESCAPE) )
	{		
		//正常退出
		psnake->_status = End_Norm;
		return;
	}
	//检测到F3按键
	else if (KEY_PRESS(VK_F3))
	{
		//进行加速,增加食物的分数
		//设置加速四档速度
		if (psnake->_speed > 80)
		{
			psnake->_speed -= 30;
			psnake->_pFood->foodscore += 2;
			psnake->vel_grade++;
		}
	}
	//检测到F4按键
	else if (KEY_PRESS(VK_F4))
	{
		//进行减速,减少食物的分数
		//进行减速四档
		if (psnake->_speed < 320)
		{
			psnake->_speed += 30;
			psnake->_pFood->foodscore -= 2;
			psnake->vel_grade--;
		}
	}
}

6.2.4SnakeMove函数的实现

cpp 复制代码
//蛇的移动
void SnakeMove(pSnakeInfo psnake)
{
	if (psnake->_status == End_Norm) return;
	//蛇即将到达的下一个节点
	pSnakeNode pnextnode = (pSnakeNode)malloc(sizeof(SnakeNode));

	if (pnextnode == NULL)
	{
		perror("pnextnode fail");
		return;
	}

	switch (psnake->_dir)
	{
	case UP:
		pnextnode->x = psnake->_phead->x;
		pnextnode->y = psnake->_phead->y - 1;
		break;
	case DOWN:
		pnextnode->x = psnake->_phead->x;
		pnextnode->y = psnake->_phead->y + 1;
		break;
	case LEFT:
		pnextnode->x = psnake->_phead->x - 2;
		pnextnode->y = psnake->_phead->y;
		break;
	case RIGHT:
		pnextnode->x = psnake->_phead->x + 2;
		pnextnode->y = psnake->_phead->y;
		break;
	}

	//对蛇即将到达的下一个节点进行判断
	if (NextIsFood(psnake, pnextnode))
	{
		//头插下一个节点
		EatFood(psnake, pnextnode);
	}
	else
	{
		//头插下一个节点,并删除尾节点
		NoEatFood(psnake, pnextnode);
	}
}

6.2.5 NextIsFood函数的实现

cpp 复制代码
int NextIsFood(pSnakeInfo psnake, pSnakeNode pnextnode)
{
	return (psnake->_pFood->x == pnextnode->x && psnake->_pFood->y == pnextnode->y);
}

6.2.6EatFood函数实现

cpp 复制代码
void EatFood(pSnakeInfo psnake, pSnakeNode pnextnode)
{
	pnextnode->next = psnake->_phead;
	psnake->_phead = pnextnode;

	pSnakeNode pcur = psnake->_phead;
	while (pcur)
	{
		SetPos(pcur->x, pcur->y);
		wprintf(L"%lc", BODY);
		pcur = pcur->next;
	}

	psnake->_pFood->totalscore += psnake->_pFood->foodscore;
	CreateFood(psnake);
}

6.2.7NoEatFood函数实现

cpp 复制代码
void NoEatFood(pSnakeInfo psnake, pSnakeNode pnextnode)
{
	pnextnode->next = psnake->_phead;
	psnake->_phead = pnextnode;

	pSnakeNode pcur = psnake->_phead;
	pSnakeNode prev = psnake->_phead;
	while (pcur->next!=NULL)
	{
		SetPos(pcur->x, pcur->y);
		wprintf(L"%lc", BODY);
		prev = pcur;
		pcur = pcur->next;
	}
	SetPos(pcur->x, pcur->y);
	printf("  ");
	prev->next = NULL;
	free(pcur);
	pcur = NULL;
}

6.2.8KillByWall函数的实现

cpp 复制代码
void KillByWall(pSnakeInfo psnake)
{
	//判断蛇头节点的横纵坐标是否在墙体内
	if (psnake->_phead->x == 0 || psnake->_phead->x == 56 || psnake->_phead->y==0 || psnake->_phead->y==26)
	{
		psnake->_status = KiLL_By_Wall;
	}
}

6.2.9KillBySelf函数的实现

cpp 复制代码
void KillBySelf(pSnakeInfo psnake)
{
	pSnakeNode pcur = psnake->_phead->next;

	int headX = psnake->_phead->x;
	int headY = psnake->_phead->y;

	while (pcur)
	{
		if (headX == pcur->x && headY == pcur->y)
		{
			psnake->_status = KiLL_By_Self;
			return ;
		}
		pcur = pcur->next;
	}
}

七、贪吃蛇游戏结束

7.1GameEnd函数的声明

cpp 复制代码
void GameEnd(pSnakeInfo psnake)
{
	//释放链表
	DestroySnake(psnake);
}

7.2GameEnd函数的实现

7.2.1DestroySnake函数的实现

cpp 复制代码
//释放链表
void DestroySnake(pSnakeInfo psnake)
{
	assert(psnake);
	pSnakeNode pcur = psnake->_phead;
	while (pcur)
	{
		pSnakeNode tmp = pcur->next;
		free(pcur);
		pcur = tmp;
	}

}

八、贪吃蛇游戏交互设计

8.1清屏函数设计

cpp 复制代码
// 底层函数:强制清空整个屏幕缓冲区(替代system("cls"),无缓存)
void ForceClearScreen()
{
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(hOutput, &csbi); // 获取屏幕缓冲区信息

    // 计算屏幕总字符数(宽×高)
    DWORD dwConsoleSize = csbi.dwSize.X * csbi.dwSize.Y;
    COORD coordZero = { 0, 0 }; // 起点坐标(0,0)
    DWORD dwCharsWritten;

    // 1. 用空格填充整个缓冲区(覆盖所有旧内容)
    FillConsoleOutputCharacter
    (
        hOutput,        // 输出句柄
        L' ',           // 填充字符(空格)
        dwConsoleSize,  // 填充数量(整个屏幕)
        coordZero,      // 起点
        &dwCharsWritten // 实际填充数(忽略)
    );

    // 2. 重置光标到左上角(避免光标在旧位置残留)
    SetConsoleCursorPosition(hOutput, coordZero);
}

8.2清空缓冲区设计

cpp 复制代码
// 底层函数:彻底清空输入缓冲区(删除所有堆积的按键)
void ClearInputBuffer()
{
    HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
    FlushConsoleInputBuffer(hInput); // 清空输入队列,无任何残留
}

8.3游戏重开设计

cpp 复制代码
void GameTest()
{
    char user_choice = 0;
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO cursor = { 0 };
    cursor.dwSize = 10; // 光标大小(1-100)

    do
    {
        // 1. 新一局初始化:强制清屏+清空输入缓存(关键!)
        ForceClearScreen();
        ClearInputBuffer(); // 删除上一局可能堆积的按键(如方向键、F3)

        // 2. 初始化游戏数据(原有逻辑不变)
        SnakeInfo snake = { 0 };
        SnakeFood food = { 0 };
        snake._pFood = &food;

        // 3. 启动游戏流程(原有逻辑不变)
        GameInit();
        GameStart(&snake);
        GameSetInfo(&snake);
        GameRun(&snake);
        GameEnd(&snake);

        getchar();
        // 4. 游戏结束:询问重新开始(底层强制清空+极简流程)
        ForceClearScreen(); // 强制清空游戏画面,无任何残留
        ClearInputBuffer(); // 清空游戏过程中堆积的按键

        // 4.1 显示"Game Over"(固定位置,基于空白屏幕)
        SetPos(38, 12);
        wprintf(L"Game Over!");

        // 4.2 显示询问提示(基于空白屏幕,无任何旧内容)
        SetPos(36, 16);
        wprintf(L"Try Again?(Y/N):");

        // 4.3 显示光标,读取输入(无任何旧按键干扰)
        cursor.bVisible = true;
        SetConsoleCursorInfo(hOutput, &cursor);
        SetPos(53, 16); // 光标定位到提示后

        // 4.4 读取用户输入(此时输入缓冲区已清空,只读取新输入)
        user_choice = getchar();
        // 清理本次输入的回车符(避免影响下一次)
        while (getchar() != '\n');

        // 4.5 隐藏光标,准备下一轮
        cursor.bVisible = false;
        SetConsoleCursorInfo(hOutput, &cursor);

    } while (user_choice == 'Y' || user_choice == 'y');

    // 程序结束:强制清屏+释放资源
    ForceClearScreen();
    CloseHandle(hOutput);
}

既然看到这里了,不妨点赞+收藏,感谢大家,若有问题请指正。

相关推荐
轩辰q2 小时前
python异步编程
开发语言·python
郝学胜-神的一滴2 小时前
现代C++ Lambda表达式:最佳实践、深入理解和资源推荐
开发语言·c++·程序人生·软件工程
一口面条一口蒜3 小时前
R语言中的S3 泛型与方法
开发语言·r语言
_OP_CHEN3 小时前
C++基础:(五)类和对象(下)—— static、友元和内部类
开发语言·c++·构造函数·static成员·友元·匿名对象·编译器优化
徐归阳3 小时前
第三十七天:2025 图形绘制
算法
yongui478343 小时前
基于MATLAB的8QAM调制解调仿真与BER性能分析
开发语言·matlab
weixin_429630263 小时前
机器学习-第三章 线性模型
人工智能·算法·机器学习
jianqiang.xue3 小时前
ESP32-S3入门第七天:UART串口通信与设备交互
c语言·单片机·嵌入式硬件·mcu·物联网·51单片机
早日退休!!!4 小时前
C 内存布局
c语言·开发语言