c程序设计语言里提到的例程

1、getline / copy 1.9节

int getline(char s[], int lim)
{
    int c, i;
    
    for(i = 0; i < lim-1 && (c=getchar())!=EOF && c != '\0'; ++i)
        s[i] = c;
    if (c == '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}
int getline(char s[], int lim)
void copy(char to[], char from[])
{
    int i;
    
    i = 0;
    while((to[i] = from[i]) != '\0')
        ++i; 
} 
void copy(char to[], char from[])

2、reverse 1.9节1.19题

#include<stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
void reverse(cahr s[]);

main()
{   
    char line[MAXLINE];

    while(getline(line, MAXLINE) > 0){
        reverse(line);
        printf("%s", line);
    }
}

void reverse(char s[])
{
    int i, j;
    char temp;
    
    i = 0;
    while(s[i] != '\0')
        ++i;
    --i;
    if (s[i] == '\n')
        --i;
    j = 0;
    while(j < i){
        temp = s[j];
        s[j] = s[i];
        s[i] = temp;
        --i;
        ++j;
    }
}
void reverse(char s[])

3.atoi 2.7节/3.5节/

int atoi(char s[])
{
    int i, n;
    n = 0;
    for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i)
        n = 10 * n + (s[i] - '0');
    return n;
}
int atoi(char s[])
#include<ctype.h>
int atoi(char s[])
{
    int i, n, sign;
    
    for(i = 0; isspace(s[i]); i++)
        ;
    sign = (s[i] == '-') > -1 : 1;
    if(s[i] == '+' || s[i] == '-')
          i++;
    for(n = 0; isdigit(s[i]); i++)
        n = 10 * n + (s[i] - '0');
    return sign * n;
}
int atoi(char s[])

4.htoi 2.7节 练习2.3

#define YES 1
#define NO 0

//convert hex string s to integer
int htoi(char s[])
{
    int hexdigit, i, inhex, n;
    i = 0;
    if(s[i] == '0'){
        ++i;
        if(s[i] == 'x' || s[i] == 'X'){
            ++i;
        }
    }
    n = 0;
    inhex = YES;
    for( ; inhex == YES; ++i){
        if(s[i] >= '0' && s[i] <= '9')
            hexdigit = s[i] - '0';
        else if(s[i] >= 'a' && s[i] <= 'z')
            hexdigit = s[i] - 'a' + 10;
        else if(s[i] >= 'A' && s[i] <= 'Z')
            hexdigit = s[i] - 'A' + 10;
        else
            inhex = NO;
           if(inhex == YES)
            n = 16 * n + hexdigit;
    }
    return n;
}
int htoi(char s[])

5.squeeze 2.8节 练习2.4。将s1中与s2中字符匹配的字符都删除

void squeeze(char s1[], char s2[])
{
    int i, j, k;
    
    for(i = k = 0; s1[i] != '\0'; i++){//k表示待匹配位置。 
        for(j = 0; s2[j] != '\0' && s2[j] != s1[j]; j++)
            ;
        if(s2[j] == '\0') // 没匹配,则将s1[i]这个字符复制到k表示的匹配后的位置。 
            s1[k++] = s1[i];
    }
    s1[k] = '\0';
}
void squeeze(char s1[], char s2[])

6.any 2.8节 练习 2.5。 返回s2中任意字符在s1中第一次出现的位置,不存在则返回-1。标准库中strpbrk函数完成同样功能,但是返回指针

int any(cha s1[], char s2[])
{
    int i, j;
    
    for(i = 0; s1[i] != '\0'; i++)
        for(j = 0; s2[j] != '\0'; j++)
            if(s1[i] == s2[j])
                return i;
    return -1;
}
int any(cha s1[], char s2[])

7.getbits 2.9节。 返回x中从右边数第p位开始(包括第p位)向右数共n位的字段

unsigned getbits(unsigned x, int p, int n)
{
    return (x >> (p+1-n)) & ~(~0 << n);
}
 (x >> (p+1-n))将相应字段移动到最右端
~0获得一组1,<<n后取反获得一组掩码
unsigned getbits(unsigned x, int p, int n)

8.setbits 2.9节 练习2.6。 将x中从右边第p位开始的n个(二进制)位设置为y中最右边n位的值,x的其余各位保持不变

unsigned setbits(unsigned x, int p, int n, unsigned y)
{
    return x & ~(~(~0 << n)  << (p+1-n)) |
          (y &   ~(~0 << n)) << (p+1-n); 
}
原始情况如下 
xxx...xnnnx...xxx x
yyy..........ynnn y

我们只要把x中的n清零,把y中除了n的位清零并移动到第p位处,然后或操作
xxx...x000x...xxx x 
000...0nnn0...000 y
-------------------
xxx...xnnnx...xxx x
unsigned setbits(unsigned x, int p, int n, unsigned y)

9.invert 2.9节 练习2.7。 将x中从右边第p位开始的n个位求反,x的其余各位保持不变

unsigned invert(unsigned x, int p, int n)
{
    return x ^ (~(~0 << n) << (p+1-n));
}
类似之前的技巧,将右边n位设置为1,然后移动到位置p
unsigned invert(unsigned x, int p, int n)

10.rightrot 2.9节 练习2.8。 将x向右循环位移n位(即移出的位会到最左端)

unsigned rightrot(unsigned x, int n)
{
    int wordlength(void);
    int rbit;
    
    while (n-- > 0){
        rbit = (x & 1) << (wordlength() - 1); //rbit将x的最右位移动到最左端
        x = x >> 1;     
        x = x | rbit; //完成循环位移 
    }
    return x;
} 

//计算出所使用的平台的字长 
int wordlength(void)
{
    int i;
    unsigned v = (unsigned) ~0;
    
    for(i = 1; (v = v >> 1) > 0; i++)
        ;
    return i;
}

//另一种解法,不使用循环 
unsigned rightrot(unsigned x, int n)
{
    int wordlength(void);
    unsigned rbits;
    
    if((n = n % wordlength()) > 0){
        rbits = ~(~0 << n) & x;
        
        rbits = rbits << (wordlength() - n);
        x = x >> n;
        x = x | rbits; 
    }
    return x;
} 
unsigned rightrot(unsigned x, int n)

11.bitcount 2.10节 练习2.9。 统计1的数量

int bitcount(unsigned x)
{
    int b;
    for(b = 0; x != 0; x &= x-1)
        ++b;
    return b;
}
int bitcount(unsigned x)

12.binsearch 3.3节

int binsearch(int x, int v[], int n)
{
    int low, high, mid;
    low = 0;
    high = n - 1;
    while(low <= high){
        mid = low + (high-low)/2;
        if(x < v[mid])
            high = mid - 1;
        else if(x > v[mid])
            low = mid + 1;
        else
            return mid;
    }
    return -1;
}
int binsearch(int x, int v[], int n)

13.escape/unescape 3.4节 练习3.2。 将字符串t复制到字符串s中,并将换行符、制表符等不可见字符换为转义字符;完成功能相反的unescape函数

void escape(char s[], char t[])
{
    int i , j;
    for(i = j = 0; t[i] != '\0'; i++)
    {
        switch(t[i]){
            case '\n':
                s[j++] = '\\';
                s[j++] = 'n';
                break;
            case '\t':
                s[j++] = '\\';
                s[j++] = 't';
                break;
            default:
                s[j++] = t[i];
                break;
        }
    }
    s[j] = '\0';
}
void escape(char s[], char t[])
void unescape(char s[], char t[])
{
    int i, j;
    for(i = j = 0; t[i] != '\0'; i++)
        switch(t[i]){
            case '\\':
                switch(t[++i]){
                    case 'n':
                        s[j++] = '\n';
                        break;
                    case 't':
                        s[j++] = '\t';
                        break;
                       default:
                           s[j++] = '\\';
                           s[j++] = t[i];
                           break;
                }
                break;
            default:
                s[j++] = t[i];
                break;
        }
    s[j] = '\0';
}
void unescape(char s[], char t[])

14.shellsort 3.5节

void shellsort(int v[], int n)
{
    int gap, i, j, temp;
    for(gap = n/2; gap > 0; gap /= 2)
        for(i = gap; i < n; i++)
            for(j = i - gap; j >= 0 && v[j] > v[j+gap]; j -= gap){
                temp = v[j];
                v[j] = v[j+gap];
                v[j+gap] = temp;
            }
}
这种实现很紧凑,但是每次v[j] > v[j+gap]都做一次完整的交换,效率不高,可以参考一般的插入排序实现,使用一个temp保存待排序数,直到最后再将temp放入数组中。
如下
void shell_sort(ElementType A[], int N)
{
    int P, D, i, temp;
    for (D = N/2 ; D>0; D/=2)
    {
        for (P = D; P < N; P++)
        {
            temp = A[P];
            for (i = P; i >= D && A[i-D] > temp; i-=D)
            {
                A[i] = A[i-D];
            }
            A[i] = temp;
        }
    }
}
void shellsort(int v[], int n)

15.reverse 3.5节

void reverse(char s[])
{
    int c, i, j;
    for(i = 0; j = strlen(s) - 1; i < j; i++, j--)
    {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}
void reverse(char s[])

16.expand 3.5节 练习3.3。 把字符串s1中类似a-z的速记符号拓展为abc...xyz的完整列表,要求拓展顺序为ascii顺序。

void expand(char s1[], char s2[])
{
    char c;
    int i, j;
    i = j = 0;
    while((c = s1[i++]) != '\0'){ //fetch a char from s1[]
        if(s1[i] == '-' && s1[i+1] >= c){
            i++;
            while(c < s1[i])
                s2[j++] = c++;
        }
        else
            s2[j++] = c;
    }
    s2[j] = '\0';
}
void expand(char s1[], char s2[])

17.itoa 3.6节/3.6节 练习3.4

void itoa(int n, char s[])
{
    int i, sign;
    
    if((sign = n) < 0)
        n = -n;
    i = 0;
    do{
        s[i++] = n % 10 + '0';
    } while((n /= 10) > 0);
    if(sign < 0)
        s[i++] = '-';
    reverse(s);
}
取数字的方向和填字符串数组的方向刚好相反。
因为n = -n,这个实现可能导致溢出。
解决溢出问题之后的版本:
#define abs(x) ((x) < 0? -(x) : (x))
void itoa(int n, char s[])
{
    int i, sign;

    sign = n;
    i = 0;
    do{
        s[i++] = abs(n % 10) + '0';
    } while((n /= 10) != 0);
    if(sign < 0)
        s[i++] = '-';
    s[i] = '\0';
    reverse(s);
}
void itoa(int n, char s[])

18.itob 3.6节 练习3.5

void itob(int n, char s[], int b)
{
    int i, j, sign;
    
    if((sign = n) < 0)
        n = -n;
    i = 0;
    do{
        j = n % b;
        s[i++] = (j <= 9) ? j+'0' : j+'a'-10;
    }while((n /= b) > 0);
    if(sign < 0)
        s[i++] = '-';
    s[i] = '\0';
    reverse(s);
}
void itob(int n, char s[], int b)

19.strindex 4.1节。 返回字符串t在s中出现位置的索引(类似strstr)

int strindex(char s[], char t[])
{
    int i, j, k;
    
    for(i = 0; s[i] != '\0'; i++){
        for(j = i; k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++)
            ;
        if(k > 0 && t[k] == '\0')
            return i;
    }
    return -1;
}
int strindex(char s[], char t[])

20.strrindex 4.1节 练习4.1。 返回字符串t在s中最右边出现位置的索引

int strrindex(char s[], char t[])
{
    int i, j, k;
    for(i = strlen(s) - strlen(t); i >= 0; i--)
    {
        for(j = i, k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++)
            ;
        if(k > 0 && t[k] == '\0')
            return i;
    }
    return -1;
}
int strrindex(char s[], char t[])

21.qsort 4.10节

void qsort(int v[], int left, int right)
{
    int i, last;
    if(left >= right)
        return;
    swap(v, left, left+(right-left)/2);
    last = left;
    for(i = left+1; i <= right; i++)
        if(v[i] < v[left])
            swap(v, ++last, i);
    swap(v, left, last);
    qsort(v, left, last-1);
    qsort(last+1, right);
}
void qsort(int v[], int left, int right)
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);
}
void qsort(void *v[], int left, int right, int(*comp)(void *, void *))

 

