C语言从零实现贪吃蛇小游戏

制作不易,点赞关注一下呗!!!

文章目录

  • 前言
  • 一. 技术要点
  • 二、WIN32API介绍
  • 三、贪吃蛇游戏设计与分析 
  •       1.游戏开始前的初始化
  •       2.游戏运行的逻辑 
  • 总结


前言

当我们掌握链表这样的数据结构之后,我们就可以用它来做一些小项目,比如童年小游戏贪吃蛇

目标:在Windows环境中控制台上使用C语言模拟实现经典小游戏贪吃蛇


一.技术要点

C语言函数,枚举,结构体,动态内存管理,预处理指令,链表,Win32API等。

二.Win32API介绍

1.什么是Win32API

Win32 API是微软的操作系统Windows提供给开发人员的编程接口,它决定了我们开发的Windows应用程序的能力。

使用Win32 API,应用程序可以充分挖掘Windows的32位操作系统的潜力。 Mircrosoft的所有32位平台都支持统一的API,包括函数、结构、消息、宏及接口。使用 Win32 API不但可以开发出在各种平台上都能成功运行的应用程序,而且也可以充分利用每个平台特有的功能和属性。

2.控制台程序(Console)

我们平时运行起来出现的黑框框就是控制台。

我们可以通过mode命令来设置窗口大小。

例如:设置为30行,100列

mode con cols=100 lines=30 

在VS上我们可以借助system函数(头文件<windows.h>)来完成这样的命令 

 

 我们也可以通过title命令来修改控制台窗口的名称

title 贪吃蛇

 

3.控制台屏幕上的坐标 COORD

COORD是Win32API中定义的一个结构体,表示一个字符在屏幕缓冲区上的坐标,坐标为(0,0)的原点位于缓冲区的顶部最左侧单元格

typedef struct _COORD {

SHORT X; // horizontal coordinate

SHORT Y; // vertical coordinate

} COORD;

4.GetStdHandle 

GetStdHandle 是Win32API的一个函数,它用于从特定的标准设备(标准输入,标准输出,标准错误)中获取一个句柄(用于标识不同设备的数值),使用这个句柄可以操作设备。

语法

HANDLE GetStdHandle( DWORD nStdHandle );

 参数有三种取值

STD_INPUT_HANDLE

标准输入的句柄

STD_OUTPUT_HANDLE

标准输出的句柄

STD_ERROR_HANDLE

标准错误的句柄

实例:

 

 

5.GetConsoleCursorInfo

功能:检索有关指定控制台光标的大小和可见性

 BOOL WINAPI GetConsoleCursorInfo(
   HANDLE               hConsoleOutput,
   PCONSOLE_CURSOR_INFO  lpConsoleCursorInfo
);

  PCONSOLE_CURSOR_INFO是指向 CONSOLE_CURSOR_INFO这个结构体的指针,该结构接收主机光标的信息。

 

6.SetConsoleCursorInfo 

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

BOOL WINAPI SetConsoleCursorInfo(
  _In_       HANDLE              hConsoleOutput,
  _In_ const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
);

一般都是配合 GetConsoleCursorInfo函数使用,先用GetConsoleCursorInfo函数获取当前光标信息,再自己手动修改光标信息,最后用SetConsoleCursorInfo 函数设置进去!!!

 

 7.GetAsyncKeyState 

GetAsyncKeyState是一个用来判断函数调用时指定虚拟键的状态,确定用户当前是否按下了键盘上的一个键的函数。

返回类型为short类型,如果返回的16位short类型数据中最高位为1,则表明该键被按下,最高位为0则表示该键抬起,如果最低位为1表示该键被按过,否则为0.

函数名返回值类型备注
GetAsyncKeyStateSHORT用来判断函数调用时指定虚拟键的状态
参数类型说明
vKeyint欲测试的虚拟键的键码

每个键都对应一个虚拟键值,可以自行查找。

