#include <stdio.h>
#inclue <ctype.h>
#define NUMERIC 1 /*numeric sort */
#define DECR 2 /* sort in decreasing order */
#define FOLD 4 /*fold upper and lower cases */
#define DIR 8 /*directory order */
#define LINES 100 /* max # of lines to be sorted */
int charcmp(char *, char *);
void error(char *);
int numcmp(char *, char *);
void readargs(int argc, char *argv[]);
int readlines(char *lineptr[], int maxlines);
void qsort(char *v[], int left, int right, int (*comp)(void*, void*));
void writelines(char *lineptr[], int nlines, int order);
char option = 0;
int pos1 = 0; /*field beginning with pos1 */
int pos2 = 0; /*ending just before pos2 */
/* sort input lines */
int main(int argc , char *argv){
char *lineptr[LINES]; /*pointers to text lines */
int nlines; /*number of input lines read */
int rc =0;
readargs(argc, argv);
if((nlines = readlines(lineptr, LINES)) > 0){
if(option & NUMERIC)
qsort((void **) lineptr, 0, nlines -1,
(int (*)(void *, void*)) numcmp);
else
qsort((void **) lineptr, 0, nlines -1,
(int (*)(void *, void *) charcmp);
writelines(lineptr, nlines, option & DECR);
}else{
printf("input too big to sort \n");
rc = -1;
}
return rc;
}
/*readargs: read program arguments */
void readargs(int argc, char *argv[]){
int c;
int atoi(char *);
while(--argc > 0 && (c =(*++argv)[0]) == '-' || c =='+'){
if(c == '-' && !isdigit(*(argv[0] + 1)))
while(c == *++argv[0])
switch(c){
case 'd': /*directory order */
option |= DIR;
break;
case 'f': /*fold upper and lower */
option |= FOLD;
break;
case 'n': /*numeric sort */
option |= NUMERIC;
break;
case 'r': /* sort in decr order */
option |= DECR;
break;
default:
printf("sort: illegal option %c\n", c);
error("Usage; sort -dfnr [+pos1] [-pos2]");
break;
}
else if (c == '-')
pos2 = atoi(argv[0] + 1));
else if ((pos1 = atoi(argv[0] + 1)) < 0)
error("Usage: sort -dfnr [+pos1] [-pos2]");
}
if (argc || pos1 > pos2)
error("Usage: sort -dfnr [+pos1] [-pos2]");
}
/*numcmp.c */
#include <math.h>
#include <ctype.h>
#include <string.h>
#define MASTR 100
void substr(char *s, char *t, int maxstr);
/*numcmp: compare s1 and s2 numerically */
int numcmp(char *s1, char *s2){
double v1, v2;
char str[MAXSTR];
substr(s1, str, MAXSTR);
v1 = atof(str);
substr(s2,str, MAXSTR);
v2 = atof(str);
if(v1 < v2)
return -1;
else if (v1 > v2)
return 1;
else
return 0;
}
#define FOLD 4 /*fold upper and lower cases */
#define DIR 8 /*directory order */
/*charcmp: return <0 if s<t, 0 if s==t, >0 if s>t */
int charcmp(char *s, char *t){
char a, b;
int i, j, option;
extern char option;
extern int pos1, pos2;
int fold = (option & FOLD) ? 1 : 0;
int dir = (option & DIR) ? 1 : 0;
i = j = pos1;
if (pos2 > 0)
endpos = pos2;
else if((endpos = strlen(s)) > strlen(t))
endpos =strlen(t);
do{
if(dir){
while(i < endpos && !isalnum(s[i]) &&
s[i] != ' ' && s[i] != '\0')
i++;
while(j < endpos && !isalnum(t[j]) &&
t[j] != ' ' && t[j] != '\0')
j++;
}
if(i <endpos & j < endpos){
a = fold ? tolower(s[i]) : s[i];
i++;
b = fold ? tolower(t[j]) ; t[j];
j++;
if(a == b && a == '\0')
return 0;
}
}while(a == b && i<endpos && j< endpos);
return a - b;
}
/*substr.c */
#include <string.h>
void error(char *);
/*substr: get a substring of s and put in str */
void substr(char *s, char *str){
int i, j, len;
extern int pos1, pos2;
len = strlen(s);
if(pos2 > 0 && len > pos2)
len = pos2;
else if (pos2 > 0 && len < pos2)
error("substr: string too short");
for(j =0; i = pos1; i < len; i++, j++)
str[j] = s[i];
str[j] = '\0';
}
Add the -d(“directory order”) option, which makes comparisons only on letters, numbers, and blanks .Make sure it works in conjuction with -f.
#include <stdio.h>
#include <ctype.h>
#define NUMERIC 1 /*numeric sort */
#define DECR 2 /*sort in decreasing order */
#define FOLD 4 /* fold upper and lower cases */
#define DIR 8 /*directory order */
#define LINES 100 /* max # of lines to be sorted */
int charcmp(char *, char *);
int numcp(char *, char *);
int readlines(char *lineptr[], int maxlines);
void qsort(char *v[], int left, int right, int (*comp)(void*, void*));
void writelines(char *lineptr[], int nlines, int order);
static char option = 0;
/*sort input lines */
int main(int argc, char *argv[]){
char *lineptr[LINES]; /*pointers to text lines */
int nlines; /* number of input lines read */
int c, rc = 0;
while(--argc > 0 && (*++argv)[0] == '-')
while(c == *++argv[0])
switch(c){
case 'd': /* directory order */
option |= DIR;
break;
case 'f': /*fold upper and lower cases */
option |= FOLD;
break;
case 'n': /*numeric sort */
option |= NUMERIC;
break;
case 'r': /* sort in decreasing order */
option |= DECR;
break;
default:
printf("sort: illegal option %c\n", c);
argc = 1;
rc = -1;
break;
}
if(argc)
printf("Usage: sort -dfnr \n");
else{
if((nlines = readlines(lineptr, LINES)) > 0){
if(option & NUMERIC)
qsort((void **) lineptr, 0, nlines -1,
(int (*)(void *, void *)) numcmp);
else
qsort((void **) lineptr, 0, nlines -1,
(int (*) (void *, void *)) charcmp);
writelines(lineptr, nlines, option & DECR);
}else{
printf("input too big to sort \n");
rc = -1;
}
}
return rc;
}
/*charcmp: return <0 if s<t, 0 if s==t, >0 if s>t */
int charcmp(char *s, char *t){
char a, b;
int fold = (option & FOLD) ? 1 : 0;
int dir =(option & DIR) ? 1 : 0;
do{
if(dir){
while(!isalnum(*s) && *s != ' ' && *s != '\0')
s++;
while(!isalnum(*t) && *t != ' ' && *t != '\0')
t++;
}
a = fold ? tolower(*s) : *s;
s++;
b =fold ? tolower(*t) : *t;
t++;
if(a ==b && a == '\0')
return 0;
}while(a == b);
return a - b;
}
Add the option -f to fold upper and lower case together, so that case distinctions are not made during sorting;for e.g, a and A compare equal.
#include<stdio.h>
#include <string.h>
#include <ctype.h>
#define NUMERIC 1 /*numeric sort */
#define DECR 2 /* sort in decreasing order */
#define FOLD 4 /* fold upper and lower cases */
#define LINES 100 /* max # of lines to be sorted */
int charcmp(char *, char *);
int numcmp(char *, char *);
int readlines(char *lineptr[], int maximum);
void qsort(char *v[], int left, int right, int (*comp)(void*, void*));
void writelines(char *lineptr[], int nlines, int order);
static char option = 0;
/*sort input lines */
int main(int argc, char *argv[]){
char *lineptr[LINES]; /*pointers to text lines */
int nlines; /*number of input lines read */
int c, rc = 0;
while(--argc > 0 && (*++argv)[0] == '-'))
while(c =*++argv[0])
switch(c){
case 'f': /*fold upper and lower cases */
option |= FOLD;
break;
case 'n': /*numeric sort */
option |= NUMERIC;
break;
case 'r': /*sort in decreasing order */
option |= DECR;
break;
default:
printf("sort: illegal option %c\n", c);
argc = 1;
rc = -1;
break;
}
if(argc)
printf("Usage: sort -fnr \n");
else{
if((nlines = readlines(lineptr, LINES)) > 0){
if(option & NUMERIC)
qsort((void **) lineptr, 0, nlines - 1,
(int (*)(void *, void*)) numcmp);
else if (option & FOLD)
qsort((void **) lineptr, 0, nlines- 1,
(int (*)(void *, void *)) charcmp);
else
qsort((void **) lineptr, 0, nlines -1,
(int (*)(void *, void *)) strcmp);
}else{
printf(" input too big to sort \n");
rc = -1;
}
}
return rc;
}
/* charcmp: return <0 if s <t , 0 if s==t, >0 if s >t */
int charcmp(char *s, char *t){
for(;tolower(*s) == tolower(*t);s++, t++)
if (*s == '\0')
return 0;
return tolower(*s) - tolower(*t);
}
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 NUMERIC 1 /*numeric sort */
#define DECR 2 /* sort in decreasing order */
#define LINES 100 /*max # of lines to be sorted */
int numcmp(char *, char *);
int readlines(char *lineptr[], int maxlines);
void qsort(char *v[], int left, int right,
int (*comp)(void *, void *));
void writelines(char *lineptr[], int nlines, int decr);
static char option = 0;
/*sort input lines */
int main(int argc, char *argv[]){
while(c ==*++argv[0])
switch(c) {
case 'n': /*numeric sort */
option |= NUMERIC;
break;
case 'r': /* sort in decreasing order */
option |= DECR;
break;
default:
printf("sort: illegal option %c\n", c);
argc = 1;
rc = -1;
break;
}
if(argc)
printf(:Usage: sort -nr\n");
else
if(nlines = readlines(lineptr, LINES)) > 0){
if(option & NUMERIC)
qsort((void **) lineptr, 0, nlines- 1,
(int (*) (void *, void *)) numcmp);
else
qsort((void **) lineptr, 0, nlines -1,
(int (*) (void *, void *)) strcmp);
writelines(lineptr, nlines, option & DECR)
} else{
printf("input too big to sort \n");
rc = -1;
}
return rc;
}
/* writelines: write output lines */
void writelines(char *lineptr[], int nlines, int decr){
int i;
if(decr) /*print in decreasing order */
for(i =nlines -1; i>= 0; i--)
printf("%s\n", lineptr[i]);
else
for(i = 0; i <nlines; i++)
printf("%s\n", lineptr[i]);
}
Write the program tail, which prints the last n lines of its input.By default, n is 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 that it makes the best use of available storage;lines should be stored as in a sorting program, not in a 2d array of fixed size.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFLINES 10 /*default # of lines to print */
#define LINES 100 /* max # of lines to print */
#define MAXLEN 100 /* max length of an input line */
void error(char *);
int getline(char *, int);
/*print last n lines of the input */
int main(int argc, char *argv[]){
char *p;
char *buf; /*pointer to large buffer */
char *bufend; /* end of the buffer */
char line[MAXLEN]; /*current input line */
char *lineptr[LINES]; /*pointers to lines read */
int first, i, last, len, n, nlines;
if(argc == 1) /*no argument present */
n = DEFLINES; /* use default # of lines */
else if (argc == 2 && (*++argv)[0] =='-')
n = atoi(argv[0] + 1);
else
error(" usage: tail [-n]");
if(n < 1 || n > LINES) /*unreasoable value for n? */
n =LINES;
for(i =0; i <LINES;i++)
lineptr[i] = NULL;
if((p=buf=malloc(LINES * MAXLEN)) == NULL)
error("tail: cannot allocate buf");
bufend = buf + LINES *MAXLEN;
last = 0; /*index of last line read */
nlines = 0; /*number of lines read */
while((len = getline(line, MAXLINE)) > 0){
if(p + len + 1 >= bufend)
p = buf; /* buffer wrap around */
lineptr[last] = p;
strcpy(lineptr[last], line)
if(++last > LINES)
last = 0; /* ptrs to buffer wrap around */
p +=len + 1;
nlines++;
}
if (n > nlines ) /* req. lines more than reqd */
n = nlines;
first = last - n;
if(first < 0) /* it did wrap around the list */
first += LINES;
for(i = first; n--> 0; i=(i + 1) % LINES)
printf("%s", lineptr[i]);
return 0;
}
/* error: print error message and exit */
void error(char *s){
printf("%s\n", s);
exit(1);
}
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.
#include <stdio.h>
#define MAXLINE 100 /*maximum line size */
#define TABINC 8 /*default tab increment size */
#define YES 1
#define NO 0
void esettab(int argc, char *argv[], char *tab);
void entab(char *tab);
/* replace strings of blanks with tabs */
int main(int argc, char *argv[]){
char tab[MAXLINE + 1];
esettab(argc, argv, tab); /* initiliaze tab stops */
entab(tab); /* replace blanks w/tab */
return 0;
}
/*esettab.c */
#include<stdlib.h>
#define MAXLINE 100 /* maximum line size */
#define TABINC 8 /*default tab increment size */
#define YES 1
#define NO 0
/* esettab: set tab stops in array tab */
void esettab(int argc, char *argv[], char *tab){
int i, inc, pos;
if(argc <= 1) /* default tab stops */
for(i =1; i <= MAXLINE;i++)
if(i % TABINC == 0)
tab[i] = YES;
else
tab[i] = NO;
else if (argc == 3 && /*user provided range */
*argv[1] == '-' && *argv[2] == '+'){
pos = atoi(&(*++argv)[1]);
inc = atoi(&(*+=argv)[1]);
for(i = 1; i <= MAXLINE;i++)
if(i != pos)
tab[i] = NO;
else{
tab[i] = YES;
pos += inc;
}
}else{ /* user provided tab stops */
for(i = 1; i <= MAXLINE;i++)
tab[i] = NO; /* turn off tab stops */
while(--argc > 0) { /* walk through argument list */
pos = atoi(*++argv);
if(pos > 0 && pos <= MAXLINE)
tab[pos] = YES;
}
}
Modify the programs entab and detab to accept a list of tab stops as arguments. Use the default tab settings if there are no arguments.
#include <stdio.h>
#define MAXLINE 100 /*maximum line size */
#define TABINC 8 /*default tab increment size */
#define YES 1
#define NO 0
void settab(int argc, char *argv[], char *tab);
void entab(char *tab);
int tabpos(int pos, char *tab);
/*replace strings of blanks with tabs */
int main(int argc, char *argv[]){
char tab[MAXLINE + 1];
settab(argc, argv, tab); /* initializ tab stops */
entab(tab); /* replace blanks w/tab */
return 0;
}
/* entab: replace strings of blanks with tabs and blanks */
void entab(char *tab){
int c, pos;
int nb = 0; /* # of blanks necessary */
int nt = 0; /* # of tabs necessary */
for(pos = 1; (c =getchar()) != EOF; pos++){
if(c == ' '){
if(tabpos(pos, tab) == NO)
++nb; /* increment # of blanks */
}else{
nb = 0; /* reset # of blanks */
++nt; /* one more tab */
}else{
for(; nt > 0; nt--)
putchar('\t'); /* output tab(s) */
if(c == '\t') /* forget the blank(s) */
nb = 0;
else /* output blank(s) */
for(; nb > 0 ;nb--)
putchar(' ');
putchar(c);
if(c == '\n')
pos = 0;
else if (c == '\t')
while(tabpos(pos, tab) != YES)
++pos;
}
}
}
#include <stdlib.h>
#define MAXLINE 100 /*maximum line size */
#define TABINC 8 /* default tab increment size */
#define YES 1
#define NO 0
/*settab: set tab stops in array tab */
void settab(int argc, char *argv[], char *tab){
int i, pos;
if (argc <= 1) /*default tab stops */
for(i =1; i <= MAXLINE;i++)
if(i %TABINC == 0)
tab[i] = YES;
else
tab[i] = NO;
else{ /*user provided tab stops */
for(i =1;i <= MAXLINE;i++)
tab[i] = NO; /* turn off all tab stops */
while(--argc > 0) {
pos = atoi(*++argv);
if(pos > 0 && pos <= MAXLINE)
tab[pos] = YES;
}
}
}
/* tabpos.c */
#define MAXLINE 100 /* maximum line size */
#define YES 1
/* tabpos: determine if pos is at a tab stop */
int tabpos(int pos, char *tab){
if(pos > MAXLINE)
return YES;
else
return tab[pos];
}
/*detab: replace tab with blanks */
void detab(char *tab){
int c, pos = 1;
while((c =getchar()) != EOF)
if(c =='\t'){
do
putchar(' ');
while(tabpos(pos++, tab) != YES);
}else if (c == '\n'){
putchar(c);
pos = 1;
}else{ /* all other characters */
putchar(c);
++pos;
}
}
Write the program expr, which evaluates a reverse Polish expression from the command line, where each operator or operand is a separate argument.For e.g expr 2 3 4 + * evaluates 2 *(3 + 4)
#include <stdio.h>
#include <math.h> /* atof() */
#define MAXOP 100 /* max size of operand or operator */
#define NUMBER '0' /*signal that a number was found */
int getop(char []);
void ungets(char []);
void push(double);
double pop(void);
/* reverse Polish calculator; uses command line */
int main(){
char s[MAXOP];
double op2;
while(--argc > 0){
ungets(" "); /*push end of argument */
ungets(*++argv); /* push an argument */
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 divisor\n");
break;
default:
printf("error: unknown command %s\n", s);
argc = 1;
break;
}
}
printf("\t %.8g\n",, pop());
return 0;
}
Rewrite the routines day_of_year and month_day with pointers instead of indexing.
static char daytab[2][13] = {
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}
};
/* day_of_year: set day of year from month & day */
int day_of_year(int year, int month, int day){
int leap;
char *p;
leap = year % 4 == 0 && year%100 != 0 || year %400 == 0;
p = daytab[leap];
while(--month)
day += *++p;
return day;
}
/* month_day: set month, day from day of year */
void month_day(int year, int yearday, int *pmonth, int *pday){
int leap;
char *p;
leap = year %4 == 0 && year%100 != 0 || year%400 == 0;
p =daytab[leap];
while(yearday >*++p)
yearday -= *p;
*pmonth = p - *(daytab + leap);
*pday = yearday;
}
There is no error checking in day_of_year or month_day.Remedy this defect.
static char daytab[2][13]= {
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}
};
/*day_of_year: set day of year from month & day */
int day_of_year(int year, int month, int day){
int i, leap;
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: set month, day from day of year */
void month_day(int year, int yearday, int *pmonth, int *pday){
int i, leap;
if (year < 1){
*pmonth = -1;
*pday = -1;
return ;
}
leap = year % 4 == 0 && year %100 != 0 || year %400 == 0;
for(i = 1; i <=12 && yearday > daytab[leap][i];i++)
yearday -=daytab[leap][i];
if (i > 12 && yearday > daytab[leap][12]){
*pmonth = -1;
*pday = -1;
}else{
*pmonth = i;
*pday = yearday;
}
}