コマンドラインパラメータによる入力のソート


由来于《The C Programming Language》P 102 ex 5.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 !
"); return -1; } if(argc) printf("Usage: sort -dfnr
"); 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
"); return -1; } } else { printf("error: fail to get the lines of input
"); 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
", lineptr[j--]); else while(nlines-- > 0) printf("%s
", lineptr[i++]); } /*getLine: */ int getLine(char* line, int maxlen) { int i; int c; for(i = 0; i < maxlen-1 && (c = getchar()) != EOF && c != '
'; ++i) line[i] = c; if(c == '
') 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 !
"); 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:この関数はカスタムダイナミックメモリ割り当て関数で、簡単で、分かりやすく、実行可能です(もちろん入力量が特に大きい場合を除きます).