Страницы

Translate

понедельник, 23 сентября 2013 г.

Exercise 5.14. Modify the sort program to handle a -r flag, which indicates sorting in reverse (decreasing) order



Exercise 5.14. Modify the sort program to handle a -r flag, which indicates sorting in reverse (decreasing) order. Be sure that -r works with -n.


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

#define MAXLINES 5000 //max lines to be sorted
#define BUFSIZE 5000

char *lineptr[MAXLINES];

int readlines(char *lineptr[], char *buf, int maxlines);
void writelines(char *lineptr[], int nlines, int order);
void sort(void *v[], int left, int right, 
            int (*comp) (void *, void *));
int numcmp(char *s1, char *s2);

/* sort input lines */
int main(int argc, char *argv[])
{
    int nlines; //number of input lines read
    int numeric, order; // 1 if numeric sort & order sort
    char buf[BUFSIZE];
    
    numeric = 0;
    order = 0;
    
    if(argc > 2)
    {
        if(strcmp(argv[1], "-n") == 0)
            numeric = 1;
        if(strcmp(argv[2], "-n") == 0)
                numeric = 1;
        if(strcmp(argv[1], "-r") == 0)
            order = 1;
        if(strcmp(argv[2], "-r") == 0)
                order = 1;
    } 
    if(argc > 1)
    {
        if(strcmp(argv[1], "-n") == 0)
            numeric = 1;
        if(strcmp(argv[1], "-r") == 0)
            order = 1;
    }
    if((nlines = readlines(lineptr,buf, MAXLINES)) >= 0)
    {
        sort((void **)lineptr, 0, nlines - 1, 
            (int (*) (void*, void*)) (numeric ? numcmp : strcmp));
        writelines(lineptr, nlines, order);
        return 0;
    }
    else
    {
        printf("input too big to sort\n");
        return 1;
    }
}

/* sort: sort v[left]...v[right] into increasing order */
void sort(void *v[], int left, int right,
            int (*comp) (void *, void *))
{
    int i, last;
    void swap(void *v[], int i, int j);
    
    if(left >= right) //do nothing if array contains
        return;       //fewer than two elements
    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);
    sort(v, left, last - 1, comp);
    sort(v, last + 1, right, comp);
}

#include <stdlib.h>

/* numcmp: compare s1 and s2 numericalli */
int numcmp(char *s1, char *s2)
{
    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;
}

#define MAXLEN 1000 //max lenght of any input line


int getlin(char *, int);

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

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

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

int getlin(char *l, int lim)
{
    int c;
    char *tmp = l;
    
    for(; --lim > 0 && (c=getchar()) != EOF && c!='\n'; l++)
        *l = c;
    if(c=='\n')
        *l++ = c;
    *l = '\0';
    return l - tmp;
}

Result:


воскресенье, 15 сентября 2013 г.

Exercise 5-13. Write the program tail, which prints the last n lines of its input. By default, n is set to 10, let us say, but it can be changed by an optional argument so that 

tail -n 

prints the last n lines. 
The program should behave rationally no matter how unreasonable the input or the value of n. Write the program so it makes the best use of available storage; lines should be stored as in the sorting program of Section 5.6, not in a two-dimensional array of fixed size.



/* tail */

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

#define MAXLINES 5000 //max lines 
#define BUFSIZE 5000
#define reserve 10

char *lineptr[MAXLINES]; //pointers to text lines

int readlines(char *lineptr[], char *buf, int nlines);
void writelines(char *lineptr[], int n, int nlines);

/* prints the last n lines */
int main(int argc, char **argv)
{
    int nlines, n; //number of input lines read && last lines
    char buf[BUFSIZE];  
    
    if(argc > 2)
    {
        printf("ERROR: invalid parametrs\n");
        return 1;
    }
    if(argc == 2 && atoi(*++argv) < 0)
        n = -(atoi(*argv));
    else
    {
        printf("wrong parameters, to use default\n");
        n = reserve;
    }
    if((nlines = readlines(lineptr, buf, MAXLINES)) >= 0)
    {
        printf("\n");
        writelines(lineptr, n, nlines);
        return 0;
    }
    else
    {
        printf("error: input too big to sort\n");
        return 1;
    }
}