8.SetConsoleCursorPosition

有时我们可能不想让字符打印从(0,0)坐标处开始打印,这时就需要用这个函数来设置坐标

使用这个函数需要两个参数:第一个参数类型为HANDLE,第二个参数类型为COORD

实例:

 

三.贪吃蛇游戏设计与分析 

1.游戏开始前的初始化

数据结构的设计:

enum GameStatus
{OK,ESC,KILL_BYWALL,KILL_BYSELF,
};
enum DIRECTION
{LEFT,RIGHT,UP,DOWN,
};
//蛇身节点
typedef struct SnakeNode
{int x;int y;struct SnakeNode* next;
}SnakeNode,*pSnakeNode;//整条蛇
typedef struct Snake
{pSnakeNode pSnake;pSnakeNode pFood;//指向食物的指针int Score;//当前累计分数int FoodWeight;//一个食物的分数int SleepTime;//休眠时间,时间越短,速度越快enum GameStatus Status;enum DIRECTION dir;
}Snake,*pSnake;

 

 

接下来打印欢迎信息 ,这里我们单独分装两个函数,一个用来设置光标位置,另一个用来打印欢迎信息:

 

下一步:创建地图

 #define WALL L'□'
void CreateMap()
{//上SetPos(0, 0);int i = 0;for (i = 0; i < 69; i += 2){wprintf(L"%lc", WALL);}//下SetPos(0,34);for (i = 0; i < 69; i += 2){wprintf(L"%lc", WALL);}//左for (i = 0; i < 34; i++){SetPos(0, i);wprintf(L"%lc", WALL);}//右for (i = 0; i < 34; i++){SetPos(68, i);wprintf(L"%lc", WALL);}
}

 

再下一步:初始化蛇

void InitSnake(pSnake ps)
{pSnakeNode cur = NULL;//创建5个蛇身节点for (int i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("createsnake malloc");exit(1);}cur->x = 32 + 2 * i;cur->y = 7;cur->next = NULL;if (ps->pSnake == NULL){ps->pSnake = cur;}else{cur->next = ps->pSnake;ps->pSnake = cur;}}//打印蛇身cur = ps->pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//贪吃蛇其他信息初始化ps->dir = RIGHT;ps->FoodWeight = 10;ps->pFood = NULL;ps->Score = 0;ps->SleepTime = 200;//200毫秒ps->Status = OK;
}

最后:创建食物 

void CreateFood(pSnake ps)
{int x = 0;int y = 0;again:do {x = rand() % 66 + 2;y = rand() % 33 + 1;} while (x % 2 != 0);pSnakeNode cur = ps->pSnake;while (cur){if (x == cur->x && y == cur->y){goto again;}cur = cur->next;}pSnakeNode food = (pSnakeNode)malloc(sizeof(pSnake));if (!food){perror("createfood malloc ");exit(1);}food->x = x;food->y = y;ps->pFood = food;SetPos(x, y);wprintf(L"%lc", FOOD);
}

 

最后将这些函数放在GameStart函数中,一起完成游戏开始前的工作 

 

2.游戏运行的逻辑 

第一步:打印帮助信息

 

 第二步:循环检测按键状态

 

 

3.游戏结束的善后 

 


总结

