下个自主shell蛋
创始人
2024-09-26 17:54:32
0

学个damn!

给我狠狠玩好嘛别卷我啊

知道的是图书馆,不知道的还以为开演唱会呢!

八点啊,那可是八点,才八点!

762a6189b796421095427f0a76cbe942.jpg

不是哥们下午两点半开馆即满人啊我靠?

只能去儿童区学我说不是?

 

别拷打我了我真碎了哥

说说自主shell编写吧(要不然进程控制不白学了)

自主shell首先得有打印命令行提示符吧,命令行提示符构成是这样的:用户名+主机名+当前所处路径,我们都封装成函数:

const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }

分别获取到了对应的字符串,我们还需要一个函数把这些字符串拼接起来,这个功德圆满的函数就是:sprintf!

sprintf是个怎样的函数呢?

sprintf是一个可以向内存空间写入的printf

而snprintf是给定大小的更安全的向内存空间中写入的printf(写到缓冲区)

void MakeCommandLine(char line[], size_t size) { 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, size, "[%s@%s %s]#", username, hostname, cwd); 	fflush(stdout); }

搞完哩, ,,

命令行已经输出了,我们需要获取用户的命令 

而像ls -a -l -i这种命令本质上是字符串嘞,不能直接用scanf获取,因为scanf空格作为分割,但是我们输入命令是不知道有多少空格的输入,按照行获取有木有?

有哇,fgets啊

为何偏偏是它 

 乐意,,,

#include #include #include #include #include  #define SIZE 512  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int main() { 	MakeCommandLine();  	char usercommand[SIZE]; 	char* s = fgets(usercommand, sizeof(usercommand), stdin); 	if (s == NULL) 	{ 		return 1; 	} 	printf("echo:%s\n", usercommand); 	return 0; }

为什么这多输出了一个空行(因为多有了一个\n啊)

为了剔除这个\n,可以这样干:

#include #include #include #include #include #include  #define SIZE 512 #define ZERO '\0'  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int main() { 	MakeCommandLine();  	char usercommand[SIZE]; 	char* s = fgets(usercommand, sizeof(usercommand), stdin); 	if (s == NULL) 	{ 		return 1; 	} 	usercommand[strlen(usercommand) - 1] = ZERO; 	printf("echo:%s\n", usercommand); 	return 0; }

 写成接口就是:

int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }

 接下来需要做的是命令行字符串分割

我们无需再进行手搓函数,有个函数已经提供了分割的功能了:strtok

字符串函数们的使用和模拟实现-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/chestnut_orenge/article/details/135351316 这样赋值,先判断,分割后strtok会返回NULL,刚好让gArgv的最后一个元素是NULL,并且while判断结束

void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }

命令行字符串分割后要执行相应的命令,但是我们不能让该程序执行(代码替换完之后就无了),所以要创建紫禁城帮助我们执行相应的命令

之前学过exec相关函数,我们所获得的命令串都是系统中的,所以默认去环境变量中寻找即可(带p的),又因为获取的是命令串,所以要带v的(容器)

现在大致是这样的:

#include #include #include #include #include #include #include  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32  void Die() {  }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }  char* gArgv[NUM];  void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  int main() { 	MakeCommandLine();  	char usercommand[SIZE]; 	GetUserCommand(usercommand, sizeof(usercommand)); 	 	splitCommand(usercommand, sizeof(usercommand));  	for (int i = 0; gArgv[i]; i++) 	{ 		printf("gArgv[%d]:%s\n", i, gArgv[i]); 	}  	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id,&status,0); 		if (rid > 0) 		{ 			 		} 	} 	return 0; }

但是我们自己编写的这个shell只能运行一次,我们想要让它一直运行执行命令 

于是封装+循环写个简单的shell就好:

#include #include #include #include #include #include #include  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32  void Die() {  }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }  char* gArgv[NUM];  void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  void ExecuteCommand() { 	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id, &status, 0); 		if (rid > 0) 		{  		} 	} }  int main() { 	int quit = 0; 	while (!quit) 	{ 		MakeCommandLine();  		char usercommand[SIZE]; 		GetUserCommand(usercommand, sizeof(usercommand));  		splitCommand(usercommand, sizeof(usercommand));  		ExecuteCommand(); 	} 	return 0; }

