100 Days of Code-day36-灵活排序(集大成于一体)

添加字段处理能力,因此可以对行内的字段进行排序,每个字段根据一组独立的选项进行排序。 ( K&R Book 的索引使用 -df 用于索引类别和 -n 用于页码进行排序

关于numcmp函数的修改:

由于此时传入的字符串s1,s2并不是像之前一样,只包含数字,或者只包含大小写字母。那么根据题目的要求,根据行内的不同字段进行排序,那么如果进行数字排序,那么我们就需要从每个字符串中。抽取出我们想要的那段只含有数字的子字符串(substring),然后对其进行比较。
下面是substr函数,主要对其中一个语句做重点解释。

void substr(char *s, char *str,int maxstr)
{
	int i, j, len;
	extern int pos1, pos2;

	len = strlen(s);

	if (pos2 > 0 && len > pos2)	//当排序字段的结束位置大于0,且字符串的长度超出结束位置限制范围
		len = pos2;	//忽略超出范围的字符
	else if (pos2 > 0 && len < pos2)//但如果其长度小于结束位置,那么该程序就没有继续进行下去的必要了,直接停止
		error("substr: string too short");
	for (j = 0, i = pos1; i < len && len < maxstr + pos1; i++, j++)
		str[j] = s[i];
	str[j] = '\0';
}

该语句执行的是将源字符串s中的部分字符拷贝到是str数组中。

for (j = 0, i = pos1; i < len && len < maxstr + pos1; i++, j++)
		str[j] = s[i];

相关思路:K&R中的对于substr的声明与该函数的定义不一致。因为在定义中缺少了一个参数。我们下面看看这个参数maxstr的意义。它关联到子字符串是否会越界的问题。
在这里插入图片描述
在这里插入图片描述


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

#define NUMERIC  1 /* numeric sort */
#define DECR 2 /* sort in decreasing order */
#define FOLD 4 /* fold upper and lower case */
#define MDIR 8 /* directory order */
#define LINES 100 /* maximum number of lines to be sorted */
#define MaxLen 100

int charcmp(char *, char *);
void error(char *);
int numcmp(char *, char *);
void readargs(int argc, char *argv[]);
int readlines(char *lineptr[], int maxlines);
void myqsort(void *v[], int left, int right, int(*comp)(void *, void *));
void writelines(char *lineptr[], int nlines, int order);

int option = 0;

int pos1 = 0; /* field begining with pos 1 */
int pos2 = 0;  /* ending just before pos 2 */
//那么在这个例子中pos1就是排序字段的起始位置,而pos2就是排序字段的结束位置

/* Sort input line */

int main(int argc, char *argv[])
{
	char *lineptr[LINES]; /* pointer to text lines */
	int nlines;  /* number of input lines read */
	int rc = 0;

	scanf("%d\n", &argc);
	for (int i = 1; i < argc; i++)
	{
		argv[i] = (char *)malloc(MaxLen * sizeof(char));
		scanf("%s", argv[i]);
	}
	getchar();

	readargs(argc, argv);
	if ((nlines = readlines(lineptr, LINES)) > 0)
	{
		if (option & NUMERIC)
			myqsort((void **)lineptr, 0, nlines - 1, (int(*)(void *, void *))numcmp);
		else
			myqsort((void **)lineptr, 0, nlines - 1, (int(*)(void *, void *))charcmp);

		writelines(lineptr, nlines, option & DECR);
	}
	else
	{
		printf("input too big to sort \n");
		rc = -1;
	}

	return rc;
}

/* readargs: read programs argument */

void readargs(int argc, char *argv[])
{
	int c;
	int atoi(char *);

	while (--argc > 0 && (c = (*++argv)[0]) == '-' || c == '+')
	{//如果输入的参数的第一个字符为'-',或者为'+'
		if (c == '-' && !isdigit(*(argv[0] + 1)))//首先确定该字符为'-',如果是,那么与此同时看接下来的字符是否为数字
			while (c = *++argv[0])//如果不是,那么就要根据相应的命令字符,决定具体的排序方式
				switch (c)
				{
				case 'd': /* directory order */
					option |= MDIR;
					break;
				case 'f':
					/* fold upper and lower */
					option |= FOLD;
					break;
				case 'n':
					/* numeric sort */
					option |= NUMERIC;
					break;
				case 'r':
					option |= DECR;
					break;
				default:
					printf("sort: illegal option %c \n", c);
					error("Usage: sort -dfnr [+pos1] [-pos2]");
					break;
				}
		else if (c == '-')		//如果'-'之后是数字,将其设置为排序字段的结束位置
			pos2 = atoi(argv[0] + 1);
		else if ((pos1 = atoi(argv[0] + 1)) < 0)  //当输入参数的第一个字符为'+'时,将其设置为排序字段的起始位置												
			error("Usage: sort -dfnr [+pos1][-pos2]");//并且看之后的字符是否小于0,如果小于就报错
	}
	if (argc || pos1 > pos2)//退出的时候,argc必须等于0,并且起始位置pos1不能大于pos2
		error("Usage: sort -dfnr [+pos1] [-pos2]");
}

/* The source file numcmp.c */

#include<math.h>
#include<ctype.h>
#include<string.h>
#define MAXSTR 100

void substr(char *s, char *t, int maxstr);

/* numcmp: compare s1 and s2 numerically */
//由于此时传入的字符串s1,s2并不是像之前一样,只包含数字,或者只包含大小写字母
//那么根据题目的要求,根据行内的不同字段进行排序,那么如果进行数字排序,那么我们就需要从每个字符串中
//抽取出我们想要的那段只含有数字的子字符串(substring),然后对其进行比较。
int numcmp(char *s1, char *s2)
{
	double v1, v2;
	char str[MAXSTR];//用来存储从源字符串s1,s2中抽取出来的子字符串
	//现在我们不能像之前直接将字符串转化为对应的数字,因为现在的字符串已经不是“单纯”的数字字符串
	//此时有两个选择
	//第一个,修改atof函数的调用接口,新增加两个参数,分别是排序字段的起始位置pos1和结束位置pos2
	//第二个,新增加一个函数提取出子字符串,然后用atof函数将该子字符串转化为对应的数字
	//相较之下,第二个选择更为简便,因为对于像atof这样常用的函数的调用接口,如果对其修改会带来许多问题
	//这样即使解决了问题,也会使得程序变得更为冗长复杂
	substr(s1, str, MAXSTR);
	v1 = atof(str);

	substr(s2, str, MAXSTR);
	v2 = atof(str);

	if (v1 < v2)
		return -1;
	else if (v1 > v2)
		return 1;
	else
		return 0;
}

#define FOLD 4 /* fold upper and lower cases */
#define MDIR 8 /* directory order */

/* charcmp: return < 0 if s < t, 0 if s =t, >0 if s > t */
int charcmp(char *s, char *t)//为什么输入换行符会报错,a和b变量未被初始化,在输入换行符时。
//为什么输入换行符会报错,a和b变量未被初始化,在输入换行符时。
//因为在readlines函数中会将输入字符串中的换行符去掉,所以在只输入换行符的情况下,最终strlen函数读取到的字符串长度为0
//所以没有办法进行对临时变量a,b的赋值操作,那么由于两个临时变量的初始值为乱码,非有效值,没有初始化,在两者进行比较时会出现问题
{//增加了字段处理功能,这使得charcmp可以根据输入命令以及相应限定范围内的子字符串,对源字符串进行排序
	char a, b;
	int i, j, endpos;

	extern int option, pos1, pos2;
	int fold = (option & FOLD) ? 1 : 0;
	int dir = (option & MDIR) ? 1 : 0;

	i = j = pos1;

	if (pos2 > 0)
		endpos = pos2;
	else if ((endpos = strlen(s)) > strlen(t))
		endpos = strlen(t);

	do
	{
		if (dir)
		{
			while (i < endpos && !isalnum(s[i]) && s[i] != ' ' && s[i] != '\0')
				s[i] != ' ' && s[i] != '\0';
			i++;
			while (j < endpos && !isalnum(t[j]) && t[j] != ' ' && t[j] != '\0')
				t[j] != ' ' && t[j] != '\0';
			j++;
		}
		if (i < endpos && j < endpos)//当两字符串均小于排序字段的结束位置时,对它们的各字符进行逐一比较
		{
			a = fold ? tolower(s[i]) : s[i];
			i++;
			b = fold ? tolower(t[j]) : t[j];
			j++;

			if (a == b && a == '\0')
				return 0;
		}
	} while (a == b && i < endpos && j < endpos);

	return a - b;
}

/* The source file substr.c */

#include<string.h>
void error(char *);

/* substr: get a substring of S and put in str */

void substr(char *s, char *str,int maxstr)
{
	int i, j, len;
	extern int pos1, pos2;

	len = strlen(s);

	if (pos2 > 0 && len > pos2)	//当排序字段的结束位置大于0,且字符串的长度超出结束位置限制范围
		len = pos2;	//忽略超出范围的字符
	else if (pos2 > 0 && len < pos2)//但如果其长度小于结束位置,那么该程序就没有继续进行下去的必要了,直接停止
		error("substr: string too short");
	for (j = 0, i = pos1; i < len && len < maxstr + pos1; i++, j++)
		str[j] = s[i];
	str[j] = '\0';
}

/* error: print error message and exit */

void error(char *s)
{
	printf("%s \n", s);
	exit(1);
}


void swap(void *v[], int i, int j)
{
	void *temp;

	temp = v[i];
	v[i] = v[j];
	v[j] = temp;
}

/* myqsort: sort v[left] ... v[right] into increasing order */

void myqsort(void *v[], int left, int right, int(*comp)(void *, void *))
{
	int i, last;
	void swap(void *v[], int, int);

	if (left >= right)  /* do nothing if array contains */
		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);
}