#define MAXLEN 1000 //max lenght of any input line

int getlin(char *, int);

/* readlines: read input lines */
int readlines(char *lineptr[], char *buf, int maxlines)
{
    int len, nlines;
    char line[MAXLEN];
    char *p = buf;     
    char *bufstop = buf + BUFSIZE;
    
    nlines = 0;
    while((len = getlin(line, MAXLEN)) > 0)
    {
        if(nlines >= maxlines || p + len > bufstop)
            return -1;
        else
        {
            line[len - 1] = '\0'; //delete newline
            strcpy(p, line);
            lineptr[nlines++] = p;
            p += len;
        }
    }
    return nlines;
}

/* writelines: write output lines */
void writelines(char *lineptr[], int n, int nlines)
{
    int i;
    
    if(n > nlines)
    {
        n = nlines;
        printf("not enough lines\n");
    }
    for(i = nlines - n ; n > 0; n--)
        printf("%s\n", lineptr[i++]);
}

int getlin(char *l, int lim)
{
    int c;
    char *tmp = l;
    
    for(; --lim > 0 && (c=getchar()) != EOF && c!='\n'; l++)
        *l = c;
    if(c=='\n')
        *l++ = c;
    *l = '\0';
    return l - tmp;
}




Exercise 5.12. Extend entab and detab to accept the shorthand entab -m +n 


Exercise 5.12. Extend entab and detab to accept the shorthand entab -m +n to mean tab stops every n columns, starting at column m. Choose convenient (for the user) default behavior.


/*entab*/

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

#define TAB 8

void entab(int m, int n);

int main(int argc, char **argv)
{
    int pos, tabinc;
    
    if(argc > 3)
    {
        printf("ERROR, wrong parameters\n");
        return 1;
    }
    if(argc <=1)
        entab(0, TAB);
    else if(argc == 3 && *(argv+1) == '-' && *(argv+2) == '+')
    {
        pos = atoi(*(argv+1));
        tabinc = atoi(*(argv+2));
        entab(pos, tabinc);
    }
    else
    {
        pos = atoi(*(argv+1));
        entab(pos, TAB);
    }
    return 0;
}
    
void entab(int m, int n)
{
    int c, ntab, nspace, symv;
        
    symv=1;
    ntab=0;
    nspace=0;
    m = -m;
    
    while((c=getchar()) != EOF)
    {
        if(m-- > 0)
            putchar(c);
        else
            symv++;
            if(c==' ')
            {
                if(symv < (-1*m))
                    putchar(c);
                if(symv % n == 0)
                {
                    ntab++;
                    nspace=0;
                }
                else
                    nspace++;
            }
            else
            {
                while(ntab>0)
                {
                    putchar('\t');
                    ntab--;
                }
                if(c=='\t')
                {
                    nspace=0;
                    putchar('\t');
                    symv=symv + (n- (symv % n));
                }
                else
                {
                    while(nspace>0)
                    {
                        putchar(' ');
                        nspace--;
                    }
                    putchar(c);
                    if(c=='\n')
                    {
                        symv=0;
                        ntab=0;
                        nspace=0;
                    }
                }
            }
    }
}


*detab*/

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

#define TAB 8

void detab(int m, int n);

int main(int argc, char *argv[])
{
    int pos, tabinc;
    
    if(argc > 3)
    {
        printf("ERROR, wrong parametrs\n");
        return 1;
    }
    if(argc <=1)
        detab(0, TAB);
    else if(argc == 3 && argv[1] == '-' && argv[2] == '+')
    {
        pos = atoi(argv[1]);
        tabinc = atoi(argv[2]);
        detab(pos, tabinc);
    }
    else
    {
        pos = atoi(argv[1]);
        detab(pos, TAB);
    }
    return 0;
}


