プログラミング言語 C
少しだけ 関数 read_lines の コードを チェック。
char *p, line[MAX_LEN];while )((len = get_line(line, MAX_LEN))( > 0)
if (n_lines >= maxlines || (p = malloc(len)) == NULL)
return -1;
else {
line[len - 1] = '\0';
strcpy(p, line);
line_ptr[n_lines++] = p;
}
文字列を copy する 関数 strcpy は、その仮引数に ポインタを とっている (p128-129)。「関数定義の 仮引数としては、char s[] と char *s は まったく 同一である (p121)」
のだから、ここで 宣言されている 配列 line も、ポインタの p と 同じように、strcpy の 引数として 呼び出しが 可能だ、と いうことになる。
strcpy(p, line);
それから、コードの ゴシックのところは、その基本の 骨組みは、関数 strdup の コードを 適用しているようだ (p173)。
char *strdup(char *s) /* make a duplicate of s */
{
char *p; p = (char *)malloc(strlen(s) + 1); /* + 1 for '\0' */
if ( p != NULL)
strcpy(p, s);
return p;
}
これで 入出力は かたづいたから、ソートへ 進もう。
クイックソートには やや変更が 必要である。 同様に swap ルーティンにも ほんの少しだが 変更が いる。
v = lineptr の 任意の要素は 文字ポインタだから、tmp も そうあるべきで、これにより 互いに copy 可能となる。(p134)
void q_sort(char *v[], int left, int right)
{
int i, last; /* do nothing if array contains fewer that two elements */
if (left >= right)
return;
/* move partition elem to v[0] */
swap(v, left, (left + right)/2);
last = left;
for (i = left + 1; i <= right; i++) /* partition */
if (strcmp(v[i], v[left]) < 0)
swap(v, ++last, i);
swap(v, left, last); /* restore partition elem */
/* The same process is then applied recursively
to the two subsets */
q_sort(v, left, last - 1);
q_sort(v, last + 1, right);
}
void swap(char *v[], int i, int j)
{
char *tmp;
tmp = v[i];
v[i] = v[j];
v[j] = tmp;
}
完成した プログラムは 次のとおり。
/* prim_sort.c */
#include
#include
#include #define MAX_LINES 5000 /* max # lines to be sorted */
#define MAX_LEN 1000 /* max length of any input line */
char *line_ptr[MAX_LINES];
int read_lines();
int get_line();
void write_lines();
void q_sort();
void swap();
/* primitive sort program */
main()
{
int n_lines; /* numbers of input lines read */
if )((n_lines = read_lines(line_ptr, MAX_LINES))( >= 0) {
q_sort(line_ptr, 0, n_lines - 1);
write_lines(line_ptr, n_lines);
return 0;
} else {
puts("error: input too big to sort");
return -1;
}
}
int read_lines(char *line_ptr[], int maxlines)
{
int len, n_lines;
char *p, line[MAX_LEN];
n_lines = 0;
while )((len = get_line(line, MAX_LEN))( > 0)
if (n_lines >= maxlines || (p = malloc(len)) == NULL)
return -1;
else {
line[len - 1] = '\0'; /* delete newline */
strcpy(p, line);
line_ptr[n_lines++] = p;
}
return n_lines;
}
int get_line(char s[], int limit)
{
int c, i;
for (i = 0; i < limit - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
void write_lines(char *line_ptr[], int n_lines)
{
while (n_lines-- > 0)
printf("%s\n", *line_ptr++);
}
void q_sort(char *v[], int left, int right)
{
int i, last;
if (left >= right)
return;
swap(v, left, (left + right)/2);
last = left;
for (i = left + 1; i <= right; i++)
if (strcmp(v[i], v[left]) < 0)
swap(v, ++last, i);
swap(v, left, last);
q_sort(v, left, last - 1);
q_sort(v, last + 1, right);
}
void swap(char *v[], int i, int j)
{
char *tmp;
tmp = v[i];
v[i] = v[j];
v[j] = tmp;
}
コンパイルして、(ちょっと irregular だけど) code file で 確認。コマンド sort とも 比較してみる。
$cc -c prim_sort.c
$cc -o prim_sort prim_sort.o
$./prim_sort < prim_sort.c | less (q で 終了)
$sort prim_sort.c | less