在学习Unix/Linux编程实践教程时,总是感觉学不到东西,过后就没啥印象了,经过向师兄请教后,还是由于自己动手练习的太少,没能够深入理解,于是让我编写一个简单的ps命令。开始很是头大,经过自己的不断努力,终于可以实现简单的ps命令的功能了。下边就给大家分享一下,有什么错误或者建议,还望大家能够指出。


先讲下自己的思路,明白以下几个小问题:

1.ps有什么用?

2.ps的系统调用情况?

3.进程信息在什么地方存储?


man ps就可以发现ps是用于显示进程瞬时信息的,它有好多参数,这里就不一一介绍;

接下来就是查看ps的系统调用,可以使用strace命令实现,部分输出如下:

C语言实现ps命令的编写_ps 实现

主要调用了如图几个文件:

C语言实现ps命令的编写_ps 实现_02

从strace输出的信息中就可以得到很多有用的信息,从/proc目录中含有进程信息相关的文件及目录(/proc/${pid}、/proc/${pid}/stat、/proc/${pid}/status);下来使用ps -e命令输出所有进程,然后再切换到/proc目录中查看,发现该目录中所有的纯数字命名的目录即为进程,再切换入该目录打开前边提到的文件,发现文件中存有进程相关信息。

打开/proc/${pid}/stat显示如下:

C语言实现ps命令的编写_ps命令编写_03

每个字段的意思可以从这便博客中查看 http://blog.chinaunix.net/uid-22145625-id-2974389.html


接下来为了实现简单的ps命令,就需要遍历/proc目录以及读取该目录中的有关文件信息

整个程序的具体函数调用流程如下图:

C语言实现ps命令的编写_linux C编写ps_04

C语言实现ps命令的编写_ps 实现_05

实现代码如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <pwd.h>
#define MAX_LEN 20
struct ps_info *trav_dir(char dir[]);
int read_info(char d_name[],struct ps_info *p1);
void print_ps(struct ps_info *head);
int is_num(char *);
void uid_to_name();
typedef struct ps_info
	char pname[MAX_LEN];
	char user[MAX_LEN];
	int  pid;
	int  ppid;
	char state;
	struct ps_info *next;
}mps;
int main(int ac,char *av[])
	mps *head,*link;
	head=trav_dir("/proc/");
	if(head==NULL)
		printf("traverse dir error\n");
	print_ps(head);
	while(head!=NULL)        //释放链表
		link=head;
		head=head->next;
		free(link);
	return 0;
mps *trav_dir(char dir[])                         
	DIR	*dir_ptr;
	mps *head,*p1,*p2;
	struct dirent *direntp;
	struct stat infobuf;
	if((dir_ptr=opendir(dir))==NULL)
		fprintf(stderr,"dir error %s\n",dir);
		head=p1=p2=(struct ps_info *)malloc(sizeof(struct ps_info));    //建立链表
		while((direntp=readdir(dir_ptr)) != NULL)               //遍历/proc目录所有进程目录
			if((is_num(direntp->d_name))==0)                   //判断目录名字是否为纯数字
				if(p1==NULL)
					printf("malloc error!\n");
					exit(0);
				if(read_info(direntp->d_name,p1)!=0)         //获取进程信息
					printf("read_info error\n");
					exit(0);
				p2->next=p1;                        //插入新节点
				p2=p1;
				p1=(struct ps_info *)malloc(sizeof(struct ps_info));
	p2->next=NULL;
	return head;
int read_info(char d_name[],struct ps_info *p1)
	FILE *fd;
	char dir[20];
	struct stat infobuf;
	sprintf(dir,"%s/%s","/proc/",d_name);
	chdir("/proc");                        //切换至/proc目录,不然stat返回-1
	if(stat(d_name,&infobuf)==-1)                     //get process USER
		fprintf(stderr,"stat error %s\n",d_name);
		//p1->user=uid_to_name(infobuf.st_uid);
		uid_to_name(infobuf.st_uid, p1);
	chdir(dir);            	            //切换到/proc/pid目录
	if((fd=fopen("stat","r"))<0)
		printf("open the file is error!\n");
		exit(0);		
	while(4==fscanf(fd,"%d %s %c %d\n",&(p1->pid),p1->pname,&(p1->state),&(p1->ppid)))     //读文件的前四个字段内容,并存放在相关的链表成员中
		break;							          
	fclose(fd);
	return 0;
void uid_to_name(uid_t uid, struct ps_info *p1)         //由进程uid得到进程的所有者user
	struct passwd *getpwuid(), *pw_ptr;
	static char numstr[10];
	if((pw_ptr=getpwuid(uid)) == NULL)
		sprintf(numstr,"%d",uid);
		strcpy(p1->user, numstr);
		strcpy(p1->user, pw_ptr->pw_name);
int is_num(char p_name[])
	int i,len;
	len=strlen(p_name);
	if(len==0) return -1;
	for(i=0;i<len;i++)
		if(p_name[i]<'0' || p_name[i]>'9')
			return -1;
	return 0;
void print_ps(struct ps_info *head)
	mps *list;
	printf("USER\t\tPID\tPPID\tSTATE\tPNAME\n");
	for(list=head;list!=NULL;list=list->next)
		printf("%s\t\t%d\t%d\t%c\t%s\n",list->user,list->pid,list->ppid,list->state,list->pname);
                            
C语言实现A*算法

最近搞MTK斯凯冒泡平台的游戏开发,碰到了自动寻路的问题,很多程序员都知道A*算法,既简单有使用!所以我也选择了A*算法,由于时间比较紧,就在网上百度此算法的C实现,确实有很多!但经测试都有不同的问题,并不能用在商业游戏中,所以最后决定还是自己写吧!A*原理 比较简单,网上有很多介绍的!我也是在网上看的,这里就不重复了!由于我是Java程序员刚开始搞嵌入式C开发不久,所以有很多C用法不是很熟悉,通过搞这个算法又知道不少知识比如Java里的集合   C里要用链表这也是此算法比较重要的一个技术点,遍历链表,还有删减节点,这些对于C程序员来说应该都是很简单的事情,这里还是说一下,以便那些从JAVA转入C开发的程序员快速理解