void detab(int m, int n)
{    
    int c, i, symvol, ntab;
    
    m = -m;
    symvol=1;
    while((c=getchar()) != EOF)
    {
        if(m-- > 0)
            putchar(c);
        else
            if(c=='\t')
            {
                ntab = n - (symvol-1);
                for(i=0; i<ntab; i++)
                    putchar(' ');
            }
            else if(c=='\n')
            {   
                symvol=0;
                printf("\n");
            }
            else
                putchar(c);
                symvol++;
                if(symvol == n)
                    symvol=0;
        }
}


Exercise 5.11. Modify the program entab and detab (written as exercises in Chapter 1) to accept a list of tab stops as arguments.

Exercise 5.11. Modify the program entab and detab (written as exercises in Chapter 1) to accept a list of tab stops as arguments. Use the default tab settings if there are no arguments.



/*entab*/

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


int main(int argc, char **argv)
{
    int c, ntab, nspace, symv;
    
    if(argc != 2)
    {
        printf("ERROR, wrong parameters\n");
        return 1;
    }
    symv=1;
    ntab=0;
    nspace=0;
    while((c=getchar()) != EOF)
    {
        symv++;
        if(c==' ')
        {
            if(symv % atoi(*(argv+1)) == 0)
            {
                ntab++;
                nspace=0;
            }
            else
                nspace++;
        }
        else
        {
             while(ntab>0)
            {
                putchar('\t');
                ntab--;
            }
            if(c=='\t')
            {
                nspace=0;
                putchar('\t');
                symv=symv+ (atoi(*(argv+1))- (symv % atoi(*(argv+1))));
            }
            else
            {
                while(nspace>0)
                {
                    putchar(' ');
                    nspace--;
                }
                putchar(c);
                if(c=='\n')
                {
                    symv=0;
                    ntab=0;
                    nspace=0;
                }
            }
        }
    }
    return 0;
}


/*detab*/

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

int main(int argc, char *argv[])
{
    int c, i, symvol, ntab;
    
    if(argc != 2 || atoi(argv[1]) <= 0)
    {
        printf("ERROR, wrong parametrs\n");
        return 1;
    }
    symvol=1;
    while((c=getchar()) != EOF)
    {
        if(c=='\t')
        {
            ntab = atoi(argv[1]) - (symvol-1);
            for(i=0; i<ntab; i++)
                putchar(' ');
            symvol=0;
        }
        else if(c=='\n')
        {   
            symvol=0;
            printf("\n");
        }
        else
            putchar(c);
            symvol++;
            if(symvol==atoi(argv[1]))
                symvol=0;
    }
    return 0;
}


Exercise 5.9. Rewrite the routines day_of_year and month_day with pointers instead of indexing.Exercise 5.9. Rewrite the routines day_of_year and month_day with pointers instead of indexing.

Exercise 5.9. Rewrite the routines day_of_year and month_day with pointers instead of indexing.


/* day_of_year */
int day_of_year(int year, int month, int day)
{
    int leap;
    char *p;
    
    if(year < 1)
        return -1;
    leap = (year%4 == 0 && year%100 != 0) || year%400 == 0;
    p = daytab[leap];
    if(month < 1 || month > 12)
        return -1;
    if(day < 1 || day > *(p + month))
        return -1;
    while(month > 0)
    {
        day += *p++;
        month--;
    }
    return day;
}


/* month_day */
void month_day(int year, int yearday, int *pmonth, int *pday)
{
    int leap;
    char *p;
    char *tmp;
    
    if(year < 1 || yearday < 1)
    {
        *pmonth = -1;
        *pday = -1;
        return;
    }
    leap = (year%4 == 0 && year%100 != 0) || year%400 ==  0;
    p = daytab[leap];
    tmp = p;
    if(leap == 1 && yearday > 366)
    {
        *pmonth = -1;
        *pday = -1;
        return;
    }
    if(leap == 0 && yearday > 365)
    {
        *pmonth = -1;
        *pday = -1;
        return;
    }  
    while(yearday > *p++)
    {
        yearday -= *p;
    }
    *pmonth = p - tmp;
    *pday = yearday;
}

Exercise 5.10. Write the program expr, which evaluates a reverse Polish expression from the command line.