大致没问题,但是有个命令跑起来有问题:cd 

 

我们的shell没法进行路径的切换和回退 

每个进程都会记录自己当前所处的路径(父进程有,紫禁城也有)

紫禁城确实是执行了路径切换的命令,但是和父进程没什么关系,而打印命令行是父进程负责的

我们需要让cd交给父进程去执行,也就是所谓的内建命令

所以我们在执行命令前要检查是否是内建命令,由于命令已经被分割,所以直接检查

在获取完用户命令后,进行切换命令需要用到系统调用的接口chdir

 写完了一串代码,会发现cd倒是能用,只不过命令行打印不正常罢了,所以这意味着我们需要对环境变量进行更新

#include #include #include #include #include #include #include  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32  void Die() {  }  const char* Home() { 	const char* home = getenv("HOME"); 	if (home == NULL) 	{ 		return "/"; 	} 	return home; }  void Cd() { 	const char* path = gArgv[1]; 	if (path == NULL) 	{ 		path = Home(); 	} 	chdir(path); }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }  char* gArgv[NUM];  void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  void ExecuteCommand() { 	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id, &status, 0); 		if (rid > 0) 		{  		} 	} }  int CheckBuildin() { 	int yes = 0; 	const char* enter_cmd = gArgv[0]; 	if (strcmp(enter_cmd, "cd") == 0) 	{ 		yes = 1; 		Cd(); 	} 	return yes; }  int main() { 	int quit = 0; 	while (!quit) 	{ 		MakeCommandLine();  		char usercommand[SIZE]; 		int n = GetUserCommand(usercommand, sizeof(usercommand)); 		if (n < 0) 		{ 			return 1; 		}  		splitCommand(usercommand, sizeof(usercommand));  		n = CheckBuildin(); 		if (n) 		{ 			continue; 		}  		ExecuteCommand(); 	} 	return 0; }

 需要注意的是,我们需要刷新环境变量,以保证出来的都是绝对路径

 改完之后除了cd -不支持,其他都支持(cd -需要保存最近一次所处路径)

#include #include #include #include #include #include #include  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32  char cwd[SIZE * 2]; char* gArgv[NUM];  void Die() { 	exit(1); }  const char* Home() { 	const char* home = getenv("HOME"); 	if (home == NULL) 	{ 		return "/"; 	} 	return home; }  void Cd() { 	const char* path = gArgv[1]; 	if (path == NULL) 	{ 		path = Home(); 	} 	chdir(path); 	char temp[SIZE * 2]; 	getcwd(temp, sizeof(temp)); 	snprintf(cwd, sizeof(cwd), "PWD=%s", temp); 	putenv(cwd); }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }   void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  void ExecuteCommand() { 	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id, &status, 0); 		if (rid > 0) 		{  		} 	} }  int CheckBuildin() { 	int yes = 0; 	const char* enter_cmd = gArgv[0]; 	if (strcmp(enter_cmd, "cd") == 0) 	{ 		yes = 1; 		Cd(); 	} 	return yes; }  int main() { 	int quit = 0; 	while (!quit) 	{ 		MakeCommandLine();  		char usercommand[SIZE]; 		int n = GetUserCommand(usercommand, sizeof(usercommand)); 		if (n < 0) 		{ 			return 1; 		}  		splitCommand(usercommand, sizeof(usercommand));  		n = CheckBuildin(); 		if (n) 		{ 			continue; 		}  		ExecuteCommand(); 	} 	return 0; }

插个眼我很好奇为什么编译不过去

我们自己创建的shell在打印命令行的时候保存的是一串路径,但是正常的shell在保存路径的时候只会保存当前路径,那应该怎么办捏?

就是设个指针让它前移,但是需要做一些特殊处理,在一般情况下打印路径分割符后的内容,在特殊情况下只打印路径分隔符

使用宏是因为要单独对指针进行操作 

