c указатели на функции - PullRequest
       37

c указатели на функции

2 голосов
/ 12 января 2010

Эта программа сортирует строки в алфавитном / числовом виде в зависимости от аргументов, переданных в main.

И я сейчас работаю над этим упражнением от k & R: Добавьте опцию -f, чтобы сложить верхний и нижний регистр, чтобы во время сортировки не различались регистры; например, a и A сравнивают равными.

Хорошо ли то, что я написал в my_strcmp? И будет ли он работать хорошо в сочетании с -r и -n? (r - обратный порядок, n- числовая сортировка).

Я понял, что я спрашиваю здесь ваше мнение, поскольку на klc wiki решение представлено не так.

#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, ​​который обрабатывает случай, если каталог и сгиб равны нулю.

Тогда мы просто удаляем их, но мы должны отслеживать, если каталог равен 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;
}

Ответы [ 4 ]

3 голосов
/ 12 января 2010

Вы должны будете установить свои собственные стандарты успеха. Запишите контрольные примеры, наборы из двух строк и вывод, который они должны произвести. Проверьте их, запустив код. Не забывайте о выбросах, передавайте пустые строки и строки NULL.

2 голосов
/ 12 января 2010

Когда fold==1, my_strcmp вернет 0, когда p1 является префиксом p2. Вы можете исправить это, переместив строку if(!*p1) return 0 в начало цикла while. Кроме того, это выглядит хорошо.

Edit: Относительно вашего второго вопроса: вы находитесь на правильном пути с приращением p1 и p2 для игнорируемых символов. Однако эта функция не будет работать в режиме без фальцовки (кажется, что она вызывает себя бесконечно). (это было исправлено путем редактирования вопроса)

Я бы сделал вспомогательную функцию compareCharactes, которая сравнивала бы 2 символа с учетом регистра или без него, в зависимости от значения fold. Тогда вы можете использовать цикл while независимо от того, включен или выключен fold.

Edit2: ОК, вы продолжаете менять свой вопрос ... В любом случае, если вы воспользуетесь моим советом относительно функции compareCharacters, не будет необходимости в отдельных функциях my_strcmp и my_strcmp2. Вы могли бы просто написать while (compareCharacters(*p1, *p2)==0) {.....}

0 голосов
/ 12 января 2010

Похоже, 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 голосов
/ 12 января 2010

на первый взгляд мне кажется, что все в порядке.

Работает ли он правильно и компилируется, компилятор и операционная система намного лучше, чем я.

...