#define MAXLEN 1000  /* max length of any input line  */
int mgetline(char *, int);
char *alloc(int);

/* readlines: read input lines */
int readlines(char *lineptr[], int maxlines)
{
	int len, nlines;
	char *p, line[MAXLEN];

	nlines = 0;
	while ((len = mgetline(line, MAXLEN)) > 0)
		if (nlines >= maxlines || (p = alloc(len)) == NULL)
			return -1;
		else
		{
			line[len - 1] = '\0'; /* delete newline */
			strcpy(p, line);
			lineptr[nlines++] = p;
		}
	return nlines;
}

/* writelines: write output lines */
/* writelines: write output lines */
void writelines(char *lineptr[], int nlines, int decr)
{
	int i;
	if (decr) /* print in decreasing order */
		for (i = nlines - 1; i >= 0; i--)
			printf("%s\n", lineptr[i]);
	else
		for (i = 0; i < nlines; i++)
			printf("%s\n", lineptr[i]);
}


#define ALLOCSIZE 10000   /* size of available space */

static char allocbuf[ALLOCSIZE]; /* storage for alloc */
static char *allocp = allocbuf;  /* next free position */

char *alloc(int n)   /* return pointer to n characters */
{
	if (allocbuf + ALLOCSIZE - allocp >= n)
	{
		allocp += n;
		return allocp - n; /* old p */
	}
	else    /* not enough room */
		return 0;
}

void afree(char *p)  /* free storage pointed to by p */
{
	if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
		allocp = p;
}


/* mgetline: read a line into s,return length */

int mgetline(char *s, int lim)
{
	int c, i;

	for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
		s[i] = c;
	if (c == '\n')
	{
		s[i] = c;
		++i;
	}

	s[i] = '\0';
	return i;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值