有OS时,进程从启动到正常终止的全过程
exit():加载器
启动代码也是调用exit()来终止函数
终止处理函数是exit()退出时,优先调用的,等终止处理函数结束时,调用_exit()
_exit正常退出时,不会调用进程终止处理函数
有关标准IO的库缓存的缓冲有三种,
无缓冲
、行缓冲
、全缓冲
就是调用文件IO的情况:
- 无缓冲就是一调用就输出;行缓冲是满了一行才输出;全缓冲是全部缓冲区积满才输出
标准IO是基于系统函数文件IO的封装库
为什么调用exit正常终止时,会刷新标准io的缓存呢?
因为exit会调用fclose关闭所有的标准io,关闭时会自动调用fflush来刷新数据。
命令行参数
在命令行执行c程序时,可以输入命令行参数
并传递给main函数的形参
,然后进程就得到了命令行的参数。
其中./可执行文件是命令行参数,其后跟的参数叫程序参数,也是命令行参数
#include<stdio.h> int main(int argc,char** argv){ int i=0; for(;i<argc;i++){//argc:参数个数 printf("%s\t",argv[i]); } printf("\n"); int j=0; for(;argv[j]!=NULL;j++){//argv:二级指针,每一级指向一个数组 printf("%s\t",argv[j]); } return 0; }
//执行结果 ./main aaa bbb ccc ./main aaa bbb ccc ./main aaa bbb ccc
命令行参数传递给main函数过程
构建指针数组 exec
./a.out *** *** ——————> 终端窗口进程 ——————> OS 内核 ——————> 启动代码 ——————> main函数形参
环境变量表
- windows
- 在windows下,如果你不加路径的话,会道默认到当前路径下找程序,没有的话就找不到你的程序
- 只要把程序所在路径,加入windows的
path环境变量
,加入后,随便在什么位置,都可以不加路径的执行这个程序
path这个环境变量的作用:专门记录各种
可执行程序
所在路径path记录后:
1)如果你有明确指定路径,那就直接到你指定的路径下找到程序并执行
2)如果没有明确指定路径,首先,在当前目录下找,如果不到这个程序,就会跑到path记录的各个路径下面去找
通过图形界面,双击快捷图标来打开程序的话,快捷图标可以自动找到所指向的程序并执行,所以对于图形界面这种操作方式来说,path的意义不是很大
windows环境变量
- 环境变量的组成:
环境变量 = 环境变量名 + 环境变量数据
自己创建一个环境变量:
先在用户变量新建一个:环境变量名+值(一般是路径)
***
%环境变量名%
*代表的就是该“环境变量”的数据,%%**就是用来获取环境变量数据(值)
环境变量被存放在了“环境变量表”里面,最原始的“环境变量表”都被保存在了“环境变量文件”中
什么是环境变量
其实就是进程在运行时,会用到的一些字符串信息
,环境表就好比是工具箱,里面放了各种进程运行时需要用到的“工具”,比如各种的路径
通过图形界面设置、修改windows“环境变量”时,修改、设置的内容,都会被永久保存到“环境变量文件”中
每个进程的环境变量表:
每一个进程都在自己的内存空间(堆空间)保存了一份自己的环境变量表。
如果某环境变量的数据有很多条,在环境变量
表
中
- 在windows这边使用;分隔
- Linux这边则使用:分隔
-
在命令行执行自己的程序时,查找的是“命令行窗口进程”的“环境变量表”
-
为什么只有重新打开“命令行窗口”后, 新设置的“环境变量”才生效?
因为新设置的环境变量,只是被保存到了windows的环境变量文件中,但是之前所打开的“命令行窗口”进程的“环境变量表”还没有得到更新,只有当重新打开后,才能更新。
其实在w10以前更麻烦,更新了环境变量文件后,必须要重启系统才能生效,不过w10后不用这么麻烦了,只需要重新打开即可。
Linux系统变量
永久修改
基本都是通过修改“环境变量文件”来实现的
临时修改
就是只修改
当前进程自己
的“环境变量表”其它不相关进程的“环境变量表”以及“环境变量文件”中数据,不会发生任何变化
当进程结束时,当前进程的“环境变量表”就被释放了
---------这就是临时修改
如何实现临时修改
- 使用
命令
修改------改的是“命令行窗口进程”的环境变量表 - 通过
API
修改------修改的只是我自己程序的“环境变量表”
查看所有环境变量
- Linux
命令:export
把当前“终端窗口进程”的所有环境变量全部显示出来
windows
命令:set
把当前“终端窗口进程”的所有环境变量全部显示出来
显示单个的环境变量
- Linux
用法:echo $环境变量命令
PATH是环境变量名,
$PATH
代表的就是PATH的环境变量数据,可以认为$就是用来获取环境变量数据的在Linux,环境变量的多个数据之间使用:分隔
- windows
用法:set 环境变量名 或者 set %环境变量名%
添加一个新的环境变量
-
Linux
例子:
export
AA=
wwwwwwwwwwww- 新环境变量名叫AA
- 环境数据为wwwwwwwwwwww
在Linux下,环境变量名往往喜欢一律大写
-
windows
例子:set aa=wwwwwwwwwwww
修改已有的环境变量
-
覆盖修改
覆盖原有数据,还是使用添加新环境变量的命令来操作,如果添加的“环境变量”之前就存在了,现在的数据会修改原来的数据
Linux
export AA=sssssssssss -
末尾追加
保留原有数据
- windows
- set aa=%AA%;dddddddddddd
- set aa=dddddddddddd;%AA%
- Linux
添加后只用:可执行文件名即可执行,无需./
export AA= A A : d d d d d d d d d d d d 或者 e x p o r t A A = d d d d d d d d d d d d : AA:dddddddddddd 或者 export AA=dddddddddddd: AA:dddddddddddd或者exportAA=dddddddddddd:AA
//$AA就表示原来的数据,新写的数据用:分割
删除环境变量
1.Linux unset AA
2.windows set aa=
不管是在windows下还是在Linux下,在命令行下添加/修改环境变量时,改动的只是当前“命令行窗口进程”的环境变量表
- 当你在另一个窗口查看时,根本找不到这个修改
- 当你把当前窗口关闭后,当前“命令行窗口进程”的环境变量表也就被释放了,那么之前的修改自然也就无效了
通过API修改环境变量表
- 获取环境表中的所有环境变量
environ全局变量
- char** environ
- 指向的是一个字符串指针数组------------每一行就是环境变量字符串
#include<stdio.h>
#include<stdlib.h>
//声明变量:environ
extern char** environ;
int main(int argc,char** argv){
int i=0;
for(;environ[i]!=NULL;i++)
printf("%s\n",environ[i]);
return 0;
}
//main函数的第三个参数
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char** argv,char** environ){
int i=0;
for(;environ[i]!=NULL;i++)
printf("%s\n",environ[i]);
return 0;
}
- 调用API:实现环境变量的添加、修改等
putenv、setenv:添加和修改环境变量
#include <stdlib.h>
/*
设置新的环境变量到环境表中:
如果这环境变量之前就存在,那么这一次的数据会无条件覆盖之前的数据
如果不存在,就添加这个新的环境变量
*/
//string:新的环境变量,比如“name=value”
int putenv(char *string);
/*
name:环境变量的名字。
value:环境变量值。
overwrite:如果发现name环境变量以前就已经存在,会根据overwrite的值来决定是否覆盖,
0:不覆盖;0:覆盖
*/
int setenv(const char *name, const char *value, int overwrite);
//tenv函数:调用成功返回0,失败返回非0,errno被设置。
//tenv函数:调用成功返回0,失败返回-1,errno被设置
#include<stdio.h>
#include<stdlib.h>
extern char** environ;
int main(int argc,char** argv){
int i=0;
putenv("aaa=wwwwwww");
setenv("bbb","nnnnnnnn",0);
for(;environ[i]!=NULL;i++)
printf("%s\n",environ[i]);
return 0;
}
注意想查看到结果,不可以采用第三个参数,只可以使用extern声明
unsetenv
#include <stdlib.h>
//删除环境变量函数
//删除name指定名字的环境变量
int unsetenv(const char *name);
#include<stdio.h>
#include<stdlib.h>
extern char** environ;
int main(int argc,char** argv){
int i=0;
putenv("aaa=wwwwwww");
putenv("aaa=www");
setenv("bbb","nnnnnnnn",0);
unsetenv("bbb");
for(;environ[i]!=NULL;i++)
printf("%s\n",environ[i]);
return 0;
}
getenv
#include <stdlib.h>
char *getenv(const char *name);
int main(int argc,char** argv){
char* p=getenv("PATH");
printf("PATH=%s\n",p);
return 0;
}
自己所写程序的环境表是怎么来的
命令行窗口执行./a.out,那么a.out进程就属于“命令行窗口进程”的子进程,子进程的环境表是从父进程复制得到的
- 当有OS支持时,基本所有的进程都是由父进程“生”出来的
原始进程————>进程————————>进程————————>终端进程——————>a.out进程 | | | | | | V V | 进程 进程 进程 | | | | | | ... ... ...
- 所有进程的“环境变量表”都是从父进程复制得到的
- 最原始进程的“环境变量表”则是从“环境变量文件”中读到的
原始进程 子进程 子进程 子进程 环境变量文件 ————> 进程环境表 ————————>进程环境表 ————————>进程环境表 ————————>.....
- 自己的进程有一个子进程的话,也会继承自己进程的环境表
c程序空间布局
-
什么是c程序的内存空间
c程序运行时,是运行在
内存
上的,也就是说需要在内存上开辟出一块空间给c程序,然后将C代码会被从硬盘拷贝到内存空间上运行 -
c程序的内存空间结构
这段空间必须布局为c程序运行所需的空间结构,c程序才能运行
如果空间没有布局好,进程将无法运行,因此进程空间(c程序的内存空间)也是非常重要的进程环境
c的内存结构是由
启动代码
来搭建的比如启动代码会把c内存空间的某一部分空间,构建为“栈”,也就是说以“栈”的方式来管理这片内存
c程序代码在内存上运行起来后,它就是一个进程,所以程序代码在内存上所占用的空间,也别称为进程空间