2010-01-12 4 views
2

이 프로그램은 main에 전달 된 인수에 따라 알파벳 순/숫자로 정렬합니다.c 함수 포인터

그리고이 핸드북에서 k & R : 대문자와 소문자를 함께 접어서 정렬 할 때 대소 문자 구분을하지 않도록 옵션을 추가하십시오. 예를 들어, 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를 편집하는 방법에 대해 약간 당황 스럽다. 이것은 내가 한 일입니다.

그러나 좋은지 잘 모르겠지만.

또한 디렉토리와 폴드가 0 인 경우 대소 문자를 처리하는 my_strcmp2를 작성했습니다. 그것은 나에게 확인을 보이는 첫눈에 ...

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

fold==1 일 때, my_strcmp은 p1이 p2의 접두어 일 때 0을 반환합니다. 줄 if(!*p1) return 0을 while 루프의 시작 부분으로 이동하여 문제를 해결할 수 있습니다. 그것 이외에 그것은 좋아 보인다.

편집 : 두 번째 질문에 대해 : 무시한 문자에 대해 p1과 p2를 증가 시키면 올바른 방향으로 가고 있습니다. 그러나이 함수는 비 접는 모드에서는 작동하지 않습니다 (자체를 무한히 호출하는 것처럼 보입니다). (질문에 대한 편집으로 해결되었습니다) fold 값에 따라 대소 문자 구분없이 대/소문자를 비교하지 않을 도우미 함수 compareCharactes을 만들려고합니다. 그러면 fold이 켜져 있든 없든 while 회 돌이를 사용할 수 있습니다.

편집 2 : 좋아요, 계속 질문을 변경합니다 ... 어쨌든 compareCharacters 함수에 대한 조언을받는다면 별도의 my_strcmpmy_strcmp2 함수가 필요하지 않습니다. 당신은 쓸 수있다 while (compareCharacters(*p1, *p2)==0) {.....}

0

그런 다음 우리는 단지 그들을 strcmp와, 그러나 우리는 디렉토리가 1 aswell 경우 추적 할 수 있습니다.

옳은 일을 컴파일하고 수행합니까, 컴파일러와 OS가 제가하는 것보다 훨씬 뛰어난 코드 검사기입니다.

0

그것은 my_strcmp와 같게 보인다. 그러나 나는 조금 다르게 할 것이다라고 생각한다. 대소 문자 구분, 대소 문자 구별 및 숫자 비교의 세 가지 가능성이 있습니다. , 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을 확장하는 대신 다른 별도의 함수를 추가하는 작업을 포함하며 이미 두 가지 작업을 수행합니다 (디렉토리 비교에서는 역 비교를 포함하여 세 개 또는 여섯 개가됩니다).

+0

다른 플래그를 결합 할 수있는 경우에는 실제로 작동하지 않습니다 (또는 모든 가능한 조합에 대해 함수를 작성해야 함). – interjay

+0

@interjay : 많은 수의 플래그를 다른 방법으로 결합 할 수 있다면 다루기 힘들어집니다. 다른 한편으로는, 적어도 지금까지 물어 보았던 것을 위해, 나는 그것이 가장 깨끗한 접근법이라고 생각한다. 임의로 조합 할 수있는 많은 플래그가 궁극적으로 어떤 경우에도 많은 코드 경로로 이어질 것이므로 대부분 패키지를 어떻게 포장하는지에 대한 질문입니다. 서로 다른 경로가 많은 코드를 공유 할 수 있다면이를 단일 함수로 결합하는 것이 좋습니다. 예를 들어 대소 문자를 구분하거나 대소 문자를 구분하는 비교는 거의 아무 것도 공유하지 않습니다. –

3

성공 기준을 스스로 세워야합니다. 테스트 케이스, 두 개의 문자열 세트 및 출력해야 할 결과를 적어 두십시오. 코드를 실행하여 확인하십시오. 이상 치를 잊지 말고 빈 문자열과 NULL 문자열도 전달하십시오.