所有代码放在这里:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<locale.h>
#include<string.h>
#include<stdbool.h>
#include<windows.h>
#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'
#define KEY_PRESS(vk)  ((GetAsyncKeyState(vk) & 0x1)? 1: 0)enum GameStatus
{OK,ESC,KILL_BYWALL,KILL_BYSELF,
};
enum DIRECTION
{LEFT,RIGHT,UP,DOWN,
};
//蛇身节点
typedef struct SnakeNode
{int x;int y;struct SnakeNode* next;
}SnakeNode,*pSnakeNode;//整条蛇
typedef struct Snake
{pSnakeNode pSnake;pSnakeNode pFood;//指向食物的指针int Score;//当前累计分数int FoodWeight;//一个食物的分数int SleepTime;//休眠时间,时间越短,速度越快enum GameStatus Status;enum DIRECTION dir;
}Snake,*pSnake;void SetPos(int x, int y);void GameStart(pSnake snake);void Welcome();void CreateMap();void InitSnake(pSnake ps);void CreateFood(pSnake ps);void printhelpinfo();//游戏运行的逻辑
void GameRun(pSnake ps);
void pause();void SnakeMove(pSnake ps);
int IsFood(pSnake ps, pSnakeNode next);
void EatFood(pSnake ps, pSnakeNode next);
void NotEatFood(pSnake ps,pSnakeNode next);void KillByWall(pSnake ps);
void KillBySelf(pSnake ps);void GameEnd(pSnake ps);#include"snake.h"
void SetPos(int x, int y)
{HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);COORD pos = { x,y };SetConsoleCursorPosition(handle, pos);
}
void Welcome()
{//打印欢迎信息SetPos(48, 15);printf("欢迎来到贪吃蛇小游戏\n");SetPos(50,35);system("pause");system("cls");//打印操作信息SetPos(35, 20);printf("用↑. ↓. ←. →来控制蛇的移动,F3是加速,F4是减速\n");SetPos(48, 22);printf("加速能获得更多分数\n");SetPos(50, 35);system("pause");system("cls");
}void CreateMap()
{//上SetPos(0, 0);int i = 0;for (i = 0; i < 69; i += 2){wprintf(L"%lc", WALL);}//下SetPos(0,34);for (i = 0; i < 69; i += 2){wprintf(L"%lc", WALL);}//左for (i = 0; i < 34; i++){SetPos(0, i);wprintf(L"%lc", WALL);}//右for (i = 0; i < 34; i++){SetPos(68, i);wprintf(L"%lc", WALL);}
}void InitSnake(pSnake ps)
{pSnakeNode cur = NULL;//创建5个蛇身节点for (int i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("createsnake malloc");exit(1);}cur->x = 32 + 2 * i;cur->y = 7;cur->next = NULL;if (ps->pSnake == NULL){ps->pSnake = cur;}else{cur->next = ps->pSnake;ps->pSnake = cur;}}//打印蛇身cur = ps->pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//贪吃蛇其他信息初始化ps->dir = RIGHT;ps->FoodWeight = 10;ps->pFood = NULL;ps->Score = 0;ps->SleepTime = 200;//200毫秒ps->Status = OK;
}void CreateFood(pSnake ps)
{int x = 0;int y = 0;again:do {x = rand() % 66 + 2;y = rand() % 33 + 1;} while (x % 2 != 0);pSnakeNode cur = ps->pSnake;while (cur){if (x == cur->x && y == cur->y){goto again;}cur = cur->next;}pSnakeNode food = (pSnakeNode)malloc(sizeof(pSnake));if (!food){perror("createfood malloc ");exit(1);}food->x = x;food->y = y;ps->pFood = food;SetPos(x, y);wprintf(L"%lc", FOOD);
}void GameStart(pSnake ps)
{//修改控制台信息system("mode con cols=120 lines=40");system("title 贪吃蛇");//隐藏光标HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO cursorinfo;GetConsoleCursorInfo(handle, &cursorinfo);cursorinfo.bVisible = false;SetConsoleCursorInfo(handle, &cursorinfo);//打印欢迎信息Welcome();//绘制地图CreateMap();//初始化蛇InitSnake(ps);//创建食物CreateFood(ps);}void printhelpinfo()
{SetPos(80, 18);printf("不能穿墙,不能咬到自己\n");SetPos(80, 19);printf("用↑ . ↓ . ← . →来控制蛇的移动\n");SetPos(80, 20);printf("F3是加速,F4是减速\n");
}void pause()
{while (1){Sleep(100);if (KEY_PRESS(VK_SPACE)){break;}}
}int IsFood(pSnake ps,pSnakeNode next)
{if (ps->pFood->x == next->x && ps->pFood->y == next->y){return 1;//是食物}elsereturn 0;
} void EatFood(pSnake ps, pSnakeNode next)
{next->next = ps->pSnake;ps->pSnake = next;//打印蛇身pSnakeNode cur = ps->pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}ps->Score += ps->FoodWeight;//释放旧食物free(ps->pFood);ps->pFood = NULL;//创建新食物CreateFood(ps);
}void NotEatFood(pSnake ps, pSnakeNode next)
{//头插法插入next->next = ps->pSnake;ps->pSnake = next;//释放尾节点pSnakeNode cur = ps->pSnake;while (cur->next->next){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//将尾节点的位置打印成空白字符SetPos(cur->next->x, cur->next->y);printf("  ");free(cur->next);cur->next = NULL;}void SnakeMove(pSnake ps)
{pSnakeNode pnext = (pSnakeNode)malloc(sizeof(SnakeNode));if (pnext == NULL){perror("snakemove malloc");exit(1);}pnext->next = NULL;switch (ps->dir){case UP:pnext->x = ps->pSnake->x;pnext->y = ps->pSnake->y-1;break;case DOWN:pnext->x = ps->pSnake->x;pnext->y = ps->pSnake->y + 1;break; case LEFT:pnext->x = ps->pSnake->x-2;pnext->y = ps->pSnake->y;break;case RIGHT :pnext->x = ps->pSnake->x+2;pnext->y = ps->pSnake->y;break;}//下一个坐标是否是食物if (IsFood(ps, pnext)){//是食物 EatFood(ps, pnext);}else{//不是食物NotEatFood(ps,pnext);}
}void KillByWall(pSnake ps)
{if (ps->pSnake->x == 0 || ps->pSnake->x == 68 || ps->pSnake->y == 0 || ps->pSnake->y == 33){ps->Status = KILL_BYWALL;}}void KillBySelf(pSnake ps)
{pSnakeNode cur = ps->pSnake->next;while (cur){if (cur->x == ps->pSnake->x && cur->y == ps->pSnake->y){ps->Status = KILL_BYSELF;return;}cur=cur->next;}
}//游戏运行的逻辑
void GameRun(pSnake ps)
{//打印帮助信息printhelpinfo();do{//打印当前分数SetPos(80, 13);printf("总分:%d\n", ps->Score);SetPos(80, 14);printf("食物的分值:%02d\n", ps->FoodWeight);//检测按键//上下左右,空格,F3,F4, ESCif (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_ESCAPE)){ps->Status = ESC;break;}else if (KEY_PRESS(VK_SPACE)){//暂停和恢复暂停pause();}else if (KEY_PRESS(VK_F3)){if (ps->SleepTime>=80){ps->SleepTime -= 30;ps->FoodWeight += 2;}}else if (KEY_PRESS(VK_F4)){if (ps->FoodWeight > 2){ps->SleepTime += 30;ps->FoodWeight -= 2;}}//睡眠Sleep(ps->SleepTime);//走一步SnakeMove(ps);//检测撞墙KillByWall(ps);//检测是否撞到自己KillBySelf(ps);} while (ps->Status == OK);
}void GameEnd(pSnake ps)
{SetPos(35, 18);switch (ps->Status){case ESC:printf("正常退出\n");break;case KILL_BYWALL:printf("很遗憾,撞到墙,游戏结束\n");break;case KILL_BYSELF:printf("很遗憾,咬到自己了,游戏结束\n");break;}//释放贪吃蛇pSnakeNode cur = ps->pSnake;while (cur){pSnakeNode next = cur->next;free(cur);cur = next;}free(ps->pFood);ps = NULL;
}void test()
{int ch = 0;do{Snake snake = { 0 };GameStart(&snake);GameRun(&snake);GameEnd(&snake);SetPos(35, 18);printf("再来一局吗:Y/N");ch=getchar();getchar();} while (ch == 'y' || ch == 'Y');
}
int main()
{setlocale(LC_ALL, "");srand((unsigned int)time(NULL));test();SetPos(55, 35);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/259361.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言每日一练——链表篇(八)

传送门 牛客面试笔试必刷101题 ----------------两个链表的第一个公共结点 题目以及解析 题目 解题代码及解析 解析 这一道题使用的还是双指针算法&#xff0c;我们先求出两个链表的长度差n&#xff0c;然后定义快慢指针&#xff0c;让快指针先走n步&#xff0c;最后快慢指…

基于SSM的社区疫情防控管理系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的社区疫情防控管理系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spri…

拿捏c语言指针(中)

前言 书接上回 拿捏c语言指针&#xff08;上&#xff09; 此篇主要讲解的是指针与数组之间的爱恨情仇&#xff0c;跟着我的脚步一起来看看吧~ 创造不易&#xff0c;可以帮忙点点赞吗 如有差错&#xff0c;欢迎指出 理解数组名 数组名是首元素地址 例外 1.sizeof&#xff0…

C#使用迭代器实现文字的动态效果

目录 一、涉及到的知识点 1.GDI 2.Thread类 3.使用IEnumerable()迭代器 二、实例 1.源码 2.生成效果&#xff1a; 一、涉及到的知识点 1.GDI GDI主要用于在窗体上绘制各种图形图像。 GDI的核心是Graphics类&#xff0c;该类表示GDI绘图表面&#xff0c;它提供将对象绘制…

在UE5中使用体积材质

在平时使用UE的材质设置时&#xff0c;经常会看见Material Domain Volume类型&#xff0c;但是却很少使用。其实该类型可以配合体积雾使用&#xff0c;并制作体积效果以弥补自带雾参数的不足。 操作流程 首先找到场景中的ExponentialHeightFog组件&#xff0c;开启体积雾Volu…

c++阶梯之类与对象(下)

前文&#xff1a; c阶梯之类与对象&#xff08;上&#xff09;-CSDN博客 c阶梯之类与对象&#xff08;中&#xff09;-CSDN博客 c阶梯之类与对象&#xff08;中&#xff09;&#xff1c; 续集 &#xff1e;-CSDN博客 1. 再谈构造函数 1.1 构造函数体赋值 在创建对象时&a…

Momentum2

攻击机 192.168.223.128 目标机 192.168.223.147 主机发现 nmap -sP 192.168.223.0/24 端口扫描 nmap -sV -A -p- 192.168.223.147 开启了22 80 端口 看一下web界面 源码&#xff0c;robots.txt ,url都观察了一下好像没什么有用信息 扫一下目录 gobuster dir -u http:…

C++面试宝典第28题:寻找丢失的数字

题目 给定一个包含n个整数的数组nums,其中nums[i]在区间[1, n]内。请找出所有在[1, n]范围内,但没有出现在nums中的数字,并以数组的形式返回结果。 示例1: 输入:nums = [4, 3, 2, 7, 8, 2, 3, 1] 输出:[5, 6] 示例2: 输入:nums = [1, 1] 输出:[2] 解析 初看这道题,…

VFH特征的使用(一)

一、SHOT特征描述符可视化 C #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/io/pcd_io.h> #include <pcl/features/normal_3d_omp.h> #include <pcl/registration/correspondence_estimation.h> #include <boo…

『 C++ 』海量数据处理

文章目录 &#x1f996; 快速找出海量数据中是否存在该整型数据&#x1f996; 有限内存情况下两个文件(海量query)中找出交集&#x1f996; 海量数据中找出只出现1次的数据&#x1f996; 有限内存情况下两个文件(整型)找出交集&#x1f996; 海量数据中找出出现次数不超过2次的…

挑战杯 YOLOv7 目标检测网络解读

文章目录 0 前言1 yolov7的整体结构2 关键点 - backbone关键点 - head3 训练4 使用效果5 最后 0 前言 世界变化太快&#xff0c;YOLOv6还没用熟YOLOv7就来了&#xff0c;如果有同学的毕设项目想用上最新的技术&#xff0c;不妨看看学长的这篇文章&#xff0c;学长带大家简单的…

5G——小区搜索流程

小区搜索流程 小区搜索目标&#xff1a;读取到SIB1. 小区搜索流程概述&#xff1a;SIB1在PDSCH信道承载&#xff0c;承载SIB1的信道在哪个位置由PDCCH告诉&#xff0c;而PDCCH的基本信息由MIB告诉&#xff0c;MIB信息由广播信道PBCH广播出去&#xff0c;物理信道解调需要解调…

vue3-组合式 API

什么是组合式 API&#xff1f; 组合式 API (Composition API) 是一系列 API 的集合&#xff0c;使我们可以使用函数而不是声明选项的方式书写 Vue 组件。它是一个概括性的术语&#xff0c;涵盖了以下方面的 API&#xff1a; 响应式 API&#xff1a;例如 ref() 和 reactive()&a…

HttpRunner自动化测试之实现参数化传递

参数化实现及重复执行 参数化测试&#xff1a;在接口测试中&#xff0c;为了实现不同组数据对同一个功能模块进行测试&#xff0c;需要准备多组测试数据对模块进行测试的过程。 在httprunner中可以通过如下方式实现参数化&#xff1a; 1、在YAML/JSON 中直接指定参数列表 2、…

【C++】C++入门

关于C是什么 C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要高度的抽象和建模时&#xff0c;C语言则不合适。为了解决软件危机&#xff0c;20世纪80年代&#xff0c;计算机界提出了OOP(object or…

静态时序分析:SDC约束命令set_clock_latency详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 时钟的延迟可以使用set_clock_latency命令设置&#xff0c;这里的时钟延迟包括源延迟(source latency)&#xff0c;即时钟对象到时钟源对象&#xff08;时钟定义…

Linux——网络通信TCP通信常用的接口和tcp服务demo

文章目录 TCP通信所需要的套接字socket()bind()listen()acceptconnect() 封装TCP socket TCP通信所需要的套接字 socket() socket()函数主要作用是返回一个描述符&#xff0c;他的作用就是打开一个网络通讯端口&#xff0c;返回的这个描述符其实就可以理解为一个文件描述符&a…

抖音关键词搜索爬虫,抖音API数据接口,抖音商品详情数据采集

抖音商品API接口抖音关键词搜索抖音直播间小黄车抖店商品数据采集 除了微博&#xff0c;小红书&#xff0c;抖音也是一个巨大的流量池。 除了评论&#xff0c;其实关键词搜索视频是更为常见的一个需求&#xff0c;于是上周末抽空开发了下&#xff0c;完成了 mvp。

数据结构——lesson3单链表介绍及实现

目录 1.什么是链表&#xff1f; 2.链表的分类 &#xff08;1&#xff09;无头单向非循环链表&#xff1a; &#xff08;2&#xff09;带头双向循环链表&#xff1a; 3.单链表的实现 &#xff08;1&#xff09;单链表的定义 &#xff08;2&#xff09;动态创建节点 &#…

【数据结构】链表OJ面试题5《链表的深度拷贝》(题库+解析)

1.前言 前五题在这http://t.csdnimg.cn/UeggB 后三题在这http://t.csdnimg.cn/gbohQ 给定一个链表&#xff0c;判断链表中是否有环。http://t.csdnimg.cn/Rcdyc 给定一个链表&#xff0c;返回链表开始入环的第一个结点。 如果链表无环&#xff0c;则返回 NULLhttp://t.cs…