2010-01-12 181 views
2

该程序根据传递给main的参数按字母顺序/数字排序行。c函数指针

正在从事这个练习k & R现在: 添加选项-f将大写和小写叠加在一起,以便在排序过程中不区分大小写;例如,a和A比较相等。

是我在my_strcmp写的很好吗?并且它会与-r和-n结合使用吗? (r-逆序,n-数值排序)。

我想在这里问你的意见,因为在KLC维基解决方案不是这样的。

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

#define MAXBUF 10000 

#define MAXLINES 5000 
char *lineptr[MAXLINES]; 

int readlines(char *lineptr[], char buffer[], 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 reverse = 0; 
int numeric = 0; 
int fold = 0; 
int my_strcmp(char *s1, char *s2) 
{ 

    char *p1 = (reverse) ? s2 : s1; 
    char *p2 = (reverse) ? s1 : s2; 


    if(fold) { 
     while(toupper(*p1) == toupper(*p2)) { 
      p1++, p2++; 
      if(!*p1) 
       return 0; 
     } 
     return toupper(*p1) - toupper(*p2); 
    } 

    return strcmp(p1, p2); 
} 

int main(int argc, char *argv[]) 
{ 
    int nlines; 
    char buffer[MAXBUF]; 

    int i = 1; 
    for(i = 1; i < argc; i++) { 
      if(strcmp(argv[i], "-n") == 0) { 
      numeric = 1; 
      } else if(strcmp(argv[i], "-r") == 0) { 
       reverse = 1; 
      } else if(strcmp(argv[i], "-f") == 0) { 
       fold = 1; 
      } else { 
       printf("illegal argument\n"); 
      } 
    } 


    if((nlines = readlines(lineptr, buffer, MAXLINES)) >= 0) { 
     qsort((void **)lineptr, 0, nlines - 1, 
     (numeric ? (int (*)(void *, void *))numcmp : (int (*)(void *, void *))my_strcmp)); 
     writelines(lineptr, nlines); 
     getchar(); 
     return 0; 
    } else { 
      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]); 
} 

int getline(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; 
} 

#define MAXLEN 1000 
int readlines(char *lineptr[], char *buffer, int maxlines) 
{ 
    int len, nlines; 
    char *p, line[MAXLEN]; 

    nlines = 0; 
    p = buffer; 
    while ((len = getline(line, MAXLEN)) > 0) 
     if (p - buffer + len > MAXBUF) 
      return -1; 
     else { 
      line[len-1] = '\0'; /* delete newline */ 
      strcpy(p, line); 
      lineptr[nlines++] = p; 
      p += len; 
     } 
    return nlines; 
} 

void qsort(void *v[], int left, int right, int(*comp)(void *, void *)) 
{ 
    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); 
} 

#include <stdlib.h> 

int numcmp(char *p1, char *p2) 
{ 
    char *s1 = reverse ? p2 : p1; 
    char *s2 = reverse ? p1 : p2; 
    double v1, v2; 

    v1 = atof(s1); 
    v2 = atof(s2); 
    if (v1 < v2) 
    return -1; 
    else if (v1 > v2)          
    return 1;  
    else 
    return 0; 
} 

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

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

还有一个问题。我试图添加选项-d(目录顺序) - “只对字母数字和空格进行比较,确保它与-f”结合使用。“对于如何编辑my_strcmp有点困惑。这是我做过什么:

int my_strcmp(char *s1, char *s2) 
{ 

    char *p1 = (reverse) ? s2 : s1; 
    char *p2 = (reverse) ? s1 : s2; 

    if(directory) { 
     while(!isdigit(*p1) && !isspace(*p1) && !isalpha(*p1) && *p1) 
      p1++; 

     while(!isdigit(*p2) && !isspace(*p2) && !isalpha(*p2) && *p2) 
      p2++; 
    } 

    if(fold) { 
     while(toupper(*p1) == toupper(*p2)) { 
      p1++, p2++; 
      if(!*p1) 
       return 0; 
      if(directory) { 
       while(!isdigit(*p1) && !isspace(*p1) && !isalpha(*p1)) 
        p1++; 

       while(!isdigit(*p2) && !isspace(*p2) && !isalpha(*p2)) 
        p2++;   
      } 
     } 
     return toupper(*p1) - toupper(*p2); 
    } 

    return my_strcmp2(p1, p2); 
} 

