通过在排序算法中调用不同的比较和交换函数,便可以实现按照不同的标准排序。通过指向函数的指针来完成。指向不同的函数实现不同的排序方式。
出现的主要错误:
1>e:\project\name\name\1.c(139): warning C4033: “alloc”必须返回值
1>e:\project\name\name\1.c(144): warning C4715: “alloc”: 不是所有的控件路径都返回值
错误原因:
语句if (nlines >= maxlines && (p = alloc(len)) == NULL)导致系统报错
- 逻辑运算符&&和||,它们有特殊的属性。由它们连接的表达式按从左往右的顺序进行求值。并且直到结果为真或假后立即停止运算。由于刚开始nlines必定小于maxlines,则对于该语句来说结果必为假。所以并没有调用alloc函数,也就没有对指针p的赋值,此时p为野指针。不能对其进行赋值操作
- 但换成nlines >= maxlines || (p = alloc(len)) == NULL就不一样了,在nlines >= maxlines显示的逻辑值为0后,系统还无法确定最终表达式的逻辑值,所以还需要继续执行剩余部分。从而调用了alloc函数,也就实现对指针p的赋值,完成了对其值的初始化。
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
#define MaxLines 5000
char *lineptr[MaxLines];
int readlines(char *lineptr[], int nlines);//当指针数组被当做参数传递给函数时,其将退化为二级指针,则意味着其会丢失掉空间大小,所以需要限定其范围
void writelines(char *lineptr[], int nlines);
void qsort(void *lineptr[], int left, int right, int(*comp)(void *, void *));
int numcmp(char *, char *);
int main(int argc, char *argv[])
{
int nlines; //读入的输入行数
int numeric = 0;//默认情况下按字典顺序对输入内容进行排序
scanf("%d", &argc);
for (int i = 1; i < argc; i++)
{
argv[i] = (char *)malloc(MaxLines * sizeof(char));
scanf("%s", argv[i]);
}
getchar();
if (argc > 1 && strcmp(argv[1], "-n") == 0) //参数个数大于1且捕获到的第二个参数为"-n",进行数值排序
numeric = 1;
if ((nlines = readlines(lineptr, MaxLines)) >= 0) {
//这里并不意味着nlines=0的时候需要参与排序,而是说这里为了方便操作
//将无输入内容一并归入有输入内容中,也就是将其当做一种正常情况。否则要多设置一个返回标志。
qsort((void **)lineptr, 0, nlines - 1,
(int(*)(void*, void*))(numeric ? numcmp : strcmp));//强制类型转换与使用三元运算符的条件表达式的结合
//若numeric = 0,按字典顺序对字符串进行排序;若numeric = 1,则对他们进行数值排序
writelines(lineptr, nlines);
return 0;
}
else {//NOTE:readline函数在输入行数超出限制范围或者没有足够的空间在放入输入内容的情况下,会返回负数。
//对于这种情况需要在显示屏上显示相应的标志
printf("input too big to sort\n");
return 1;
}
}
void writelines(char *lineptr[], int nlines)
{
int i;
for (i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
}
#define MaxLen 1000
int getline(char *, int);
char *alloc(int);
int readlines(char *lineptr[], int maxlines)
{
int len, nlines;
char *p, line[MaxLen];
nlines = 0;
while ((len = getline(line, MaxLen)) > 0)
if (nlines >= maxlines || (p = alloc(len)) == NULL)
return -1;
else {
line[len - 1] = '\0';//去掉该字符串末尾处的换行符
strcpy(p, line);
lineptr[nlines++] = p;
}
return nlines;//要注意每条路径都要有返回值
}
int getline(char *s, int MaxLength)
{
char c;
char *temps = s;
while (--MaxLength && (c = getchar()) != EOF && c != '\n')
*s++ = c;
if (c == '\n')
*s++ = c;
*s = '\0';
return s - temps;
}
#define AllocSize 100
static char allocbuf[AllocSize];
static char *allocp = allocbuf;
char *alloc(int len)
//char *place=allocbuf; 不能在函数内去声明缓存区下一个可放入字符串的指针变量
//因为这样的话,它作为局部变量,每次调用的时候都会对其进行一次初始化
//这样会导致每次返回的地址都是同一个地址
//而我们想要的是只对该地址在刚开始的时候初始化一次,同时使其对其他文件不可见
//所以我们可以将其设置为静态变量,这样它就一直可以在特定函数中使用,直到程序结束时再停止占用空间
{
if (allocbuf + AllocSize - allocp >= len) {
allocp += len;
return allocp - len;
}
else
return 0;
}
void qsort(void *v[], int left, int right, int(*comp)(void *, void *))//指针参数的类型为通用指针类型void*,因为任何类型的指针都可以转换为void*类型
//并且将它转化为原来的类型时不会丢失信息
{
//若此前numeric为1,由于comp为指向函数的指针,那么此时comp指向的是numcmp
//所以此时*comp为函数numcmp
//同理,如果numeric为0,则*comp为strcmp函数
int i, last;
void swap(void *v[], int, int);
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);
qsort(v, left, last - 1, comp);
qsort(v, last + 1, right, comp);
}
void swap(int v[], int i, int j)
{
int temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
//若采用数值排序,那么在排序的过程中,输入的字符串若为非数字的字符组成,如"aaa"。
//此时由于在将字符串转换成浮点型数的过程中,会判断该字符是否为数字,即isdigit(s[i]) (i为整数)
//所以当字符串为"aaa",转化过后的浮点数为0(初始值即为0,一直都没有累加)
int numcmp(char *s1, char *s2)
{
double v1, v2;
v1 = atof(s1);//当采用数值排序时,若输入的时非数字型字符串,如"aaa"。由于atof函数是将数字型字符串转换成相应的浮点数
//如果字符串的字符不是数字,那么在这过程中并不会产生累加,也就是说结果依旧是初值0。所以返回的结果也就为0。
v2 = atof(s2);
if (v1 < v2)
return -1;
else if (v1 > v2)
return 1;
else
return 0;
}
int strcmp(char *s1, char *s2)
{
for (; *s1 == *s2; s1++, s2++)
if (*s1 == '\0')
return 0;
return *s1 - *s2;
}
衍生问题:关于mallo函数调用堆空间的问题
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char *copy(char *s)
{
char *t=malloc(strlen(s)+1);
char *ptr=s;
int i=0;
do {
t[i++]=*ptr++;
}
while(*ptr!='\0');
t[i] = '\0';
return t;//返回指向本地堆空间的指针,很容易导致空间泄露,如果计算机忘记释放其内存
//因为将该指针传递的时候,只会将其当做一个非常量参数,会遗漏其空间大小
//解决方案待定!!!
}
int main()
{
const char *s="hello ads"; //pass a pointer to char which should not be changed ,we should declare it const
char *b=copy(s);//literals strings are really arrays of character,so the array decays to a pointer when it is passed
//to a function ,so the information regarding its size is "lost"
printf("%s\n",b);
free(b);
return 0;
}
该问题参考网址:https://stackoverflow.com/questions/10148357/mallocsizeofs-allocates-less-memory-than-expected