Страницы

Translate

вторник, 24 декабря 2013 г.

Exercise 8.8. Write a routine bfree(p,n) that will free any arbitrary block p of n characters into the free list maintained by malloc and free.

Exercise 8.8. Write a routine bfree(p,n) that will free any arbitrary block p of n characters into the free list maintained by malloc and free. By using bfree, a user can add a static or external array to the free list at any time.








unsigned bfree(char *p, unsigned n)
{
    Header *hp;
   
    if(n < sizeof(Header))
        return 0;
    hp = (Header *) p;
    hp->s.size = n / sizeof(Header);
    free((void *) (hp + 1));
    return hp->s.size;
}

Exercise 8.7. malloc accepts a size request without checking its plausibility; free believes that the block it is asked to free contains a valid size field. Improve these routines so they make more pains with error checking.

Exercise 8.7. malloc accepts a size request without checking its plausibility; free believes that the block it is asked to free contains a valid size field. Improve these routines so they  make more pains with error checking.






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

#define MAXBYT 10240

typedef long Align; //for alignment to long boundary
union header
{
    struct  //block header
    {
        union header *ptr; //next block if on free list
        unsigned size;      //size of this block
    } s;
    Align x; //force alignment of blocks
};

typedef union header Header;

static Header base; //empty list to get started
static Header *freep = NULL; //start of free list
static Header *morecore(unsigned nu);
static Header *freeptr;
static Header *prevptr;
static unsigned maxalloc; //max bytes

/* malloc: universal storage allocator */
void *_malloc(unsigned nbytes)
{
    Header *p, *prevp;
    Header *moreroce(unsigned);
    unsigned nunits;
   
    if(nbytes > MAXBYT)
    {
        fprintf(stderr, "alloc: i can`t allocate more than %d bytes/n",
                    MAXBYT);
        return NULL;
    }   
    nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
    if((prevp = freep) == NULL) //no free list yet
    {
        base.s.ptr = freeptr = prevptr = &base;
        base.s.size = 0;
    }
    for(p = prevp->s.ptr; ;prevp = p, p = p->s.ptr)
    {
        if(p->s.size >= nunits) //big enough
        {
            if(p->s.size == nunits) //exactly
                prevp->s.ptr = p->s.ptr;
            else //allocate tail end
            {
                p->s.size -= nunits;
                p += p->s.size;
                p->s.size = nunits;
            }
            freep = prevp;
            return (void *) (p+1);
        }
        if(p == freep) //wrapped around free list
            if((p = morecore(nunits)) == NULL)
                return NULL; // non left
    }
}

#define NALLOC 1024 //minimum units to request
/* morecore: ask system for more memory */
static Header *morecore(unsigned nu)
{
    char *cp, *sbrk(int);
    Header *up;
   
    if(nu < NALLOC)
        nu = NALLOC;
    cp = sbrk(nu * sizeof(Header));
    if(cp == (char *) -1) //no space at all
        return NULL;
    up = (Header *) cp;
    up->s.size = nu;
    maxalloc = (up->s.size > maxalloc) ? up->s.size : maxalloc;
    free((void *) (up + 1));
    return freep;
}

/* free: put block ap in free list */

void free(void *ap)
{
    Header *bp, *p;
   
    bp = (Header *) ap - 1; // point to block header
    if(bp->s.size == 0 || bp->s.size > maxalloc)
    {
        fprintf(stderr, "alloc: i can`t allocate more than %d bytes/n",
                    MAXBYT);
        return;
    }   
    for (p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
        if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))
            break; //freed block at start or end of arena
    if(bp + bp->s.size == p->s.ptr) //join to upper nbr
    {
        bp->s.size +=p->s.ptr->s.size;
        bp->s.ptr = p->s.ptr->s.ptr;
    }
    else
        bp->s.ptr = p->s.ptr;
    if(p + p->s.size == bp) //join to lower nbr
    {
        p->s.size += bp->s.size;
        p->s.ptr = bp->s.ptr;
    }
    else
        p->s.ptr = bp;
    freep = p;
}

Exercise 8.6. The standard library function calloc(n,size) returns a pointer to n objects of size size, with the storage initialized to zero

Exercise 8.6. The standard library function calloc(n,size) returns a pointer to n objects of
size size, with the storage initialized to zero. Write calloc, by calling malloc or by
modifying it.









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

/* calloc */