但是我不敢肯定,如果它的好。

我也写了my_strcmp2,它​​处理的情况下,如果目录和fold是零。

然后我们只是strcmp的他们,但我们必须跟踪如果目录1名藏汉...

int my_strcmp2(char *s1, char *s2) 
{ 
    char *p1 = (reverse) ? s2 : s1; 
    char *p2 = (reverse) ? s1 : s2; 

    while(*p1 == *p1 && *p1) { 
     p1++; 
     p2++; 

     if(directory) { 
      while(!isdigit(*p1) && !isspace(*p1) && !isalpha(*p1) && *p1) 
       p1++; 

      while(!isdigit(*p2) && !isspace(*p2) && !isalpha(*p2) && *p2) 
       p2++; 
     } 
    } 
    return *p1 - *p2; 
} 

回答

2

当0121,,my_strcmp将返回0时,当p1是p2的前缀。您可以通过将if(!*p1) return 0行移至while循环的开头来解决此问题。除此之外,它看起来不错。

编辑: 关于你的第二个问题:你正处于正确的轨道上,对于被忽略的字符增加p1和p2。 但是,此功能在非折叠模式下不起作用(它似乎无限调用它自己)。 (这是由固定的编辑的问题)

我想使一个辅助函数compareCharactes会,比较2个字符具有或不区分大小写取决于fold值。然后,您可以使用您的while循环,无论是打开还是关闭fold

EDIT2:好的,您是不断变化的你的问题......总之,如果你把我的意见对compareCharacters功能,就没有必要单独my_strcmpmy_strcmp2功能。你可以写while (compareCharacters(*p1, *p2)==0) {.....}

0

乍看起来OK我。

它编译和做正确的事情,编译器和操作系统是比我更好的代码验证程序。

0

它看起来像my_strcmp应该工作,但我想我会做一点不同的事情。您确实有三种可能性:案例敏感,不区分大小写和数字比较。我会做这样的事情:

typedef int (*cmp_func)(void *, void *); 
cmp_func funcs[] = {strcmp, my_strcmp, numcmp}; 

enum comparison_types = { case_sensitive, case_insensitive, numeric}; 

int comparison = case_sensitive; 

// ... 

if (strcmp(argv[i], "-f")) 
    comparison = case_insensitive; 
else if (strcmp(argv[i], "-n")) 
    comparison = numeric; 

// ... 
    qsort(/* ... */, funcs[comparison]); 

利用这一点,将my_strcmp不区分大小写的比较。添加目录顺序比较将涉及添加另一个单独的函数,而不是扩大(进一步)在my_strcmp,这已经很大,并且已经做了两件不同的事情(并且与目录比较,将做三个或六个包括反向比较)。

+0

虽然当不同的标志可以组合时(或者你需要为每种可能的组合编写一个函数),但这并不会真正起作用。 – interjay 2010-01-12 19:04:41

+0

@interjay:的确,如果你可以用不同的方式组合大量的标志,这将变得笨拙。另一方面,至少对于迄今为止提出的问题,我认为这是最干净的方法。我还会注意到很多可以任意组合的标志在任何情况下最终都会导致大量的代码路径,所以这主要是您如何打包这些代码的问题。如果不同的路径可以共享大量的代码,将它们组合成单个函数可能是值得的 - 但是(例如)区分大小写和区分大小写的比较几乎不分享。 – 2010-01-12 19:16:48

3

你必须设定自己的成功标准。记下测试用例,两个字符串的集合以及他们应该产生的输出。通过运行代码验证它们。不要忘记异常值,也要传递空字符串和NULL字符串。