用do...while(0)是因为可以形成代码块,且do...while(0)后面可加;

在使用时可当做函数,且可应对分支情况的出现

然后还需要接着判断其他的内建命令

#include #include #include #include #include #include #include  #define SkipPath(p) do{ p += (strlen(p) - 1); while (*p != '/')p--;}while(0)  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32   char cwd[SIZE * 2]; char* gArgv[NUM];  void Die() { 	exit(1); }  const char* Home() { 	const char* home = getenv("HOME"); 	if (home == NULL) 	{ 		return "/"; 	} 	return home; }  void Cd() { 	const char* path = gArgv[1]; 	if (path == NULL) 	{ 		path = Home(); 	} 	chdir(path); 	char temp[SIZE * 2]; 	getcwd(temp, sizeof(temp)); 	snprintf(cwd, sizeof(cwd), "PWD=%s", temp); 	putenv(cwd); }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd();  	SkipPath(cwd); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, strlen(cwd) == 1 ? "/" : cwd + 1); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }   void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  void ExecuteCommand() { 	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id, &status, 0); 		if (rid > 0) 		{  		} 	} }  int CheckBuildin() { 	int yes = 0; 	const char* enter_cmd = gArgv[0]; 	if (strcmp(enter_cmd, "cd") == 0) 	{ 		yes = 1; 		Cd(); 	} 	return yes; }  int main() { 	int quit = 0; 	while (!quit) 	{ 		MakeCommandLine();  		char usercommand[SIZE]; 		int n = GetUserCommand(usercommand, sizeof(usercommand)); 		if (n < 0) 		{ 			return 1; 		}  		splitCommand(usercommand, sizeof(usercommand));  		n = CheckBuildin(); 		if (n) 		{ 			continue; 		}  		ExecuteCommand(); 	} 	return 0; }

判断echo命令

 

 这是记录最近一次的返回值(echo $?)啊麻烦死了自己实现shell

忙活半天只能做个青春版,还不能查历史输入的命令

#include #include #include #include #include #include #include  #define SkipPath(p) do{ p += (strlen(p) - 1); while (*p != '/')p--;}while(0)  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32  int lastcode = 1; char cwd[SIZE * 2]; char* gArgv[NUM];  void Die() { 	exit(1); }  const char* Home() { 	const char* home = getenv("HOME"); 	if (home == NULL) 	{ 		return "/"; 	} 	return home; }  void Cd() { 	const char* path = gArgv[1]; 	if (path == NULL) 	{ 		path = Home(); 	} 	chdir(path); 	char temp[SIZE * 2]; 	getcwd(temp, sizeof(temp)); 	snprintf(cwd, sizeof(cwd), "PWD=%s", temp); 	putenv(cwd); }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd();  	SkipPath(cwd); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, strlen(cwd) == 1 ? "/" : cwd + 1); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }   void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  void ExecuteCommand() { 	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id, &status, 0); 		if (rid > 0) 		{ 			lastcode = WEXITSTATUS(status); 			if (lastcode != 0) 			{ 				printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode); 			} 		} 	} }  int CheckBuildin() { 	int yes = 0; 	const char* enter_cmd = gArgv[0]; 	if (strcmp(enter_cmd, "cd") == 0) 	{ 		yes = 1; 		Cd(); 	} 	else if (strcmp(enter_cmd, "echo") == 0 && strcmp(gArgv[1], "$?") == 0) 	{ 		yes = 1; 		printf("%d\n", lastcode); 		lastcode = 0; 	} 	return yes; }  int main() { 	int quit = 0; 	while (!quit) 	{ 		MakeCommandLine();  		char usercommand[SIZE]; 		int n = GetUserCommand(usercommand, sizeof(usercommand)); 		if (n < 0) 		{ 			return 1; 		}  		splitCommand(usercommand, sizeof(usercommand));  		n = CheckBuildin(); 		if (n) 		{ 			continue; 		}  		ExecuteCommand(); 	} 	return 0; }

 在shell中建立环境变量表也是默认创建指针

