您的位置:首页 > 文旅 > 美景 > 西安优化外包_排名好的网站建设企业_长沙网址seo_武汉网站开发公司seo

西安优化外包_排名好的网站建设企业_长沙网址seo_武汉网站开发公司seo

2025/1/11 18:25:15 来源:https://blog.csdn.net/m0_73911405/article/details/145037031  浏览:    关键词:西安优化外包_排名好的网站建设企业_长沙网址seo_武汉网站开发公司seo
西安优化外包_排名好的网站建设企业_长沙网址seo_武汉网站开发公司seo

一、知识补充

1.1 snprintf

snprintf() 是 C语言的一个标准库函数,定义在<stdio.h>头文件中。

snprintf() 函数的功能是格式化字符串,并将结果存储在指定的字符数组中。该函数的原型如下:

int snprintf(char *str, size_t size, const char *format[,argument...]);

参数

  • str:指向一个字符数组,用于存储格式化后的字符串,该数组的大小至少为 size。
  • size:指定写入 str 数组中字符的最大个数(包括最后的空字符 '\0')。
  • format:包含格式说明符的字符串,它定义了后续参数的输出格式。
  • [,argument...]:可变参数列表,与格式字符串中的格式说明符相匹配

return 

  • 如果参数 size 的值足够大,则函数返回写入到 str 数组中的字符个数(不包括结尾的空字符),它的值位于[0, size-1]之间。
  • 如果出现编码错误,则返回一个负数。
  • 请注意,只有当这个返回值是非负且小于n时,字符串才被完整地写入了。

1.2 fflush 

fflush()函数:更新缓存区。头文件:#include<stdio.h> 

调用fflush()会将缓冲区中的内容写到stream所指的文件中去.若stream为NULL,则会将所有打开的文件进行数据更新。 

int fflush(FILE *stream);

fflush(stdin):刷新缓冲区,将缓冲区内的数据清空并丢弃。
fflush(stdout):刷新缓冲区,将缓冲区内的数据输出到设备。

  1 #include<stdio.h>2 #include<unistd.h>3 int main()4 {5     printf("hello");                                                                                                            6 7     sleep(5);8 9     printf(" world!\n");10 11     return 0;12 }

5秒后打印hello world!

  1 #include<stdio.h>2 #include<unistd.h>3 int main()4 {5     printf("hello\n");                                                                                                            6 7     sleep(5);8 9     printf(" world!\n");10 11     return 0;12 }

 先打印hello,5秒后打印 world!\n有刷新功能

  1 #include<stdio.h>2 #include<unistd.h>3 int main()4 {                                                                                                                               5     printf("hello");6 7     fflush(stdout);//将缓冲区的内容输出到设备中8 9     sleep(5);10 11     printf(" world!\n");12 13     return 0;14 }

先打印hello5秒后打印 world!

fflush()的作用是用来刷新缓冲区,fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃; fflush(stdout)刷新标准输出缓冲区,把输出缓冲区里的东西强制打印到标准输出设备上。

 1.3 fgets

fgets是C标准库中用于从文件或标准输入流中读取一行字符的函数,常用于处理字符串输入。它的主要作用是读取文件或标准输入中的一行,直到遇到换行符\n或达到指定的字符数为止。

char * fgets ( char * str, int num, FILE * stream );

参数

  • str:这是一个指向字符数组的指针,fgets将把读取的字符存储到这个数组中。
  • num:这是一个整数,表示最多读取的字符数(包括\0终止符)。即使没有读取到换行符,fgets也会在读取的字符数达到num-1时停止
  • stream:这是输入流,可以是文件流(如stdin、stdout)或者其他文件指针。

返回值:

  • 如果读取成功,fgets返回str,即指向读取数据的字符数组。
  • 如果发生错误或达到文件末尾,fgets返回NULL。

1.4 strtok

C语言字符函数和字符串函数-CSDN博客

可参考第11节中的strtok

1.5 getcwd

 getcwd是属于系统接口

#include <unistd.h>
char *getcwd(char *buf, size_t size);

getcwd()会将当前工作目录的绝对路径复制到参数buf所指的内存空间中,参数size为buf的空间大小。

如果getcwd函数执行失败,它将返回NULL

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {char cwd[1024];if (getcwd(cwd, sizeof(cwd))!= NULL) {printf("当前工作目录是: %s\n", cwd);} else {perror("获取当前工作目录出错");return 1;}return 0;
}

像pwd就是调用getcwd这个系统接口 

[zxw@hcss-ecs-cc58 myshell]$ pwd
/home/zxw/linux/112/lesson16/myshell

1.6 chdir 

chdir属于是系统接口