void _calloc(unsigned n, unsigned size)
{
    unsigned i, nsize;
    char *p, *q;
   
    nsize = n * size;
    if((p = q = malloc(nsize)) != NULL)
        for(i = 0; i < nsize; i++)
            *q++=0;
    return p;
}

пятница, 20 декабря 2013 г.

Exercise 8.5. Modify the fsize program to print the other information contained in the inode entry



Exercise 8.5. Modify the fsize program to print the other information contained in the inode entry.



#include <stdio.h>
#include <string.h>
#include <sys/stat.h> //structure returned by stat
#include <sys/types.h> //typedefs
#include <sys/syscall.h>
#include <fcntl.h> //flags for read and write
#include <dirent.h>
#include <sys/dir.h> //local directory structure


int stat(char *, struct stat *);
void dirwalk(char *, void (*fcn) (char *));


/* fsize: print file "name" size */
void fsize(char *name)
{
    struct stat stbuf;
   
    stat(name, &stbuf) == -1)
    {
        fprintf(stderr, "fsize: can`t acces %s\n", name);
        return;
    }
    if(stbuf.st_mode & S_IFMT) == S_IFDIR)
        dirwalk(name, fsize);
    printf("%8ld %s\n%u %ld\n", stbuf.st_size, name,  stbuf.st_uid,stbuf.st_mtime);
}

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

Exercise 8.4.Write int fseek(FILE *fp, long offset, int origin).



Exercise 8.4. The standard library function int fseek(FILE *fp, long offset, int origin) is identical to lseek except that fp is a file pointer instead of a file descriptor and return value is an int status, not a position. Write fseek.



/* fseek: random access using file pointer */
int _fseek(_FILE *fp, long offset, int origin)
{
    unsigned nc; //discharged characters
    long rc = 0; //return code
   
    if(fp->flag.f_read)
    {
        if(origin == 1)
            offset -= fp->cnt;
        rc = lseek(fp->fd, offset, origin);
        fp->cnt = 0; //buffer is empty
    }
    else if(fp->flag.f_write)
    {
        if((nc = fp->ptr - fp->base) > 0)
            if(write(fp->fd, fp->base, nc) != nc)
                rc = -1;
        if(rc != -1) // no error
            rc = lseek(fp->fd, offset, origin);
    }
    return (rc == -1) ? -1 : 0;
}

Exercise 8.3. Design and write _flushbuf, fflush, and fclose



Exercise 8.3. Design and write _flushbuf, fflush, and fclose.



/* _flushbuf: selects or clears the input buffer */
int _flushbuf(int x, _FILE *fp)
{
    unsigned nc; //amount discharged characters
    int bufsize; //size of the allocated buffer
   
    if (fp < _iob || fp >= _iob + OPEN_MAX)
        return EOF; //wrong pointer
    if(fp->flag.f_write == 0 || fp->flag.f_err == 1)
        return EOF;
    bufsize = (fp->flag.f_unbuf == 1) ? 1 : BUFSIZ;
    if(fp->base == NULL) //buffer is not yet
    {
        if((fp->base = (char *) malloc(bufsize)) == NULL)
        {
            fp->flag.f_err = 1;
            return EOF; //can not takes buffer
        }
    }
    else //buffer is already
    {
        nc = fp->ptr - fp->base;
        if(write(fp->fd, fp->base, nc) != nc)
        {
            fp->flag.f_err = 1;
            return EOF;//error, return EOF
        }
    }
    fp->ptr = fp->base; //beginning of the buffer
    *fp->ptr++=(char)x;
    fp->cnt = bufsize - 1;
    return x;
}

/* fclose: closed the file */
int _fclose(_FILE *fp)
{
    int rc; //return code
   
    if((rc = _fflush(fp)) != EOF)
    {
        free(fp->base); // release memory buffer
        fp->ptr = NULL;
        fp->cnt = 0;
        fp->base = NULL;
        fp->flag.f_unbuf = 0;
        fp->flag.f_buf = 1;
        fp->flag.f_eof = 0;
        fp->flag.f_err = 0;
        fp->flag.f_read = 0;
        fp->flag.f_write = 0; 
    }
    return rc;
}

/* fflush: reset the buffer corresponding to the file */
int _fflush(_FILE *fp)
{
    int rc = 0;
   
    if(fp < _iob || fp >= _iob + OPEN_MAX)
        return EOF; //wrong pointer
    if(fp->flag.f_write)
        rc = _flushbuf(0, fp);
    fp->ptr = fp->base;
    fp->cnt = (fp->flag.f_unbuf == 1) ? 1 : BUFSIZ;
    return rc;
}