22.strcpy 5.5节

void strcpy(char *s, char *t)
{
    while(*s++ == *t++)
        ;
    return;
}
void strcpy(char *s, char *t)
1 应该使用的完善的版本
2 char *strcpy(char *strDest, const char *strSrc)
3 {
4     assert((strDest!=NULL) && (strSrc !=NULL));   
5     char *address = strDest;                     
6     while( (*strDest++ = * strSrc++) != ‘\0’ )
7        ;
8     return address ;                           
9 }

23.strcmp 5.5节

int strcmp(char *s. char *t)
{
    for( ; *s == *t; s++, t++)
        if(*s == '\0')
            return 0;
    return *s - *t;
}
int strcmp(char *s. char *t)

24.strend 5.5节 练习5.3。 如果字符串t出现在字符串s的尾部,函数返回1;否则返回0

int strend(char *s, char *t)
{
    char *begin_s = s;
    char *begin_t = t;
    
    for( ; *s; s++)
        ;
    for( ; *t; t++)
        ;
    for( ; *s == *t; s--, t--)
        if(t == begin_t || s == begin_s)
            break;
    if(*s == *t && t == begin_t && *s != '\0')
        return 1;
    else
        return 0;
}
int strend(char *s, char *t)

25.find 5.10节。 对命令<find -x -n 模式>返回与x不匹配的行,-x表示除此之外,-n表示显示行号

