通过命令行参数对输入进行排序

源自《The C Programming Language》P102 ex5.11及其后的pr 5-14 ... pr 5-14,代码见pr 5-16:

代码:

#include <stdio.h>
#include <string.h>

#define		MAXLINES		5000			/*进行排序的最大文本行数*/
#define		NUMERIC			1
#define		DECR			2
#define		IGNORE			4
#define		DIR				8

//char* lineptr[MAXLINES];					/*指向文本行的指针数组*/
static int option = 0;

int readLines(char* lineptr[], int maxlines);
void writeLines(char* lineptr[], int nlines, int order);
void myQsort(void* lineptr[], int left, int right, 
		   int (*comp) (void*, void* ), int option);
int numcmp(char*, char* );
int charcmp(char*, char* );

typedef	int (*PFUNC) (void*, void*);

int main(int argc, char* argv[])
{
	int nlines;
	//int option;
	int c;
	char* lineptr[MAXLINES];
	PFUNC pFunc;

	nlines = 0;
	//option = 0;
	/*本处使用的while switch语句来取命令行参数,比通过if语句来取,要简洁高效易扩展*/
	while(--argc > 0 && **(++argv) == '-')	/*获取命令行参数,用于操作*/
		while(c = *++(*argv))
			switch(c)
			{
			case 'n':
				option |= NUMERIC;
				break;
			
			case 'r':
				option |= DECR;
				break;

			case 'f':
				option |= IGNORE;
				break;

			case 'd':
				option |= DIR;
				break;

			default:
				printf("error: illegal command parameters !\n");
				return -1;
			}
	if(argc)
		printf("Usage: sort -dfnr \n");
	else if((nlines = readLines(lineptr, MAXLINES)) > 0)
	{
		if(nlines <= MAXLINES)				/*进行越界判断*/
		{
			if(option & NUMERIC)
				pFunc = numcmp;
			else
				pFunc = charcmp;
			myQsort((void** )lineptr, 0, nlines-1, pFunc, option);
			writeLines(lineptr, nlines, option & DECR);
			return 0;
		}
		else
		{
			printf("error: the lines overflow the MAXLINES\n");
			return -1;
		}
	}
	else
	{
		printf("error: fail to get the lines of input\n");
		return -1;
	}
}

#define		MAXLEN		1000				/*每个输入文本行的最大长度*/
int getLine(char* line, int maxlen);
char* alloc(int);

/*readLines函数:读入输入行*/
int readLines(char* lineptr[], int maxlines)
{
	int len;
	int nlines;
	char* p;
	char line[MAXLEN];

	nlines = 0;
	p = NULL;
	while((len = getLine(line, MAXLEN)) > 0)
		if(nlines >= MAXLINES || !(p = alloc(len)))
			return -1;
		else
		{
			line[len-1] = '\0';
			strcpy(p, line);
			lineptr[nlines++] = p;
		}
	
	return nlines;
}

/*writeLines函数:打印排序后的文本行*/
void writeLines(char* lineptr[], int nlines, int order)
{
	int i;
	int j;

	i = 0;
	j = nlines - 1;
	if(order)
		while(i++ <= nlines - 1)
			printf("%s\n", lineptr[j--]);
	else
		while(nlines-- > 0)
			printf("%s\n", lineptr[i++]);
}

/*getLine:从输入终端获取一个文本行*/
int getLine(char* line, int maxlen)
{
	int i;
	int c;

	for(i = 0; i < maxlen-1 && (c = getchar()) != EOF && c != '\n'; ++i)
		line[i] = c;
	if(c == '\n')
		line[i++] = c;
	line[i] = '\0';

	return i;

}


/*myQsort函数:快速排序,按照递增顺序对lineptr[left]...lineptr[right]进行排序
			 传递comp函数指针,可以处理任何数据类型的排序,而不仅仅是字符串*/
void myQsort(void* lineptr[], int left, int right, 
			 int (*comp) (void*, void*), int option)
{
	int last;
	int i;
	void swap(void* v[], int i, int j);

	if(left >= right)			            /*如果数组元素的个数少于2,则返回*/
		return;
	swap(lineptr, left, (left + right) / 2);
	last = left;
	for(i = left+1; i <= right; ++i)
		if(!(option & DECR))
		{
			if((*comp)(lineptr[i], lineptr[left]) < 0)
				swap(lineptr, ++last, i);
		}
		else
			if((*comp)(lineptr[i], lineptr[left]) > 0)
				swap(lineptr, ++last, i);			
			
	swap(lineptr, left, last);
	myQsort(lineptr, left, last - 1, comp, option);
	myQsort(lineptr, last + 1, right, comp, option);

}

