オプション付きソートプログラム
K&R本 演習5-14、演習5-15
sortを変更して分類を逆方向にすることを指示する-rというフラグを取り扱えるようにせよ。-rは-nと同時に使えなければならない
分類において、大文字と小文字の区別をなくしてしまうためのオプション-fを加えよ。これによって、大文字と小文字のデータは一緒に分類されるから、aとAは、比較上は同じになる。
sort処理ですね。行を読み込む必要があるので、前回作ったreadlines関数をそのまま利用したいと思います。
ちなみにsort関連の演習5-16と5-17は設問の意味が良くわからなかったのでスルー。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define LINEMAX 100 #define LINESMAX 5000 int strcmp_lower (char *s1,char *s2); void swap(void **v,int i,int j); int readlines (FILE *fh,char **lines,int size); int mynumcmp (char *v1,char *v2); int mynumcmpr (char *v1,char *v2); int mystrcmp (char *a,char *b); int mystrcmpr (char *a,char *b); int mystrcmp_lower (char *a,char *b); int mystrcmp_lowerr (char *a,char *b); void myqsort(void *v[],int left,int right,int (*comp)(void *,void *)); void swap(void **v,int i,int j) { void *work; work = v[i]; v[i] = v[j]; v[j] = work; } int mynumcmp (char *v1,char *v2) { double a = atof(v1); double b = atof(v2); if ( a > b ) return 1; if ( a < b ) return -1; return 0; } int mynumcmpr (char *v1,char *v2) { double a = atof(v1); double b = atof(v2); if ( b > a ) return 1; if ( b < a ) return -1; return 0; } int mystrcmp (char *a,char *b) { return strcmp(a,b); } int mystrcmpr (char *a,char *b) { return strcmp(b,a); } int mystrcmp_lower (char *a,char *b) { return strcmp_lower(a,b); } int mystrcmp_lowerr (char *a,char *b) { return strcmp_lower(b,a); } // 大文字小文字区別しないstrcmp int strcmp_lower (char *s1,char *s2) { while ( tolower(*s1) == tolower(*s2) ) { if ( *s1 == '\0' ) { return 0; } *s1++; *s2++; } return *s1 - *s2; } // K&Rに提示されているものを参考に書き換え void myqsort(void *v[],int left,int right,int (*comp)(void *,void *)) { int i,last; if ( left >= right ) { return; } swap(v,left,(left+right) / 2); last = left; for(i=left+1;i<=right;++i) { if ((*comp)(v[i],v[left]) < 0) { swap(v,++last,i); } } swap(v,left,last); myqsort(v,left,last-1,comp); myqsort(v,last+1,right,comp); } int readlines (FILE *fh,char **lines,int size) { int linenum = 0; size_t len; size_t linelen = 0; char str[LINEMAX]; char *p = NULL; int add = 1; while( fgets(str,sizeof(str),fh) != NULL ) { linelen += len = strlen(str); add = (str[len-1] == '\n') ? 1 : 0; p = (char *)realloc(p,linelen+1); if ( p == NULL ) { return EOF; } strcpy_s(p+linelen-len,len+1,str); if ( add ) { if ( linenum == size ) { break; } lines[linenum++] = p; linelen = 0; p = NULL; } } return linenum; } int main (int argc,char *argv[]) { char *lines[LINESMAX]; int linenum; int reverse = 0; int numeric = 0; int lower = 0; int i; int (*comp)(void *,void *) = mystrcmp; // コマンドラインオプションの処理 if ( argc > 1 ) { while(--argc){ if ( **++argv == '-' ) { if ( strlen(*argv) > 2 ) { printf("unknown option: %s\n",++*argv); break; } switch(*++*argv){ case 'f': // 小文字にしてソートする lower = 1; break; case 'n': // 数値順にソートする numeric = 1; break; case 'r': // 逆順にソートする reverse = 1; break; default: printf("unknown option: %s\n",*argv); break; } } } } // 比較関数の振り分け。ちょっと微妙? if ( reverse ) { if ( lower ) { comp = mystrcmp_lowerr; } else if ( numeric ) { comp = mynumcmpr; } else { comp = mystrcmpr; } } else { if ( lower ) { comp = mystrcmp_lower; } else if ( numeric ) { comp = mynumcmp; } } linenum = readlines(stdin,lines,LINESMAX); if ( linenum == EOF ) { puts("読み込みエラー"); return 1; } myqsort(lines,0,linenum-1,comp); for(i=0;i<linenum;i++){ printf("%s",lines[i]); } return 0; }
これほど長いプログラムは今回が初めてですね。本格的って感じがします。
$ cat main.c | main -f -r (中略) void swap(void **v,int i,int j); void swap(void **v,int i,int j) { void myqsort(void *v[],int left,int right,int (*comp)(void *,void *)); void myqsort(void *v[],int left,int right,int (*comp)(void *,void *)) { int strcmp_lower (char *s1,char *s2); int strcmp_lower (char *s1,char *s2) { int readlines (FILE *fh,char **lines,int size); int readlines (FILE *fh,char **lines,int size) { int mystrcmpr (char *a,char *b); int mystrcmpr (char *a,char *b) { int mystrcmp_lowerr (char *a,char *b); int mystrcmp_lowerr (char *a,char *b) { int mystrcmp_lower (char *a,char *b); (中略)
とまあこのように複数のオプションの指定も可能です。