#include<stdio.h>
#include<string.h> 
#define MAXLINE 1000
int getline(char *line, int max);

int main(int argc, char *argv[])
{
    char line[MAXLINE];
    long lineno = 0;
    int c, except = 0, number = 0, found = 0;
    
    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;
                       found = -1;
                       break;
            }
        if(argc != 1)
            printf("Usage: find -x -n pattern\n");
        else
            while(getline(line, MAXLINE) > 0){
                lineno++;
                if((strstr(line, *argv) != NULL) != except){
                    if(number)
                        printf("%ld:", lineno);
                    printf("%s", line);
                    found++;
                }
            }
        return found;
}
find

26.tail 5.10节 练习5.13。 使用命令tail -n将输入中的后n行打印出来

 

5.11节 练习5.14~5.17 命令行参数解析

练习5.20 语义解析6.4节 词频统计

6.6节 表查找核心代码

 

 tip:

1:文件描述符0、1、2对应stdin、stdout、stderr

2:read/write()返回实际传输字节数,在读文件时,函数的返回值可能小于请求的字节数;在写文件时,如果返回值与请求值不同则可能发生了错误。返回0表示到达文件结尾,返回-1表示发生某种错误。

3:

 

1、printf / scanf

知识点:变长参数函数使用:

头文件#include<stdarg.h>