четверг, 12 декабря 2013 г.

Exercise 8.2. Rewrite fopen and _fillbuf with fields instead of explicit bit operations.


Exercise 8.2. Rewrite fopen and _fillbuf with fields instead of explicit bit operations.
Compare code size and execution speed.








#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#define PERMS 0666 //read/write for all

#define EOF (-1)
#define OPEN_MAX 20

struct flag_field
{
    unsigned f_read : 1;
    unsigned f_write : 1;
    unsigned f_unbuf : 1;
    unsigned f_buf : 1;
    unsigned f_eof : 1;
    unsigned f_err : 1;
} flag;


typedef struct _iobuf
{
    int cnt; //the number of remaining characters
    char *ptr; //position next symvol
    char *base; //buffer address
    struct flag_field flag; //access mode
    int fd; // file descriptor
} _FILE;

extern _FILE _iob[OPEN_MAX];

_FILE _iob[OPEN_MAX] = { /* stdin, stdout, stderr */
    {0, (char *) 0, (char *) 0, {1,0,0,0,0}, 0},
    {0, (char *) 0, (char *) 0, {0,1,0,0,0}, 1},
    {0, (char *) 0, (char *) 0, {0,1,1,0,0}, 2}
};

/* fopen: open the file, return file's point */
_FILE *_fopen(char *name, char *mode)
{
    int fd;
    _FILE *fp;
   
   
   
    if(*mode != 'r' && *mode != 'w' && *mode != 'a')
        return NULL;
    for(fp = _iob; fp< _iob + OPEN_MAX; fp++)
        if(fp->flag.f_read == 0 && fp->flag.f_write == 0)
            break; //find free position
    if(fp>=_iob + OPEN_MAX)
        return NULL; // no free position
    if(*mode == 'w') //makes file
        fd = creat(name, PERMS);
    else if(*mode == 'a')
    {
        if((fd = open(name, O_WRONLY, 0)) == -1)
            fd = creat(name, PERMS);
        lseek(fd, 0L, 2);
    }
    else
        fd = open(name, O_RDONLY, 0);
    if(fd == -1) //not open the file "name"
        return 0;
    fp->fd = fd;
    fp->cnt = 0;
    fp->base = 0;
    fp->flag.f_unbuf = 0;
    fp->flag.f_buf = 1;
    fp->flag.f_eof = 0;
    fp->flag.f_err = 0;
    if(*mode == 'r') //read
    {
        fp->flag.f_read = 1;
        fp->flag.f_write = 0;
    }
    else //write
    {
        fp->flag.f_read = 0;
        fp->flag.f_write = 1;
    }
    return fp;
}

/* _fillbuf: identify and fill the input buffer */
int _fillbuf(_FILE *fp)
{
    int bufsize;
   
    if(fp->flag.f_read == 0 || fp->flag.f_eof == 1 ||
        fp->flag.f_err == 1)
        return EOF;
    bufsize = (fp->flag.f_unbuf == 1) ? 1 : BUFSIZ;
    if (fp->base == NULL) // buffer isn`t yet
        if((fp->base = (char *) malloc(bufsize)) == NULL)
            return EOF; // can`t allocate memory
    fp->ptr = fp->base;
    fp->cnt = read(fp->fd, fp->ptr, bufsize);
    if(--fp->cnt < 0)
    {
        if(fp->cnt == -1)
            fp->flag.f_eof = 1;
        else
            fp->flag.f_err = 1;
        fp->cnt = 0;
        return EOF;
    }
    return (unsigned char) *fp->ptr++;
}

вторник, 3 декабря 2013 г.

Exercise 8.1. Rewrite the program cat from Chapter 7 using read, write, open, and close instead of their standard library equivalents



Exercise 8.1. Rewrite the program cat from Chapter 7 using read, write, open, and close instead of their standard library equivalents. Perform experiments to determine the relative speeds of the two versions.


#include <stdio.h>
#include <fcntl.h>
#include "syscalls.h"


/* cat */
int main(int argc, char *argv[])
{
    int fp;
    void filecopy(int ifp, int ofp);
   
    if(argc == 1) //no arguments, default stdin
        filecopy(0, 1);
    else
        while(--argc > 0)
            if((fp = open(*++argv, 0_RDONLY)) == -1)
                error("cat: can`t open the file %s\n", *argv);
            else
            {
                filecopy(fp, 1);
                close(fp);
            }
    return 0;
}

