Exercise 5-15. Add the option
-fto fold upper and lower case together, so that case distinctions are not made during sorting; for example,aandAcompare equal.
Add a fold flag. When set, the comparison function converts both characters to lowercase before comparing. The key: don’t modify the strings themselves — do the case conversion only inside the comparison function, so the original strings are printed unchanged.
Key Addition to the Sort from Exercise 5-14
/* K&R Exercise 5-15 — sort with -f (fold case), builds on Ex 5-14
* Compile: gcc -ansi -Wall ex5-15.c -o mysort
* Usage: ./mysort [-n] [-r] [-f] */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXLINES 5000
#define MAXSTORE 100000
static char store[MAXSTORE];
static char *lineptr[MAXLINES];
static int numeric = 0, reverse = 0, fold = 0;
int my_getline(char *s, int lim)
{
char *p = s; int c;
while (--lim > 0 && (c = getchar()) != EOF && c != '\n') *p++ = c;
if (c == '\n') *p++ = c;
*p = '\0';
return (int)(p - s);
}
int readlines(void)
{
int len, n = 0;
char *sp = store, line[1024];
while ((len = my_getline(line, sizeof line)) > 0 && n < MAXLINES
&& sp + len < store + MAXSTORE) {
line[len-1] = '\0';
strcpy(sp, line);
lineptr[n++] = sp;
sp += len;
}
return n;
}
void writelines(char *lp[], int n) { while (n-- > 0) printf("%s\n", *lp++); }
int numcmp(const char *s1, const char *s2)
{
double v1 = atof(s1), v2 = atof(s2);
return (v1 < v2) ? -1 : (v1 > v2) ? 1 : 0;
}
/* Case-folding string comparison */
int foldcmp(const char *s1, const char *s2)
{
for ( ; tolower((unsigned char)*s1) == tolower((unsigned char)*s2); s1++, s2++)
if (*s1 == '\0')
return 0;
return tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
}
int compare(const void *a, const void *b)
{
const char *s1 = *(const char **)a, *s2 = *(const char **)b;
int res;
if (numeric) res = numcmp(s1, s2);
else if (fold) res = foldcmp(s1, s2);
else res = strcmp(s1, s2);
return reverse ? -res : res;
}
int main(int argc, char *argv[])
{
int n, i;
for (i = 1; i < argc; i++)
if (argv[i][0] == '-') {
char *p;
for (p = argv[i]+1; *p; p++) {
if (*p == 'n') numeric = 1;
if (*p == 'r') reverse = 1;
if (*p == 'f') fold = 1;
}
}
if ((n = readlines()) > 0) {
qsort(lineptr, n, sizeof(char *), compare);
writelines(lineptr, n);
}
return 0;
}
Test It
printf "Banana\napple\nCherry\n" | ./mysort # B before a (ASCII order)
printf "Banana\napple\nCherry\n" | ./mysort -f # apple Banana Cherry
printf "Banana\napple\nCherry\n" | ./mysort -f -r # Cherry Banana apple
What This Exercise Teaches
- Non-destructive transformation in comparators — apply
toloweronly during comparison; the original strings are preserved for output tolowerwith cast —tolower((unsigned char)c)avoids undefined behaviour whencharis signed andcis negative (e.g., an accented character)- Flag combinations —
-fand-rcompose correctly because thecomparewrapper applies both transformations sequentially
Set Up Your C Environment
← Exercise 5-14 |
Chapter 5 Solutions |
Exercise 5-16 →
Book: The C Programming Language, 2nd Ed — Kernighan & Ritchie