使用va_list ap; 来声明一个变长参数类型的变量ap,即argument pointer。

使用va_start(ap, fmt); fmt为最后一个有名参数(函数原型void print(char *fmt, ...)),ap将被设置为指向第一个无名参数的指针。

使用ival = va_arg(ap, int);来获得一个参数,类型由va_arg的第二个参数决定,并且ap指向下一个参数。

va_end(ap); 在函数返回前调用,完成相关清理工作。

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

int main()
{
    print("%d %d",1,2);
    return 0;
}

void print(char *fmt, ...)
{
    va_list ap;
    char *p, *sval;
    int ival;
    double dval;
    
    va_start(ap, fmt);
    for(p = fmt; *p; p++){
        if(*p != '%'){
            putchar(*p);
            continue;
        }
        switch (*++p) { //略过% 
            case 'd':
                ival = va_arg(ap, int);
                printf("%d", ival);
                break;
            case 'f':
                dval = va_arg(ap, double);
                printf("%f", dval);
                break;
            case 's':
                for(sval = va_arg(ap, char *); *sval; sval++)
                    putchar(*sval);
                break;
            default:
                putchar(*p);
                break;
        }
    }
    va_end(ap);
}
void print(char *fmt, ...)

 因为类型提升的问题,未被声明的参数会被提升为int和double,所以var_arg(ap, char)和var_arg(ap,float)错误的。

posted @ 2016-09-22 22:45  autoria  阅读(489)  评论(0编辑  收藏  举报