#include <unistd.h>
int chdir(const char *path//路径);

用于改变当前工作目录,其参数为Path 目标目录,可以是绝对目录或相对目录。

成功返回0,错误返回-1。

1.7 putenv

#include <stdlib.h>
int putenv(char *string);

函数说明:putenv()用来改变或增加环境变量的内容.

参数string 的格式为name=value, 如果该环境变量原先存在, 则变量内容会依 value 改变, 否则此参数内容会成为新的环境变量。

返回值:执行成功则返回0, 有错误发生则返回-1. 

 二、模拟Shell命令行解释器

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>using namespace std;const int basesize = 1024;
const int argvnum = 64;
const int envnum = 64;
// 全局的命令行参数表
char *gargv[argvnum];
int gargc = 0;using namespace std;
// 我系统的环境变量表
char *genv[envnum];// 全局的当前shell工作路径
char pwd[basesize];
char pwdenv[basesize];// 全局变量
int lastcode = 0;string GetUserName()
{string name = getenv("USER");return name.empty() ? "None" : name;
}string GetHostName()
{string hostname = getenv("HOSTNAME");return hostname.empty() ? "None" : hostname;
}string GetPwd()
{string pwd = getenv("PWD");return pwd.empty() ? "None" : pwd;// string pwd = getenv("PWD");// 获取当前pwdif(nullptr == getcwd(pwd,sizeof(pwd))) return "None";// 修改环境变量snprintf(pwdenv,sizeof(pwdenv),"PWD=%s",pwd);putenv(pwdenv);return pwd;
}string LastDir()
{string curr =GetPwd();if(curr == "/" || curr == "None") return curr;size_t pos = curr.rfind("/");if(pos == string::npos) return curr;return curr.substr(pos+1);
}// 1.命令行提示符
string MakeCommandLine()
{char command_line[basesize];snprintf(command_line,basesize,"[%s@%s %s]# ",GetUserName().c_str(),GetHostName().c_str(),GetPwd().c_str());GetUserName().c_str(),GetHostName().c_str(),LastDir().c_str());return command_line;
}void PrintCommandLine()
{printf("%s",MakeCommandLine().c_str());fflush(stdout);
}void debug()
{printf("argc:%d\n",gargc);for(int i = 0; gargv[i]; i++){printf("argv[%d]:%s\n",i,gargv[i]);}
}bool GetCommandLine(char command_buffer[],int size)// 2.获取用户命令
// 2.获取用户命令
bool GetCommandLine(char command_buffer[],int size)
{// 我们认为,我们要将用户输入的命令行,当成一个完整的字符串// "ls -a -l -n"char *result = fgets(command_buffer,size,stdin);if(!result){return false;}command_buffer[strlen(command_buffer)-1] = 0;if(strlen(command_buffer) == 0) return false;return true;
}//3.分析命令
void ParseCommandLine(char command_buffer[],int len)
{(void)len;memset(gargv, 0, sizeof(gargv));gargc = 0;// "ls -a -l -n"const char *sep = " ";gargv[gargc++] = strtok(command_buffer,sep);// =是刻意写的 ---》最后返回NULLwhile(gargv[gargc++] = strtok(nullptr,sep)); gargc--;
}void AddEnv(const char *item)
{int index = 0;while(genv[index]){index++;}genv[index] = (char*)malloc(strlen(item)+1);strncpy(genv[index],item,strlen(item)+1);genv[++index] = nullptr;}// shell自己执行命令,本质是shell调用自己的函数
bool CheckAndExecBuiltCommand()
{if(strcmp(gargv[0],"cd") == 0){// 内建命令没有创建子进程,自己执行if(gargc == 2){chdir(gargv[1]);lastcode = 0;}else{lastcode = 1;}return true;}else if(strcmp(gargv[0],"export") == 0){// export也是内建命令if(gargc == 2){AddEnv(gargv[1]);lastcode = 0;}else{lastcode = 2;}return true;}else if(strcmp(gargv[0],"env") == 0){for(int i = 0; genv[i]; i++){printf("%s\n",genv[i]);}lastcode = 0;return true;}else if(strcmp(gargv[0],"echo") == 0){if(gargc == 2){// echo $?// echo helloif(gargv[1][0] == '$'){if(gargv[1][1] == '?'){printf("%d\n",lastcode);lastcode = 0;}}else{printf("%s\n",gargv[1]);}}else{lastcode = 3;}return true;}return false;
}// 4.执行命令
// 在shell中
// 有些命令,必须由子进程来执行
// 有些命令,不能由子进程执行,要由shell自己执行bool ExecuteCommand()
{// 让子进程进行执行pid_t id = fork();if(id < 0){return false;}if(id == 0){//child//1.执行命令execvp(gargv[0],gargv);execvpe(gargv[0],gargv,genv);//2.退出exit(1);}int status = 0;pid_t rid = waitpid(id,&status,0);if(rid < 0)if(rid > 0){//DO Nothingif(WIFEXITED(status)){lastcode = WEXITSTATUS(status);}else{lastcode = 100;}return true;}return false;
}// shell自己执行命令,本质是shell调用自己的函数
bool CheckAndExecBuiltCommand()
// 作为一个shell,获取环境变量应该从系统的配置
// 我们今天就直接从父进程获取环境变量
void InitEnv()
{if(strcmp(gargv[0],"cd") == 0)extern char **environ;int index = 0;while(environ[index]){// 内建命令if(gargc == 2){chdir(gargv[1]);}return true;genv[index] = (char*)malloc(strlen(environ[index])+1);strncpy(genv[index],environ[index],strlen(environ[index]+1));index++;}return false;genv[index] = nullptr;
}int main()
{InitEnv();char command_buffer[basesize];while(true){PrintCommandLine();// 1.命令行提示符// command_line -> outputif(!GetCommandLine(command_buffer, basesize))// 2.获取用户命令{continue;}// printf("%s\n",command_buffer); //"ls -a -b" ---> "ls" "-a" "-b"ParseCommandLine(command_buffer,strlen(command_buffer));// 3.分析命令//debug();//debug();//检查 if(CheckAndExecBuiltCommand()){continue;}ExecuteCommand(); // 4.执行命令}return 0;
}

通过模拟实现了解环境变量也是单独申请了一块地址的,另外我们之前所学习的本地变量也是通过一个数组来维护的。也清楚的了解一些为什么要内建命令,不能单独fork子进程。

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com