是一个缓冲区,可以自己申请,环境变量表是char* env[32],而定义开个空间就直接自己设置就好:

char** env = (char*)malloc(sizeof(char*)*32);

 自己写个shell就对它怎样执行命令认识的更加深刻了

相关内容

热门资讯

安卓系统怎么升级抖音,轻松实现... 亲爱的手机控们,你是不是也和我一样,对手机里的抖音APP爱不释手呢?不过,你知道吗?抖音APP也在不...
安卓系统下载taptap就好了... 你有没有发现,现在手机上玩游戏的体验越来越棒了?想要找到那些好玩的游戏,安卓系统的小伙伴们可要记得,...
emui8.1安卓系统视频,安... 亲爱的读者们,你是否曾在某个瞬间,被手机上流畅的视频播放所吸引?今天,就让我带你深入探索华为EMUI...
安卓系统中控安装carplay... 你有没有想过,在安卓手机上也能享受到苹果的CarPlay功能呢?没错,就是那个让iPhone用户爱不...
目前安卓系统永久会卡吗,永久卡... 你有没有发现,你的安卓手机有时候用着用着就卡了呢?是不是也在想,这安卓系统是不是就注定了要卡卡卡?别...
安卓系统能刷ios吗,安卓设备... 你有没有想过,安卓手机能不能刷成iOS系统呢?这可是个让人好奇心爆棚的问题!想象你的安卓手机突然变成...
安卓系统关机短信吗,一键轻松关... 你有没有想过,当你的安卓手机突然关机了,它会给你发条短信吗?这听起来像是科幻电影里的情节,但实际上,...
灵越属于安卓系统吗,安卓系统下... 你有没有想过,你的手机里那个叫做“灵越”的小家伙,它到底是不是安卓系统的忠实伙伴呢?今天,我们就来一...
安卓系统怎么把王者转区,安卓系... 你是不是也和我一样,沉迷于王者荣耀,却因为服务器的问题,想要把账号转到更近的服务器呢?别急,今天就来...
淡粉色的平板安卓系统,探索安卓... 你有没有发现,最近市面上出现了一种特别美腻的平板电脑,它的系统竟然是淡粉色的安卓系统!是不是瞬间觉得...
外星信号与系统和安卓,探索未知... 哇,你知道吗?最近科学家们在外太空的探索中又有了新的发现,这可是让人兴奋不已的事情呢!想象如果真的有...
安卓系统如何后台管理,后台管理... 你有没有发现,手机里的安卓系统就像一个超级管家,默默地在后台为你打理一切?今天,就让我带你一起探索这...
全军出击账号ios系统和安卓系... 你有没有发现,最近全军出击这款游戏可是火得一塌糊涂啊!不管是iOS系统还是安卓系统,都能轻松驾驭,玩...
刘氏神数安卓系统,揭秘安卓系统... 你有没有听说过刘氏神数安卓系统?这可是最近在数码圈里火得一塌糊涂的存在呢!想象你的手机瞬间变成了一个...
vivo新系统怎么退回安卓系统... 亲爱的手机控们,你是否在最新的vivo手机上体验了新系统,却突然觉得有些不适应呢?别担心,今天就来手...
安卓系统微信误删好友,教你轻松... 你有没有遇到过这种情况?手机里微信的好友列表里突然少了几个熟悉的名字,心里顿时慌得一笔,是不是不小心...
如何删除密码设置安卓系统,安卓... 你是不是也遇到了这样的烦恼:手机里的安卓系统密码设置太复杂,有时候自己都忘了密码是什么了?别急,今天...
怎样使安卓系统允许安装,安卓系... 你是不是也和我一样,对安卓系统的限制感到头疼?有时候,我们想要安装一些非官方的应用,却发现系统不让步...
一分钟了解!牛牛房卡游戏代理华... 今 日消息,华山大厅房卡添加微信33549083 苹果今日发布了 iOS 16.1 正式版更新,简单...
玩家攻略,牛牛房卡哪里有卖的茄... 茄子娱乐房卡更多详情添加微:33549083、 2、在商城页面中选择房卡选项。 3、根...