Exercise 5.10. Write the program expr, which evaluates a reverse Polish expression from the command line, where each operator or operand is a separate argument.
For example, expr 2 3 4 + *
                            evaluates 2 * (3+4)

/* expr */
#include <stdio.h>
#include <stdlib.h> //for atof()
#include <math.h>

#define MAXOP 100 //max size of operand or operator
#define NUMBER '0' //signal that a number was found

int getop(char[]);
void ungetch(char[]);
void push(double);
double pop(void);

int main(int argc, char *argv[])
{
    double op2;
    char s[MAXOP];
    
    while(--argc > 0)
    {
        ungetch(" ");
        ungetch(*++argv);
        switch(getop(s))
        {
            case NUMBER:
                push(atof(s));
                break;
            case '+':
                push(pop() + pop());
                break;
            case '*':
                push(pop() * pop());
                break;
            case '-':
                op2 = pop();
                push(pop() - op2);
                break;
            case '/':
                op2 = pop();
                if(op2 != 0.0)
                    push(pop() / op2);
                else
                    printf("error: zero devisior\n");
                break;
            default:
                printf("error: unknown command %s\n", s);
                argc = 1;
                break;
        }
    }
    printf("\t%.8g\n", pop());
    return 0;
}

#define MAXVAL 100 //maximum depth of val stack

double val[MAXVAL]; //value stack
int sp = 0; //next free stack position

/* push: push f into value stack */
void push(double f)
{
    if(sp < MAXVAL)
        val[sp++] = f;
    else
        printf("error: stack full, can`t push %g\n", f);
}

/* pop: pop and return top value from stack */
double pop(void)
{
    if(sp > 0)
        return val[--sp];
    else
    {
        printf("error: stack empty\n");
        return 0.0;
    }
}

#include <ctype.h>

int getch(void);
void ungetch(char []);


/* getop: get next character ot numeric operand */
int getop(char s[])
{
    int i, c;
    while((s[0] = c = getch()) == ' ' || c == '\t')
        ;
    s[1] = '\0';
    if(!isdigit(c) && c != '.') // not a nember
        return c; 
    i = 0;
    if(isdigit(c)) //collect integer part
        while(isdigit(s[++i] = c = getch()))
            ;
    if(c == '.') //collect fraction part
        while(isdigit(s[++i] = c = getch()))
            ;
    s[i] = '\0';
    return NUMBER;
}

#define BUFSIZE 100

char buf[BUFSIZE];  //buffer for ungetch;
int bufp = 0; //next free position in bud

int getch(void) // get a (possibly pushed-back) character  
{
   return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(char argv[]) // push character back on input
{
    if(bufp >= BUFSIZE)
        printf("ungetch: too many characnters\n");
    else
        buf[bufp++] = *argv;
}

Result:

среда, 11 сентября 2013 г.

Exercise 5.8. There is no error checking in day_of_year or month_day. Remedy this defect.

Exercise 5.8. There is no error checking in day_of_year or month_day. Remedy this defect.


/* day_of_year */
int day_of_year(int year, int month, int day)
{
    int i, leap;
    
    if(year < 1)
        return -1;
    leap = (year%4 == 0 && year%100 != 0) || year%400 == 0;
    if(month < 1 || month > 12)
        return -1;
    if(day < 1 || day > daytab[leap][month])
        return -1;
    for(i = 1; i < month; i++)
        day += daytab[leap][i];
    return day;
}


/* month_day */
void month_day(int year, int yearday, int *pmonth, int *pday)
{
    int i, leap;
    
    if(year < 1 || yearday < 1)
    {
        *pmonth = -1;
        *pday = -1;
        return;
    }
    leap = (year%4 == 0 && year%100 != 0) || year%400 ==  0;
    if(leap == 1 && yearday > 366)
    {
        *pmonth = -1;
        *pday = -1;
        return;
    }
    if(leap == 0 && yearday > 365)
    {
        *pmonth = -1;
        *pday = -1;
        return;
    }        
    for(i = 0; yearday > daytab[leap][i]; i++)
        yearday -= daytab[leap][i];
    *pmonth = i;
    *pday = yearday;
}