/*swap函数:交换字符指针数组的两个元素*/
void swap(void* v[], int i, int j)
{
	void* tmp;
	tmp = v[i];
	v[i] = v[j];
	v[j] = tmp;
}


#include <stdlib.h>
#include <ctype.h>
#include <math.h>

int numcmp(char* s1, char* s2)
{
	double v1;
	double v2;

	v1 = atof(s1);
	v2 = atof(s2);
	if(v1 < v2)
		return -1;
	else if(v1 > v2)
		return 1;
	else
		return 0;
}

/*charcmp:可以处理忽略大小写及目录序列这两种情况的字符串之间的比较*/
int charcmp(char*s ,char* t)
{
	char a;
	char b;
	int ignore;
	int dir;

	ignore = (option & IGNORE) ? 1 : 0;
	dir = (option & DIR) ? 1 : 0;

	do
	{
		if(dir)
		{
			while(!isalnum(*s) && *s != ' ' && *s != '\0')
				++s;
			while(!isalnum(*t) && *t != ' ' && *t != '\0')
				++t;
		}
		a = ignore ? tolower(*s) : *s;
		++s;
		b = ignore ? tolower(*t) : *t;
		++t;
		if(a == b && a == '\0')				/*a == '\0':没有理解?*/
			return 0;
	}while(a == b);
	return a - b;
}


#define		ALLOCSIZE		10000
static char allocbuf[ALLOCSIZE];
static char* allocp = allocbuf;

/*alloc函数:从自定义的缓冲区中分配长度为n字节的空间*/
char* alloc(int n)
{
	if(allocbuf + ALLOCSIZE - allocp >= n)
	{
		allocp += n;
		return allocp - n;
	}
	else
		return 0;
}


分析:

1,设计流程:

       (a) 通过变量option来收集命令行中的所有命令,以供下面排序使用;

       (b) 通过函数readLines将输入中所有行存储起来;

       (c) 通过函数myQsort对所有的输入按照命令行参数进行排序;

       (d) 通过函数writeLines对排序后的输入打印输出;

 

2,在获取option的值时,采用上述代码中的while switch-case语句组合在可读性及扩展性上优于使用if-else语句,

       while switch-case版本:

       

	while(--argc > 0 && **(++argv) == '-')	/*获取命令行参数,用于操作*/
		while(c = *++(*argv))
			switch(c)
			{
			case 'n':
				option |= NUMERIC;
				break;
			
			case 'r':
				option |= DECR;
				break;

			case 'f':
				option |= IGNORE;
				break;

			case 'd':
				option |= DIR;
				break;

			default:
				printf("error: illegal command parameters !\n");
				return -1;
			}


if-else版本:

	if(argc == 2 && strcmp(*(argv+1), "-n") == 0)
		numeric = 1;
	if(argc == 2 && strcmp(*(argv+1), "-r") == 0)
		direction = NEGETIVE;
	if(argc == 2 && (strcmp(*(argv+1), "-rn") == 0 || strcmp(*(argv+1), "-nr") == 0))
	{
		numeric = 1;
		direction = NEGETIVE;
	}
	if(argc == 3 && ((strcmp(*(argv+1), "-n") == 0 && strcmp(*(argv+2), "-r") == 0) ||
		(strcmp(*(argv+1), "-r") == 0 && strcmp(*(argv+2), "-n") == 0) ) )
	{
		numeric = 1;
		direction = NEGETIVE;
	}


3,获取输入字符串的函数readLines:通过p = alloc(len)给长度为len的字符串分配相应的空间,通过strcpy(p, line);及lineptr[nlines++] = p;函数

                                                                     将字符串从局部变量line字符数组中拷贝到p所指的空间中,并使指针lineptr[nlines]指向本字符串。

      函数alloc:本函数是自定义的动态内存分配函数,简单,易懂,可行(当然输入量特别大时除外)。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值