/* filecopy: copy file ifp into file ofp */
void filecopy(int ifp, int ofp)
{
    int n;
    char buf[BUFSIZ];
   
    while((n = read(ifp, buf, BUFSIZ)) > 0)
        if(write(ofp, buf, n) != n)
            error("cat:write error");
}

суббота, 30 ноября 2013 г.

Exercise 7.9. Functions like isupper can be implemented to save space or to save time. Explore both possibilities



Exercise 7.9. Functions like isupper can be implemented to save space or to save time.
Explore both possibilities.



#include <ctype.h>

/* to save space */

int isupper(char c)
{
    if(c >= 'A' && c =< 'Z')
        return 1;
    else
        return 0;
}

/* to save time */

#define isupper(c) ((c) >= 'A' && (c) <= 'Z') ? 1 : 0


пятница, 29 ноября 2013 г.

Exercise 7.8. Write a program to print a set of files, starting each new one on a new page, with a title and a running page count for each file



Exercise 7.8. Write a program to print a set of files, starting each new one on a new page,
with a title and a running page count for each file.



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

#define MAXFIELD 2 //maximum rows at the top and bottom of the page
#define MAXSTRING 60
#define MAXLINE 100
#define NAME 20

FILE *in, *out;
void fprint(char *pfile);
int headfile(char *pfile, int pageno);

int main(int argc, char *argv[])
{

    char file[NAME];
    char fileout[NAME]; //the output file
   
    if(argc == 1)
    {
        printf("ERROR, no arguments\n");
        return 1;
    }
    else
    {
        printf("Type the name of the output file: ");
        gets(fileout);
        out = fopen(fileout, "w");
        while(--argc > 0)
        {
            strcpy(file, *++argv);
            if((in = fopen(file, "r")) == NULL)
            {
                perror(file);
                return 1;
            }
            else
            {
                fprint(file);
                fclose(in);
            }
        }
    }
    fclose(out);
    return 0;
}

/* print the selected file */
void fprint(char *pfile)
{
    char line[MAXLINE];
    int lineno, pageno;

   
    lineno = pageno = 1;
    lineno = headfile(pfile, pageno);
    pageno++;
    while(!feof(in))
    {
        if(lineno == 1)
        {
            fprintf(out, "\f");
            lineno = headfile(pfile, pageno);
            pageno++;
        }
        fgets(line, MAXLINE-1, in);
        fputs(line,out);
        lineno++;
        if(lineno == (MAXSTRING - MAXFIELD))
            lineno = 1;
    }
    fprintf(out, "\f");
}

/* print header and blank lines */
int headfile(char *pfile, int pageno)
{
    int line = 0;
   
    while(line++ < MAXFIELD)
        fprintf(out, "\n");
    fprintf(out, "file %s, page - %d\n", pfile, pageno);
    line++;
    return line;
}

среда, 27 ноября 2013 г.

Exercise 7.7. Modify the pattern finding program of Chapter 5 to take its input from a set of named files or, if no files are named as arguments, from the standard input.



Exercise 7.7. Modify the pattern finding program of Chapter 5 to take its input from a set of named files or, if  no files are named as arguments, from the standard input. Should the file name be printed when a matching  line is found?

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

#define MAXLINE 1000
#define NAME 20

FILE *in;
int except = 0;
int number = 0;
long lineno = 0;

int getline(char *line, int max);
void fstdin(char *line, char *pattern);
void ffile(FILE *fp, char *pattern, char *line, char *file_name);

