Windows 服务程序(二)
服务控制管理器 (SCM, Service Control Manager),它在系统启动时自动启动,其主要作用是维护和管理一张服务信息表。
OpenSCManager() 介绍:
功能:建立了一个到服务控制管理器的连接,并打开指定的数据库。
函数原型:SC_HANDLE OpenSCManager(
LPCSTR lpMachineName, // 指向零终止字符串,指定目标计算机的名称。 通常为 NULL。
LPCSTR lpDatabaseName, // 指向零终止字符串,指定将要打开的服务控制管理数据库的名称。通常为 NULL。
DWORD dwDesiredAccess // 指定服务访问控制管理器的权限。通常为 SC_MANAGER_ALL_ACCESS。
);
参数:
lpMachineName
指向零终止字符串,指定目标计算机的名称。
如果该指针为NULL ,或者它指向一个空字符串,那么该函数连接到本地计算机上的服务控制管理器。
lpDatabaseName
指向零终止字符串,指定将要打开的服务控制管理数据库的名称。
此字符串应被置为 SERVICES_ACTIVE_DATABASE。
如果该指针为NULL ,则打开默认的 SERVICES_ACTIVE_DATABASE 数据库。
dwDesiredAccess
指定服务访问控制管理器的权限。
在授予要求的权限前,系统会检查调用进程的权限令牌,该令牌针对与服务控制管理器相关的安全描述符的权限控制列表。
此外,该函数的调用将隐式地指定 SC_MANAGER_CONNECT 的访问权限。
此外,下列服务控制管理器对象的访问类型可以被指定:
SC_MANAGER_ALL_ACCESS 除了所有此表中列出的访问类型,还包括 STANDARD_RIGHTS_REQUIRED。
SC_MANAGER_CONNECT 可以连接到服务控制管理器。
SC_MANAGER_CREATE_SERVICE 使要求的 CreateService 函数创建一个服务对象,并将其添加到数据库中。
SC_MANAGER_ENUMERATE_SERVICE 使要求的 EnumServicesStatus 功能清单的服务,这是在数据库中。
SC_MANAGER_LOCK 使要求的 LockServiceDatabase 功能获得锁定数据库。
SC_MANAGER_QUERY_LOCK_STATUS 使要求的 QueryServiceLockStatus 检索功能锁定状态信息的数据库。
返回值
如果函数成功,返回值是一个指定的服务控制管理器数据库的句柄。如果函数失败,返回值为NULL 。
OpenService() 介绍:
功能:打开一个服务对象。
函数原型:SC_HANDLE OpenService(
SC_HANDLE hSCManager, // 使用 OpenSCManager() 打开后返回的对象句柄。
LPCSTR lpServiceName, // 需要打开的服务的名称,其中不能出现斜杆。
DWORD dwDesiredAccess // 打开权限。通常为 SC_MANAGER_ALL_ACCESS。
);
参数:
lpServiceName
这是在创建服务对象时由 CreateService 函数的 lpServiceName 参数指定的名称,
而不是用户界面应用程序显示的用于标识服务的服务显示名称。
dwDesiredAccess
权限同上。
在授予请求的访问权限之前, 系统将根据与服务对象关联的安全描述符的自由访问控制列表检查调用进程的访问令牌。
返回值:如果函数成功, 则返回值是服务的句柄。如果函数失败,返回值为NULL 。
CreateService() 介绍:
功能:创建一个服务对象,并将其添加到指定的服务控制管理器数据库的函数。
函数原型:SC_HANDLE CreateService(
SC_HANDLE hSCManager, // 服务控制管理器数据库的句柄。
LPCSTR lpServiceName, // 要安装的服务的名称。
LPCSTR lpDisplayName, // 用户界面程序用来标识服务的显示名称。
DWORD dwDesiredAccess, // 对服务的访问权限。通常为 SC_MANAGER_ALL_ACCESS。
DWORD dwServiceType, // 服务类型。 通常为 SERVICE_WIN32_OWN_PROCESS。
DWORD dwStartType, // "服务启动" 选项。通常为 SERVICE_AUTO_START。
DWORD dwErrorControl, // 错误的严重性和所采取的操作。
LPCSTR lpBinaryPathName, // 服务二进制文件的完全限定路径。
LPCSTR lpLoadOrderGroup, // 通常不关心,设置为 NULL。
LPDWORD lpdwTagId, // 通常不关心,设置为 NULL。
LPCSTR lpDependencies, // 通常不关心,设置为 NULL。
LPCSTR lpServiceStartName, // 通常不关心,设置为 NULL。
LPCSTR lpPassword // 通常不关心,设置为 NULL。
);
参数:
hSCManager
服务控制管理器数据库的句柄。此句柄由 OpenSCManager 函数返回,
并且必须具有 SC_MANAGER_CREATE_SERVICE 访问权限。
lpServiceName
要安装的服务的名称。最大字符串长度为256个字符。
服务控制管理器数据库保留字符的大小写, 但服务名称比较始终不区分大小写。正斜杠 (/) 和反斜线 () 不是有效的服务名称字符。
lpDisplayName
用户界面程序用来标识服务的显示名称。此字符串的最大长度为256个字符。
该名称在服务控制管理器中保留为 case。显示名称比较始终不区分大小写。
dwDesiredAccess
对服务的访问。在授予请求的访问权限之前, 系统将检查调用进程的访问令牌。值同 OpenSCManager() 的该参数。
dwServiceType
服务类型
| 值 | 含义 |
| SERVICE_FILE_SYSTEM_DRIVER | 文件系统驱动程序服务。 |
| SERVICE_KERNEL_DRIVER | 驱动程序服务。 |
| SERVICE_WIN32_OWN_PROCESS | 在其自己的进程中运行的服务。(常用的值) |
| SERVICE_USER_OWN_PROCESS | 该服务在登录用户帐户下在其自己的进程中运行。 |
dwStartType
"服务启动" 选项
| 值 | 含义 |
| SERVICE_AUTO_START | 在系统启动期间, 服务控制管理器自动启动服务。(常用的值) |
| SERVICE_BOOT_START | 由系统加载器启动的设备驱动程序。此值仅对驱动程序服务有效。 |
| SERVICE_DEMAND_START | 当进程调用 StartService 函数时, 由服务控制管理器启动的服务。 |
| SERVICE_DISABLED | 无法启动的服务。尝试启动服务会导致错误代码 ERROR_SERVICE_DISABLED。 |
| SERVICE_SYSTEM_START | 由 IoInitSystem 函数启动的设备驱动程序。此值仅对驱动程序服务有效。 |
dwErrorControl
错误的严重性和所采取的操作
| 值 | 含义 |
| SERVICE_ERROR_CRITICAL | 如果可能, 启动程序会在事件日志中记录错误。如果正在启动最后一次已知良好的配置, 则启动操作将失败。否则, 系统将以最后一次正确的配置重新启动。 |
| SERVICE_ERROR_IGNORE | 启动程序忽略错误并继续启动操作。 |
| SERVICE_ERROR_NORMAL | 启动程序在事件日志中记录错误, 但继续启动操作。 |
| SERVICE_ERROR_SEVERE | 启动程序在事件日志中记录错误。如果正在启动最后一次已知良好的配置, 则启动操作将继续进行。否则, 系统将以上次已知良好的配置重新启动。 |
lpBinaryPathName
服务二进制文件的完全限定路径。如果路径包含空格, 则必须引用它以使其正确解释。
该路径还可以包含自动启动服务的参数。例如, "d:\myshare\myservice.exe arg1 arg2"。这些参数被传递到服务入口点。
如果在另一台计算机上指定路径, 则该共享必须由本地计算机的计算机帐户访问, 因为这是远程调用中使用的安全上下文。
但是, 此要求允许远程计算机中的任何潜在漏洞影响本地计算机。因此, 最好使用本地文件。
返回值:如果函数成功, 则返回值是服务的句柄。如果函数失败, 返回值为 NULL。
StartService() 介绍:
功能:启动服务。
函数原型:BOOL StartService(
SC_HANDLE hService,
//此句柄由 OpenService 或 CreateService 函数返回, 并且必须具有 SERVICE_START 访问权限。
DWORD dwNumServiceArgs, // 通常不关心,设置为 NULL。
LPCSTR *lpServiceArgVectors // 通常不关心,设置为 NULL。
);
返回值:非零表示成功,零表示失败。
QueryServiceStatus() 介绍:
功能:检索指定服务的当前状态。
函数原型:BOOL QueryServiceStatus(
SC_HANDLE hService,
// 此句柄由 OpenService 或 CreateService 函数返回, 并且必须具有 SERVICE_START 访问权限。
LPSERVICE_STATUS lpServiceStatus // 指向接收状态信息的 SERVICE_STATUS 结构的指针。
);
返回值:非零表示成功,零表示失败。
ControlService() 介绍:
功能:向服务发送控制代码。
函数原型:BOOL ControlService(
SC_HANDLE hService,
// 此句柄由 OpenService 或 CreateService 函数返回, 并且必须具有 SERVICE_START 访问权限。
DWORD dwControl, // 控制代码。
LPSERVICE_STATUS lpServiceStatus // 指向接收最新服务状态信息的 SERVICE_STATUS 结构的指针。
);
参数
dwControl
| 控制代码 | 含义 |
| SERVICE_CONTROL_CONTINUE | 通知暂停的服务应恢复。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
| SERVICE_CONTROL_INTERROGATE | 通知服务应将其当前状态信息报告给服务控制管理器。hService 句柄必须具有 SERVICE_INTERROGATE 访问权限。 |
| SERVICE_CONTROL_NETBINDADD | 通知网络服务有一个用于绑定的新组件。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
| SERVICE_CONTROL_NETBINDDISABLE | 通知网络服务其中一个绑定已被禁用。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
| SERVICE_CONTROL_NETBINDENABLE | 通知网络服务已启用已禁用的绑定。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
| SERVICE_CONTROL_NETBINDREMOVE | 通知网络服务已删除绑定的组件。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
| SERVICE_CONTROL_PARAMCHANGE | 通知服务其启动参数已更改。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
| SERVICE_CONTROL_PAUSE | 通知服务应暂停。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
| SERVICE_CONTROL_STOP | 通知服务应停止。hService 句柄必须具有 SERVICE_STOP 访问权限。 |
返回值:非零表示成功,零表示失败。
DeleteService() 介绍:
功能:将指定的服务标记为从服务控制管理器数据库中删除。
函数原型:BOOL DeleteService(
SC_HANDLE hService // 此句柄由 OpenService 或 CreateService 函数返回, 并且必须具有 "删除" 访问权限。
);
返回值:非零表示成功,零表示失败。
CloseServiceHandle() 介绍:
功能:关闭服务控制管理器或服务对象的句柄。
函数原型:BOOL CloseServiceHandle(
SC_HANDLE hSCObject // 要关闭的服务控件管理器对象或服务对象的句柄。
);
参数
hSCObject
要关闭的服务控件管理器对象或服务对象的句柄。
服务控制管理器对象的句柄由 OpenSCManager 函数返回, 并且服务对象的句柄由 OpenService 或 CreateService 函数返回。
返回值:非零表示成功,零表示失败。
DemoCode:
#include<stdio.h>
#include<Windows.h>
#include<winsock.h>
#pragma comment(lib, "Advapi32")
#pragma comment(lib,"ws2_32")
#define MYPORT 1234
#define BACKLOG 10
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
SC_HANDLE SCManager;
SC_HANDLE SCService;
void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
void WINAPI ServiceHandler(DWORD fdwControl);
void InstallService();
void StartService0();
void StopService();
void UnInstallService();
void MyWork(); // 自定义特定功能的函数。本打算用线程调用完成的,简单起见就这样吧。
//DWORD WINAPI MyWork(LPVOID lpParam); 该函数涉及到线程,先放这里。
int main(void)
{
SERVICE_TABLE_ENTRY ServTable[];
ServTable[].lpServiceName = (LPSTR)"Test";
ServTable[].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServTable[].lpServiceName = NULL;
ServTable[].lpServiceProc = NULL;
StartServiceCtrlDispatcher(ServTable);
InstallService();
StartService0();
return ;
} void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv)
{
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = ;
ServiceStatus.dwCheckPoint = ;
ServiceStatus.dwServiceSpecificExitCode = ;
ServiceStatus.dwWaitHint = ;
hStatus = RegisterServiceCtrlHandler("BackDoor",
(LPHANDLER_FUNCTION)ServiceHandler);
if (!hStatus)
{
printf("Register Service Error!\n");
system("pause");
return;
}
SetServiceStatus(hStatus, &ServiceStatus);
if (GetLastError() != NO_ERROR)
{
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = ;
ServiceStatus.dwWaitHint = ;
SetServiceStatus(hStatus, &ServiceStatus);
printf("Start Error!\n");
system("pause");
return;
}
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint = ;
ServiceStatus.dwWaitHint = ;
SetServiceStatus(hStatus, &ServiceStatus);
// 从这里开始可以放入你想服务为你做的事情。
/*
HANDLE hThread = CreateThread(NULL, 0, MyWork, NULL, 0, NULL);
if (hThread = NULL)
return;
*/
MyWork();
return;
} void WINAPI ServiceHandler(DWORD fdwControl)
{
switch (fdwControl)
{
case SERVICE_CONTROL_PAUSE:
ServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = ;
ServiceStatus.dwWaitHint = ;
SetServiceStatus(hStatus, &ServiceStatus);
StopService();
UnInstallService();
return;
default:
break;
}
SetServiceStatus(hStatus, &ServiceStatus);
return;
} void InstallService()
{
char PathName[MAX_PATH];
char SysName[MAX_PATH];
GetModuleFileName(NULL, PathName, MAX_PATH);
GetSystemDirectory(SysName, MAX_PATH);
wsprintf(SysName, "%s\\Test.exe", SysName);
if (!MoveFile(PathName, SysName))
{
printf(" Move File Error!\n");
system("pause");
return;
}
SCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (SCManager == NULL)
{
printf("OpenSCManager Error!\n");
system("pause");
return;
}
SCService = CreateService(
SCManager,
"BackDoor",
"Service32",
SC_MANAGER_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_IGNORE,
SysName,
NULL, NULL, NULL, NULL, NULL);
if (SCService == NULL)
{
printf("CreateService Error!\n");
CloseServiceHandle(SCManager);
system("pause");
return;
}
printf("Create Service Succeed!\n");
CloseServiceHandle(SCService);
CloseServiceHandle(SCManager);
return;
} void StartService0()
{
SCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (SCManager == NULL)
{
printf("OpenSCManager Error!\n");
system("pause");
return;
}
SCService = OpenService(SCManager, "BackDoor", SC_MANAGER_ALL_ACCESS);
if(SCService == NULL)
{
printf("OpenService Error!\n");
CloseServiceHandle(SCManager);
system("pause");
return;
}
if (StartService(SCService, NULL, NULL))
{
while (QueryServiceStatus(SCService,&ServiceStatus))
{
if (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
break;
else
Sleep();
}
printf("Service Start Succeed!\n");
}
CloseServiceHandle(SCService);
CloseServiceHandle(SCManager);
return;
} void StopService()
{
SCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (SCManager == NULL)
{
printf("OpenSCManager Error!\n");
system("pause");
return;
}
SCService = OpenService(SCManager, "BackDoor", SC_MANAGER_ALL_ACCESS);
if (SCService == NULL)
{
printf("Open Service Error!\n");
CloseServiceHandle(SCManager);
system("pause");
return;
}
if (ControlService(SCService, SERVICE_CONTROL_STOP, &ServiceStatus))
{
while (QueryServiceStatus(SCService, &ServiceStatus))
{
if (ServiceStatus.dwCurrentState == SERVICE_STOPPED)
break;
else
Sleep();
}
printf("Service Stop Succeed!\n");
}
CloseServiceHandle(SCService);
CloseServiceHandle(SCManager);
return;
} void UnInstallService()
{
SCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (SCManager == NULL)
{
printf("OpenSCManager Error!\n");
system("pause");
return;
}
SCService = OpenService(SCManager, "BackDoor", SC_MANAGER_ALL_ACCESS);
if (SCService == NULL)
{
printf("Open Service Error!\n");
CloseServiceHandle(SCManager);
system("pause");
return;
}
if (DeleteService(SCService))
printf("Uninstall Service Succeed!\n");
else
printf("Unistall Service Error!\n");
CloseServiceHandle(SCService);
CloseServiceHandle(SCManager);
return;
} void MyWork()
{
SOCKET sockfd, new_fd;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
int sin_size = sizeof(struct sockaddr_in);
WSADATA ws;
if (WSAStartup(MAKEWORD(, ), &ws) != )
{
printf("WSAStart up Error!\n");
WSACleanup();
system("pause");
exit();
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, )) == INVALID_SOCKET)
{
printf("Socket Error!\n");
system("pause");
exit();
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);
my_addr.sin_addr.S_un.S_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -)
{
printf("Bind Error!\n");
closesocket(sockfd);
system("pause");
exit();
}
if (listen(sockfd, BACKLOG) == SOCKET_ERROR)
{
printf("Listen Error!\n");
closesocket(sockfd);
system("pause");
exit();
}
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == INVALID_SOCKET)
{
printf("Accept Error!\n");
closesocket(sockfd);
exit();
}
closesocket(sockfd);
closesocket(new_fd);
WSACleanup();
return;
} /*
DWORD WINAPI MyWork(LPVOID lpParam)
{
return 0;
}
*/
这个程序需要用管理员身份运行,运行结果如下图:

Windows 服务程序(二)的更多相关文章
- Windows服务二:测试新建的服务、调试Windows服务
一.测试Windows服务 为了使Windows服务程序能够正常运行,我们需要像创建一般应用程序那样为它创建一个程序的入口点.像其他应用程序一样,Windows服务也是在Program.cs的Main ...
- Windows服务程序和安装程序制作
转:http://www.cr173.com/html/15350_1.html 本文介绍了如何用C#创建.安装.启动.监控.卸载简单的Windows Service 的内容步骤和注意事项. 一.创建 ...
- .net Windows服务程序和安装程序制作图解 及 VS 2010创建、安装、调试 windows服务(windows service)
.net Windows服务程序和安装程序制作 最近项目中用到window服务程序,以前没接触过,比较陌生,花了两天的时间学习了下,写了个简单的服务,但在制作安装程序的时候,参照网上很多资料,却都制作 ...
- 创建一个Windows服务程序与实现定时器效果
1.创建一个Windows服务程序 一. 新建Window服务项目 二. 添加安装程序 三. 配置服务属性 四. 编写定时器代码 publicpartialclassService1 ...
- 如何在Windows服务程序中添加U盘插拔的消息
研究了下这个问题,主要要在一般的windows服务程序中修改两个地方: 一.调用RegisterServiceCtrlHandlerEx VOID WINAPI SvcMain( DWORD dwAr ...
- 用Visual C#创建Windows服务程序
一.Windows服务介绍: Windows服务以前被称作NT服务,是一些运行在Windows NT.Windows 2000和Windows XP等操作系统下用户环境以外的程序.在以前,编写Wind ...
- .NET 跨平台RPC框架DotNettyRPC Web后台快速开发框架(.NET Core) EasyWcf------无需配置,无需引用,动态绑定,轻松使用 C# .NET 0配置使用Wcf(半成品) C# .NET Socket 简单实用框架 C# .NET 0命令行安装Windows服务程序
.NET 跨平台RPC框架DotNettyRPC DotNettyRPC 1.简介 DotNettyRPC是一个基于DotNetty的跨平台RPC框架,支持.NET45以及.NET Standar ...
- 用C/C++创建windows服务程序
转载:https://blog.csdn.net/chenyujing1234/article/details/8023816 一.演示过程下方代码演示了如何使用vs(C/C++)创建windows服 ...
- WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一)
上接 WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) 七 WCF服务的Windows 服务程序寄宿 这种方式的服务寄宿,和IIS一样有一个一样 ...
随机推荐
- ACM团队周赛题解(2)
拉了CF583和CF486的两套div2题目 还是先贴宏定义部分 #define MAXN 1000000+5#define MOD 1000000007#define PI (acos(-1.0)) ...
- 装系统------- 了解常用的启动方式以及如何进入bios
1.从硬盘启动:这种方式提供了最简单的维护解决方案,其基本原理就是增加一个系统的开机启动项,每次开机的时候您都可以选择是进入本地系统还是进入PE. 安装程序并不将PE的启动项作为默认启动项,而是提供一 ...
- 摩托罗拉GP68对讲机官方说明书下载,包含使用说明压音表和电路结构等
摩托罗拉GP68对讲机官方说明书,包含使用说明和电路结构等 1.使用说明书 链接: https://pan.baidu.com/s/1fhXXaBp-MSuQs9Sv3v_Crg 提取码: mc3e ...
- selenium WebDriver 截取网站的验证码
在做爬虫项目的时候,有时候会遇到验证码的问题,由于某些网站的验证码是动态生成的,即使是同一个链接,在不同的时间访问可能产生不同的验证码, 一 刚开始的思路就是打开这个验证码的链接,然后通过java代码 ...
- Day 22 进程管理2之系统的平均负载
1.管理进程状态 当程序运行为进程后,如果希望停止进程,怎么办呢? 那么此时我们可以使用linux的kill命令对进程发送关闭信号.当然除了kill.还有killall,pkill 1.使用kill ...
- 理解 Spring 注解编程模型
理解 Spring 注解编程模型 Spring 中有一个概念叫「元注解」(Meta-Annotation),通过元注解,实现注解的「派生性」,官方的说法是「Annotation Hierarchy」. ...
- C++基础之string类
string也是属于顺序容器,但是string类很重要且经常使用,因此在这里单独记录. string的操作总结 string(const char *s,int n); //用c字符串s初始化,s应 ...
- java数据结构——单链表、双端链表、双向链表(Linked List)
1.继续学习单链表,终于摆脱数组的魔爪了,单链表分为数据域(前突)和引用域(指针域)(后继),还有一个头结点(就好比一辆火车,我们只关心火车头,不关心其它车厢,只需知晓车头顺藤摸瓜即可),头结点没有前 ...
- Find the Multiple POJ-1426
题目链接:Find the Multiple 题目大意 找出一个只由0和1组成的能整除n的数. 思路 所有由0和1组成的数可以看作是某个只由0.1组成的数a经过以下两种变化得到 1.a * 10 2. ...
- SpringBoot起飞系列-Web开发(四)
一.前言 从今天你开始我们就开始进行我们的web开发,之前的一篇用SpringBoot起飞系列-使用idea搭建环境(二)已经说明了我们如何进行开发,当然这是搭建起步,接下来我们就开始进行详细的开发, ...