/* find:  print lines that match pattern from 1st arg */
int main(int argc, char *argv[])
{
     char line[MAXLINE];
     char pattern[MAXLINE];
     char file[NAME];
;
     int c;
         
     while(--argc > 0 && (*++argv)[0] == '-')
        while(c = *++argv[0])
            switch(c)
            {
                case 'x':
                    except = 1;
                    break;
                case 'n':
                    number = 1;
                    break;
                default:
                    printf("find: illegal option %c\n", c);
                    argc = 0;
                    break;
            }
    if(argc < 1)
    {
        printf("Usage: find -x -n pattern file...\n");
        return 1;
    }
    else
        strcpy(pattern, *argv);
    if (argc == 1) // read from stdin
        fstdin(line, pattern //search in the string
    else
        while(--argc != 0) //get file`s name
        {
            strcpy(file, *++argv);
            if((in = fopen(file, "r")) == NULL)
            {
                perror(file);
                return 1;
            }
            else
            {
                ffile(in, pattern, line,file); //search in the file
                fclose(in);
            }
        }
    return 0;
}

/* ffile: search in the file */

void ffile(FILE *in, char *pattern, char *line, char *file_name)
{
    while(!feof(in))
    {
        fgets(line, MAXLINE-1, in);
        lineno++;
        if((strstr(line, pattern) != NULL) != except)
        {
            printf("%s\n", file_name);
            if(number)
                printf("%ld: ", lineno);
            printf("%s", line);
        }
    }
}
       
/* fstdin: search in the string from standart input */
void fstdin(char *line, char *pattern)
{
    while(getline(line, MAXLINE) > 0)
    {
        lineno++;
        if((strstr(line, pattern) != NULL) != except)
        {
            if(number)
                printf("%ld: ", lineno);
            printf("%s", line);
        }
    }
}

/* getline: read the string, return the length */

int getline(char *line, int max)
{
    if(fgets(line, max, stdin) == NULL)
        return 0;
    else
        return strlen(line);
}


Result:


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

Exercise 7.6. Write a program to compare two files, printing the first line where they differ



Exercise 7.6. Write a program to compare two files, printing the first line where they differ.



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

#define MAXNAME 20
#define MAXLINE 100

FILE *first, *second;

int main()
{
    char f[MAXNAME], s[MAXNAME], str1[MAXLINE], str2[MAXLINE];
   
    printf("type the names of the compared files\n");
    printf("first: ");
    gets(f);
    printf("second: ");
    gets(s);
    if((first = fopen(f, "r")) == NULL)
    {
        perror(f);
        return 1;
    }
    else if((second = fopen(s, "r")) == NULL)
    {
        perror(s);
        return 1;
    }
    else
        printf("files open\n\n");
    while(!feof(first) && !feof(second))
    {
        fgets(str1, MAXLINE-1, first);
        fgets(str2, MAXLINE-1, second);
        if(strcmp(str1,str2) != 0)
             {
                printf("first different strings:\n\n");
                printf("%s\n%s\n", str1, str2);
                break;
            }
    }
    fclose(first);
    fclose(second);
    return 0;
}


Result:







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

Exercise 7.5. Rewrite the postfix calculator of Chapter 4 to use scanf and/or sscanf to do the input and number conversion.



Exercise 7.5. Rewrite the postfix calculator of Chapter 4 to use scanf and/or sscanf to do the input and number conversion.



#include <stdio.h>
#include <stdlib.h>
#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 push(double);
double pop(void);

/* reverse polish calculator */
int main()
{
    int type;
    double op2;
    char s[MAXOP];
   
    while((type = getop(s)) != EOF)
    {
        switch(type)
        {
            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)
                    push(pop() / op2);
                else
                    printf("error: zero devisior\n");
                break;
            case '%':
                op2 = pop();
                if(op2 != 0.0)
                    push(fmod(pop(), op2));
                else
                    printf("error: zero devisor\n");
                break;
            case '\n':
                printf("\t%.8g\n", pop());
                break;
            default:
                printf("error: unknown command %s\n", s);
                break;
        }
    }
    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>

/* getop: get next character ot numeric operand */
int getop(char s[])
{
    int i, c, rc;
    static char lastc[] = " ";
   
    c = lastc[0];
    lastc[0] = ' ';
    while((s[0] = c) == ' ' || c == '\t')
        if(scanf("%c", &c) == EOF)
            c = EOF;
    s[1] = '\0';
    if(!isdigit(c) && c != '.' && c != '-') // not a number
        return c;
    i = 0;
    if (c == '-')
    {
        scanf("%c", &c);
        rc = c;
        if(isdigit(c) || c == '.')
            s[++i] = c; //negative numbers
        else
            {
                if(rc != EOF)
                    lastc[0] = c;
                return '-';
            }
    }
    if(isdigit(c)) //collect integer part
        do
        {
            scanf("%c", &c);
            rc = c;
            if(!isdigit(s[++i] = c))
                break;
        } while(rc != EOF);
    if(c == '.') //collect fraction part
        do
        {
            scanf("%c", &c);
            rc = c;
            if(!isdigit(s[++i] = c))
                break;
        } while(rc != EOF);
    s[i] = '\0';
    if(rc != EOF)
        lastc[0] = c;
    return NUMBER;
}


Result:





Exercise 7.4. Write a private version of scanf analogous to minprintf




Exercise 7.4. Write a private version of scanf analogous to minprintf from the previous section.


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

#define ARRAYFMT 10

void minscanf(char *, ...);


/* minscanf: */

void minscanf(char *fmt, ...)
{
    va_list ap; //points to the next unnamed argument
    char *p, *sval;
    int *ival, i;
    unsigned *uval;
    double *dval;
    char arrayfmt[ARRAYFMT]; //array of characters
   
    i = 0;
    va_start(ap, fmt);//establishes for the first unnamed argument
    for(p = fmt; *p; p++)
    {
        if(*p != '%')
        {
            arrayfmt[i++] = *p;
            continue;
        }
        arrayfmt[i++] = '%';
        for(;*(p+1) && !isalpha(*(p+1)); i++)
            arrayfmt[i] = *++p;
        arrayfmt[i++] = *(p+1);//letter format
       
arrayfmt[i] = '\0';       
        switch (*++p) //letter format
        {
            case 'd':
            case 'i':
                ival = va_arg(ap, int *);
                scanf(arrayfmt, ival);
                break;
            case 'f':
                dval = va_arg(ap, double *);
                scanf(arrayfmt, dval);
                break;
            case 's':
                sval = va_arg(ap, char *);
                scanf(arrayfmt, sval);
                break;
            case 'o':
            case 'x':
            case 'X':
            case 'u':
            case 'e':
                uval = va_arg(ap, unsigned *);
                scanf(arrayfmt, uval);
                break;
        }
        i = 0;
    }
    va_end(ap);//clear, after finish}

суббота, 16 ноября 2013 г.

Exercise 7.2. Write a program that will print arbitrary input in a sensible way.



Exercise 7.2. Write a program that will print arbitrary input in a sensible way. As a minimum,
it should print non-graphic characters in octal or hexadecimal according to local custom, and
break long text lines.



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

#define MAXLINE 25 //maximum number of characters in line
#define OCTLEN 8 //length of the octal value

/*  print arbitrary input in a sensible way */
int main()
{
    int c, pos;
   
    pos = 0; //position in string    

    while((c = getchar()) != EOF)
        if(iscntrl(c) || isspace(c))
        {
            if(pos + OCTLEN < MAXLINE)
                pos = pos + OCTLEN;
            else
            {
                putchar('\n');
                pos = OCTLEN;
            }
            printf("
\\%03o", c);
            if(c == '\n')
            {
                pos = 0;
                putchar('\n');
            }
        }
        else
        {
            if(pos + 1 < MAXLINE)
                pos = pos + 1;
            else
            {
                putchar('\n');
                pos = 1;
            }
            putchar(c);
        }
    return 0;
}

Exercise 7.3. Revise minprintf to handle more of the other facilities of printf.


Exercise 7.3. Revise minprintf to handle more of the other facilities of printf.


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


#define MASFMT 10

/* minprintf: */
void minprintf(char *fmt, ...)
{
    va_list ap; //points to the next unnamed argument    

    char *p, *sval;
    int ival, i;
    unsigned uval;
    double dval;
    char masfmt[MASFMT]; //array of characters
   
    va_start(ap, fmt);//establishes for the first unnamed argument
    for(p = fmt; *p; p++)
    {
        if(*p != '%')
        {
            putchar(*p);
            continue;
        }
        i = 0;
        masfmt[i++] = '%';
        for(;*(p+1) && !isalpha(*(p+1)); i++)
            masfmt[i] = *++p;
        masfmt[i++] = *(p+1);//letter format        

        masfmt[i] = '\0';       
        switch (*++p) //letter format
        {
            case 'd':
            case 'i':
                ival = va_arg(ap, int);
                printf(masfmt, ival);
                break;
            case 'f':
                dval = va_arg(ap, double);
                printf(masfmt, dval);
                break;
            case 's':
                for(sval = va_arg(ap, char *); *sval; sval++)
                putchar(*sval);
                break;
            case 'o':
            case 'x':
            case 'X':
            case 'u':
            case 'e':
                uval = va_arg(ap, unsigned);
                printf(masfmt, uval);
                break;
            default:
                putchar (*p);
                break;
        }
    }
    va_end(ap);//clear, after finish

}


вторник, 12 ноября 2013 г.

Exercise 7.1. Write a program that converts upper case to lower or lower case to upper



Exercise 7.1. Write a program that converts upper case to lower or lower case to upper,
depending on the name it is invoked with, as found in argv[0].

I changed a little exercise , I think it would be better.

 Write a program that converts upper case to lower or lower case to upper,
depending on the name it is invoked with, as found in argv[1].


#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
    int c;
   
    if(argc != 2)
    {
        printf("ERROR, no parametrs\n");
        return 1;
    }
    else if(strcmp(argv[1], "lower") == 0)
        while((c = getchar()) != EOF)
            putchar(tolower(c));
    else if(strcmp(argv[1], "upper") == 0)
        while((c = getchar()) != EOF)
            putchar(toupper(c));
    else
        printf("wrong parametrs\n");
    return 0;
}

 

среда, 6 ноября 2013 г.

Exercise 6.6. Implement a simple version of the #define processor (i.e., no arguments)



Exercise 6.6. Implement a simple version of the #define processor (i.e., no arguments) suitable for use with C programs, based on the routines of this section. You may also find getch and ungetch helpful.



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

#define MAXWORD 100
#define HASHSIZE 101

struct nlist{           //table entry
    struct nlist *next; //next entry in chain
    char *name;         //define name
    char *defn;         //replacemrnt text
};
static struct nlist *hashtab[HASHSIZE]; //pointer table 

void error(int, char *);
char *s_dup(char *);
int getch(void);
void ungetch(int);
int getword(char *, int);
void getdef(void);
void undef(char *);
void ungets(char *);
struct nlist *lookup(char *);
struct nlist *install(char *, char *);
void skipspace(void);
unsigned hash(char *);


/* a simple version of the #define processor */
int main()
{
    char word[MAXWORD];
    struct nlist *np;
    
    while(getword(word, MAXWORD) != EOF)
        if(strcmp(word, "#") == 0)  //beginning def processor
            getdef();
        else if(!isalpha(word[0]))
            printf("%s\n", word);   //can't define
        else if((np = lookup(word)) == NULL)
            printf("%s\n", word);   //not define
        else
            ungets(np->defn);       //return definition
    return 0;
}

/* getdef: get definition and put it in table */
void getdef(void)
{
    int i;
    char def[MAXWORD], dir[MAXWORD], name[MAXWORD];
    
    skipspace();
    if(!isalpha(getword(dir, MAXWORD)))
        error(dir[0], "getdef: after # waiting directive");
    else if(strcmp(dir, "define") == 0)
    {
        skipspace();
        if(!isalpha(getword(name, MAXWORD)))
            error(name[0], "getdef: not letter, waiting name");
        else
        {
            skipspace();
            for(i = 0; i < MAXWORD; i++)
                if((def[i] = getch()) == EOF || def[i] == '\n')
                    break;
            def[i] = '\0';
            if(i <= 0) //not definition
                error('\n', "getdef: incomplete definition");
            else //put definition to table
                install(name, def);
        }
    }
    else if(strcmp(dir, "undef") == 0)
    {
        skipspace();
        if(!isalpha(getword(name, MAXWORD)))
            error(name[0], "getdef: not letter in directine undef");
        else
            undef(name);
    }
    else
        error(dir[0], "getdef: aftewr # waiting directive");
}

/* error: print message about error and skip string */
void error(int c, char *s)
{
    printf("Error: %s\n", s);
    while(c != EOF && c != '\n')
        c = getch();
}

/* skipspace: skip space and tabs */
void skipspace(void)
{
    int c;
    
    while((c = getch() == ' ' || c == '\t'))
        ;
    ungetch(c);
}

/* ungets */
void ungets( char *s)
{
    int len;
    
    len = strlen(s);
    while(len > 0)
        ungetch(s[--len]);

}

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

Exercise 6.5. Write a function undef that will remove a name and definition from the table maintained by lookup and install.



Exercise 6.5. Write a function undef that will remove a name and definition from the table
maintained by lookup and install.


/* undef: remove the name and definition of the table */
void undef(char *s)
{
    int h;
    struct nlist *prev, *np;
    
    prev = NULL;
    h = hash(s);    //hash string s
    for(np = hashtab[h]; np != NULL; np = np->next)
    {
        if(strcmp(s, np->name) == 0)
            break;
        prev = np;
    }
    if(np != NULL)  // name found
    {
        if(prev == NULL)    // it is first name in hash
            hashtab[h] = np->next;
        else    //not first
            prev->next = np->next;
        free((void *) np->name);
        free((void *) np->defn);
        free((void *) np);  //releases the dedicated structure
    }
}

суббота, 26 октября 2013 г.

Exercise 6.4. Write a program that prints the distinct words in its input sorted into decreasing order of frequency of occurrence



Exercise 6.4. Write a program that prints the distinct words in its input sorted into decreasing order of frequency of occurrence. Precede each word by its count.



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

#define MAXWORD 100

struct tnode {  //the tree node
    char *word; //points to text
    int count; //number of occurrences
    struct tnode *left; //left child
    struct tnode *right; //right child
};
struct words {
    char *words;
    int counts;
};


struct tnode *addtree(struct tnode *, char *);
int getword(char *, int);
void sort(struct words *); //sort array
int countword;
int i = 0;


/* word frequency count */
int main()
{
    struct tnode *root;
    char word[MAXWORD];
    
    root = NULL;
    while(getword(word, MAXWORD) != EOF)
        if(isalpha(word[0]))
            root = addtree(root, word);
    struct words sortword[countword];
    void fillarray(struct tnode *, struct words *); //fill an array 
    fillarray(root, sortword);
    sort(sortword); 
    int j;
    for(j = 0; j < countword; j++)
        printf("%4d %s\n", sortword[j].counts, sortword[j].words);
    return 0;
}

/* fillarray: fill an array of structures */
void fillarray(struct tnode *p, struct words sortword[])
{
    if(p != NULL)
    {
        fillarray(p->left, sortword);
        sortword[i++] = (struct words) {p->word, p->count};
        fillarray(p->right, sortword);
    }
}

/* sort: sort an array by inserting */
void sort(struct words sortword[])
{
    struct words temp;
    int i, j;
    for(i = 1; i<countword; i++)
    {
        temp = sortword[i];
        for(j = i-1; j >=0 && sortword[j].counts > temp.counts; j--)
        {
            sortword[j+1] = sortword[j];
            sortword[j] = temp;
        }
    }
}

struct tnode *talloc(void);
char *s_dup(char *s);

/* adtree: add a node with w, at or below p */ 
struct tnode *addtree(struct tnode *p, char *w)
{
    int cond;
    
    if(p == NULL) //a new word has arrived
    {
        p = talloc(); //make a new node
        p->word = s_dup(w);
        countword++; //count words
        p->count = 1;
        p->left = p->right = NULL;
    }
    else if((cond = strcmp(w, p->word)) == 0)
        p->count++; //repeated word
    else if(cond < 0) //less than into left subtree
    {
        p->left = addtree(p->left, w);
    }
    else  //greater than into right subtree
    {
        p->right = addtree(p->right, w);
    }
    return p;
}

/* talloc: make a tnode */
struct tnode *talloc(void)
{
    return(struct tnode *) malloc(sizeof(struct tnode));
}

/* make a duplicate of s */
char *s_dup(char *s)
{
    char *p;
    
    p = (char *)malloc(strlen(s)+1); // +1 for '\0'
    if(p != NULL)
        strcpy(p, s);
    return p;
}

#define BUFSIZE 100

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

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

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

/* getword: get next word or character from input */
int getword(char *word, int lim)
{
    int c, d; 
    int getch(void);
    void ungetch(int);
    int in_comment(void);
    char *w = word;
    
    while(isspace(c = getch()))
        ;
    if(c != EOF)
        *w++ = c;
    if(isalpha(c) || c == ' ' || c == '#')
    {
        for(;--lim > 0; w++)
            if(!isalnum(*w= getch()) && *w != '_')
            {
                ungetch(*w);
                break;
            }
    }
    else if(c=='\'' || c == '"')
    {
        for(; --lim > 0; w++)
            if((*w = getch()) == '\\')
                *++w = getch();
            else if(*w == c)
            {
                w++;
                break;
            }
            else if(*w == EOF)
                break;
    }
    else if(c == '/')
    {
        if(((d = getch()) == '*'))
            c = in_comment();
        else
            ungetch(d);
    }
    *w = '\0';
    return c;
}

/* comment */
int in_comment(void)
{
    int c;
    
    while((c = getch()) != EOF)
        if(c == '*')
        {
            if((c = getch()) == '/')
                break;
            else
                ungetch(c);
        }
    return c;
}

Result: