The C Programming Language

说明:该篇用于记录The C Programming Language中遇到的习题,留待回头复习使用。习题中定当存在不完善的描述和解题思路,热烈欢迎各路高手提出宝贵意见。

题0:1-11,你准备如何测试单词计数程序? 如果程序中存在某种错误,那么什么样的输入最有可能发现这类错误呢?

//搬运的答案,完全未理解如何测试
#include<assert.h>
#include<stdio.h>

int main()
{
    FILE *f;
    unsigned long i;
    static char *ws = " \f\t\v";
    static char *a1 = " abcdefghijklmnopqrstuvwxyz";
    static char *i5 = " a b c d e f g h i j k l"
    "m n o p q r s t u v w x y z"
    " a b c d e f g h i j k l"
    "m n o p q r s t u v w x y z""n\n";

    /*Generate the following:*/
    /* 0. input file contains zero words */
    f = fopen("test0", "w");
    assert(f != NULL);
    fclose(f);

    /* 1. input file contains 1 enormous word without any newlines */
    f = fopen("test1", "w");
    assert(f != NULL);
    for (i = 0; i < ( (66000ul /26) + 1); i++)
    {
        fputs(a1, f);

    }
    fclose(f);

    /* 2. inoout file contains all white space without newlines */
    f = fopen("test2", "w");
    assert(f != NULL);
    for (i = 0; i < ((66000ul /4) +1); i++)
    {
        fputs(ws, f);
    }
    fclose(f);


    /* 3. input file contains 660000 newlines */
    f = fopen("test3", "w");
    assert(f != NULL);
    for (i = 0; i < 66000; i++)
    {
        fputs('\n',f);
    }
    fclose(f);

    /* 4. input file contains word/
     *
     *  {huge sequence of whitespace of different kinds word}
     */
     f = fopen("test4", "w");
     assert (f != NULL);
     fputs("word", f);
     for (i = 0; i < ((66000ul /26) + 1); i++)
     {
         fputs(ws, f);
     }
     fputs("word", f);
     fclose(f);

    /* 5. input file contains 66000 single letter words,
     *     66 to the line
     */
     f = fopen("test5", "w");
     assert (f != NULL);
     for (i = 0; i < 1000; i++)
     {
         fputs(i5, f);
     }
     fclose(f);

     /* 6. input file contains 66000 words without any newlines  */
    f = fopen("test6", "w");
    assert(f != NULL);
    for(i = 0; i < 66000; i++)
    {
        fputs("word ", f);
    }
    fclose(f);

    return 0;
}


题1:编写一个程序,每个字符占据一行进行输出

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

#define IN 1   //在单词内部
#define OUT 0  //在单词外部
int main()
{
    int c, state;
    c = getchar();
    state = OUT;

    while(c != EOF)
    {
        if(c == '\n' || c == '\t' || c== ' ')
        {
            state = OUT;
        }
        else if(state == OUT)      //①注意理解此处的state == OUT
        {
            state = IN;
            putchar(c);
            state = OUT;   //②注意理解此处的state = OUT
            putchar('\n');
        }

        c = getchar();
    }
}

题1.1:以每行一个单词的形式打印其输出

//存在bug,版本v1.0,有完善的版本v2.0紧接在下面
#include<stdio.h>
#define IN 1
#define OUT 0
int main()
{
    int c, state;
    state = OUT;

    while ((c = getchar()) != EOF)
    {
        if (c == '\n' || c == '\t' || c == ' ')
        {
            state = OUT;
            printf("\n");
        }
        else if (state == OUT)
        {
            state = IN;
            putchar(c);
            state = OUT;
        }
    }
}

//不完美的地方在于,如果输入的开头为空格、换行、制表符,则输出的最前端会空一行或者多行,解决的办法加入一个判断语句,判断上个字符的状态,见下面。
//完善版本v2.0
#include<stdio.h>
#define IN 1
#define OUT 0
int main()
{
    int c, laststate, state;
    state = OUT;
    laststate = OUT;   //上一个字符的状态:不在单词内部

    while ((c = getchar()) != EOF)
    {
        if (c == '\n' || c == '\t' || c == ' ')
        {
            state = OUT;
            if (laststate == IN )  //当前字符在单词外部,上个字符在单词内部时,输出换行符。
            {
                putchar('\n');
            }

        }
        else
        {
            state = IN;
            putchar(c);
        }
        laststate = state;
    }
}

题2:编写一个将输入复制到输出的程序,并将其中连续的多个空格用一个空格代替

//搬运答案及自己的理解
#include <stdio.h>
#define NONBLANK 'a'    //统一处理的作用;
int main()
{
   int c, lastc;
   lastc = NONBLANK;  //最大的用处是用来处理开头即有几个连续的空格的情况
   while((c = getchar()) != EOF)
   {
       if (c != ' ')
       {
           putchar(c);    //当前不是空格,直接输出
       }
       else                  //当前是空格。
       {
           if (lastc != ' ')    //若上个字符不是空格,则直接输出当前空格; 若上个字符是空格,则不做处理;   总之任意多个空格只输出第一个空格。
           {
               putchar(c);
           }
       }
       lastc = c;  //更新lastc
   }
}

题3:编写一个将输入复制到输出端的程序,并将其中的制表符替换为\t,把回退符替换为\b,把反斜杠替换为\。这样可以将制表符和回退符以可见的方式显示出来。

//搬运答案
#include<stdio.h>
int main()
{
    int c;

    while((c = getchar()) != EOF)
    {
        if (c == '\t')
        {
            printf("\\t");
        }
        if (c == '\b')
        {
            printf("\\b");
        }
        if (c == '\\')
        {
            printf("\\\\");
        }

        if (c != '\t')
        {
            if (c != '\b')
            {
                if (c != '\\')
                {
                    putchar(c);
                }
            }
        }
    }
}

题4:编写一个程序,打印输入中各个字符出现频度的直方图。

//搬运的源代码。
#include <stdio.h>
#include <ctype.h>
#define MAXHIST 15
#define MAXCHAR 128

int main()
{
    int c, i;
    int len; //length of each bar//
    int maxvalue; //maximum value for cc[]//
    int cc[MAXCHAR]; //character counters //

    for(i = 0; i < MAXCHAR; ++i)
    {
      cc[i] = 0;
    }

    while ((c = getchar()) != EOF)
    {
        if (c < MAXCHAR)
        {
            ++cc[c];
        }

    }

    maxvalue = 0;
    for(i = 1; i < MAXCHAR; ++i)
    {
        if(cc[i] > maxvalue)
            {
                maxvalue = cc[i];
            }
    }


    for (i = 1; i <MAXCHAR; ++i)
    {
        if(isprint(i))
        {
            printf("%5d - %c - %5d :", i, i, cc[i]);
        }
        else
        {
            printf("%5d - - %5d :", i, cc[i]);
        }

        if (cc[i] > 0)
        {
            if ((len = cc[i] * MAXHIST / maxvalue) <= 0)
            len = 1;
        }
        else
        {
            len = 0;
        }

        while(len > 0)
        {
            putchar('*');
            --len;
        }
        putchar('\n');
    }

}


题目5:1-16,修改打印最长文本行的程序的主程序main,使之可以打印任意输入行的长度,并尽可能多的打印文本。

//修改前的程序
#include<stdio.h>
#define MAXLINE 1000   //最大的输入长度

int getline(char line[], int maxline);
void copy(char to[], char from[]);

/*打印最长的输入行*/
int main()
{
    int len;  //当前行的长度
    int max;  //此前的最大长度
    char line[MAXLINE];  //当前输入行
    char longest[MAXLINE];    //保存最长的输入行

    max = 0;
    while ((len = getline(line, MAXLINE)) > 0)
        if (len > max)
        {
              max = len;
              copy(longest, line);
         }
    if (max > 0)    //有这样的输入行
         printf("%s", longest);
    return 0;
}


// getline: 把输入读入数组s,返回其长度

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')      //是否可以合并在for循环中。不可以,否则区分不开每行
    {
        s[i] = c;   
        ++i;
    }
    s[i] = '\0';
    return i;
}

//copy:复制函数;此处假设内存空间足够大
void copy(char to[], char from[])
{
     int i;

    i = 0;
    while ((to[i] = from[i]) != '\0')  
          ++i; 
}
//修改后的程序
#include<stdio.h>
#define MAXLINE 1000   //最大的输入长度

int getline(char line[], int maxline);
void copy(char to[], char from[]);

/*打印最长的输入行*/
int main()
{
    int len;  //当前行的长度
    int max;  //此前的最大长度
    char line[MAXLINE];  //当前输入行
    char longest[MAXLINE];    //保存最长的输入行

    max = 0;
    while ((len = getline(line, MAXLINE)) > 0)
        printf("%d, %s",len,line);
        if (len > max)
        {
              max = len;
              copy(longest, line);
         }
        if (max > 0)    //如果有这样的输入行,则打印输出
            printf("%s", longest);
    return 0;
}


// getline: 把输入读入数组s,返回其长度

int getline(char s[], int lim)
{
    int c, i, j;
    j = 0;
    for (i = 0; (c = getchar()) != EOF && c != '\n'; ++i)
    {
        if (i < lim - 2)
        {
            s[j] = c;
            ++j;
        }

    }
    if (c == '\n')      //是否可以合并在for循环中。不可以,否则区分不开每行
    {
        s[j] = c;
        ++i;
        ++j;
    }
    s[j] = '\0';
    return i;
}

//copy:复制函数;此处假设内存空间足够大
void copy(char to[], char from[])
{
     int i;

     i = 0;
    while ((to[i] = from[i]) != '\0')
          ++i;
}
//原书作者的代码V1.0,仔细思考
#include <stdio.h>

#define MAXLINE 3

int getline(char line[], int maxline);
void copy(char to[], char from[]);
int main()
{
    int len;
    int max;
    char line[MAXLINE];
    char longest[MAXLINE];

    max = 0;

    while ((len = getline(line, MAXLINE)) > 0)
    {
        printf("%d : %s", len, line);

        if (len > max)
        {
            max = len;
            copy(longest, line);
        }
    }

    if (max > 0)
    {
        printf("Longest is %d characters:\n%s", max, longest);

    }
    printf("\n");

    return 0;
}

int getline(char s[], int lim)
{
    int c, i, j;

    for (i = 0, j = 0; (c = getchar()) != EOF && c != '\n'; ++i)
    {
        if (i < lim - 1)
        {
            s[j++] = c;
        }
    }
    if (c == '\n')
    {
        if (i <= lim - 1)
        {
            s[j++] = c;
        }
        i++;
    }
    s[j] = '\0';
    return i;
}

void copy(char to[], char from[])
{
    int i;

    i = 0;
    while ((to[i] = from[i]) != '\0')
    {
        ++i;
    }
}

//原书作者的代码V2.0
#include<stdio.h>

#define MAXLINE 20

int getline(char s[], int lim);
void copy(char to[], char from[]);

int main()
{
    char line[MAXLINE];
    char longest[MAXLINE];
    char temp[MAXLINE];
    int len, max, premax, getmore;

    max = premax = getmore = 0;

    while ((len = getline(line, MAXLINE)) > 0)
    {
        if (line[len - 1] != '\n')
        {
            if(getmore == 0)
            {
                copy(temp, line);
            }
            premax += len;
            if(max < premax)
            {
                max = premax;
            }
            getmore = 1;
        }
        else
        {
            if (getmore == 1)
            {
                if (max < premax + len)
                {
                    max = premax + len;
                    copy(longest, temp);
                    longest[MAXLINE - 2] = '\n';
                }
                getmore = 0;
            }
            else if (max < len)
            {
                max = len;
                copy(longest, line);
            }
            premax = 0;
        }
    }
    if (max > 0)
    {
        printf("%s", longest);
        printf("len = %d\n", max);
    }
    return 0;
}

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;
    }
    else if (c == EOF && i > 0)
    {
        /*  gotta do something about no newline preceding
         *  EOF
         */
         s[i] = '\n';
         ++i;
    }
    s[i] = '\0';
    return i;
}

void copy(char to[], char from[])
{
    int i;

    i = 0;
    while ((to[i] = from[i]) != '\0')
    {
        ++i;
    }
}

题目6:1-13,编写一个程序,打印输入中单词长度的直方图,水平方向的直方图比较容易绘制,垂直方向的难些。

//搬运答案,还未理解
//水平方向
#include <stdio.h>
#define MAXHIST 15
#define MAXWORD 11
#define IN 1
#define OUT 0

int main()
{

int c, i, nc, state;
int len;
int maxvalue;
int ovflow;
int wl[MAXWORD];

state = OUT;
nc = 0;
ovflow = 0;
for (i = 0; i < MAXWORD; ++i)
wl[i] = 0;
while((c = getchar()) != EOF)
{
if(c == ' ' || c == '\n' || c == '\t')
{
state = OUT;
if (nc > 0)
if (nc < MAXWORD)
++wl[nc];
else
++ovflow;
nc = 0;
}else if (state == OUT)
{
state = IN;
nc = 1;
}else
++nc;
}
maxvalue = 0;
for (i = 1; i < MAXWORD; ++i)
if (wl[i] > maxvalue)
maxvalue = wl[i];
for (i = 1; i < MAXWORD; ++i)
{
printf("%5d - %5d :", i, wl[i]);
if (wl[i] > 0)
{
if ((len = wl[i] * MAXHIST / maxvalue) <= 0)
len = 1;
}else
len = 0;
while (len > 0)
{
putchar('*');
--len;
}
putchar('\n');
}
if (ovflow > 0)
printf ("There are %d words >= %d\n", ovflow, MAXWORD);
}



//垂直方向直方图,格式存在问题,待解决
#include <stdio.h>
#define MAXHIST 15
#define MAXWORD 11
#define IN 1
#define OUT 0

int main()
{

int c, i, nc, j, state;
int len;
int maxvalue;
int ovflow;
int wl[MAXWORD];

state = OUT;
nc = 0;
ovflow = 0;
for (i = 0; i < MAXWORD; ++i)
wl[i] = 0;
while((c = getchar()) != EOF)
{
if(c == ' ' || c == '\n' || c == '\t')
{
state = OUT;
if (nc > 0)
if (nc < MAXWORD)
++wl[nc];
else
++ovflow;
nc = 0;
}else if (state == OUT)
{
state = IN;
nc = 1;
}else
++nc;
}
maxvalue = 0;
for (i = 1; i < MAXWORD; ++i)
if (wl[i] > maxvalue)
maxvalue = wl[i];
for (i = MAXHIST; i > 0; --i)
{
for(j = 1; j < MAXWORD; ++j)
if(wl[j] * MAXHIST / maxvalue >= i)
printf(" * ");
else
printf(" ");
putchar('\n');

}
for(i = 1; i < MAXWORD; ++i)
printf("%4d", i);
putchar('\n');
for(i = 1; i < MAXWORD; ++i)
printf("%4d", wl[i]);
putchar('\n');
if(ovflow > 0)
printf("There are %d words >= %d\n", ovflow, MAXWORD);

}
//原书作者的代码,经过修改多次。空闲下来仔细拜读。
#include<stdio.h>

#define MAXWORDLEN 10

int main()
{
    int c;
    int inspace = 0;
    long lengtharr[MAXWORDLEN + 1];
    int wordlen = 0;

    int firstletter = 1;
    long thisval = 0;
    long maxval = 0;
    int thisidx = 0;
    int done = 0;

    for (thisidx = 0; thisidx <= MAXWORDLEN; thisidx++)
    {
        lengtharr[thisidx] = 0;
    }

    while (done == 0)
    {
        c = getchar();

        if (c == ' ' || c == '\t' || c == '\n' || c == EOF)
        {
            if (inspace == 0)
            {
                firstletter = 0;
                inspace = 1;

                if (wordlen <= MAXWORDLEN)
                {
                    if (wordlen > 0)
                    {
                        thisval = ++lengtharr[wordlen - 1];
                        if (thisval > maxval)
                        {
                            maxval = thisval;
                        }
                    }
                }
                else
                {
                    thisval = ++lengtharr[MAXWORDLEN];
                    if (thisval > maxval)
                    {
                        maxval = thisval;
                    }
                }
            }
            if (c == EOF)
            {
                done = 1;
            }
        }
        else
        {
            if (inspace == 1 || firstletter == 1)
            {
                wordlen = 0;
                firstletter = 0;
                inspace = 0;
            }
            ++wordlen;
        }
    }

    for (thisval = maxval; thisval > 0; thisval--)
    {
        printf("%4d | ", thisval);
        for (thisidx = 0; thisidx <= MAXWORDLEN; thisidx++)
        {
            if (lengtharr[thisidx] >= thisval)
            {
                printf("*  ");
            }
            else
            {
                printf("   ");
            }
        }
        printf("\n");
    }
    printf("    +");
    for (thisidx = 0; thisidx <= MAXWORDLEN; thisidx++)
    {
        printf("----");
    }
    printf("\n    ");
    for(thisidx  = 0; thisidx < MAXWORDLEN; thisidx++)
    {
        printf("%2d ", thisidx + 1);
    }
    printf(">%d\n", MAXWORDLEN);
    return 0;
}


题目6.1:1-14,编写一个程序,打印输入中各个字符出现频度的直方图。

//搬运答案,代码未理解
#include<stdio.h>

/* NUM_CHARS should really be CHAR_MAX but K&R
 * haven't covered that at this stage in the book
 */
#define NUM_CHARS 256

int main()
{
    int c;
    int freqarr[NUM_CHARS + 1];

    long thisval = 0;
    long maxval = 0;
    int thisidx = 0;


    for (thisidx = 0; thisidx <= NUM_CHARS; thisidx++)
    {
        freqarr[thisidx] = 0;
    }

    while ((c = getchar()) != EOF)
    {
        if (c < NUM_CHARS)
        {
            thisval = ++freqarr[c];
            if (thisval > maxval)
            {
                maxval = thisval;
            }
        }
        else
        {
            thisval = ++freqarr[NUM_CHARS];
            if (thisval > maxval)
            {
                maxval = thisval;
            }
        }
    }

    for (thisval = maxval; thisval > 0; thisval--)
    {
        printf("%4d  |", thisval);
        for (thisidx = 0; thisidx <= NUM_CHARS; thisidx++)
        {
            if (freqarr[thisidx] >= thisval)
            {
                printf("*");
            }
            else if (freqarr[thisval] > 0)
            {
                printf(" ");
            }
        }
        printf("\n");
    }
    printf("    +");
    for (thisidx > 0; thisidx <= NUM_CHARS; thisidx++)
    {
        if (freqarr[thisidx] > 0)
        {
            printf("-");
        }
    }
    printf("\n    ");
    for (thisidx = 0; thisidx < NUM_CHARS; thisidx++)
    {
        if (freqarr[thisidx] > 0)
        {
            printf("%d", thisidx /100);
        }
    }
    printf("\n    ");
    for (thisidx = 0; thisidx < NUM_CHARS; thisidx++)
    {
        if (freqarr[thisidx] > 0)
        {
            printf("%d", (thisidx - (100 * (thisidx / 100))) / 10);
        }
    }
    if (freqarr[NUM_CHARS] > 0)
    {
        printf("%d\n", NUM_CHARS);
    }
    printf("\n");

    return 0;
}

题目7:1-17,编写一个程序,打印长度大于80个字符的所有输入行

#include <stdio.h>
#define MAXLINE 100    //允许输入行的最大长度
#define LONGLINE 80
int getline(char line[], int maxline);,使空格充满到下一个

// 打印比LONGLINE长的所有行
int main()
{
    int len;    //当前行的长度

    char line[MAXLINE];

    while((len = getline(line, MAXLINE)) > 0)  // 此处注意不可以直接改为大于80,否则条件可能为假,不满足题意。
    {
        if (len > LONGLINE)
        {
            printf("%s\n",line);
        }
    }
    return 0;
}

int getline(char s[], int lim)
{
    int c, i, j;
    j = 0;
    for (i = 0;(c = getchar()) != EOF && c != '\n'; ++i)
    {
        if (i < lim - 2)
        {
            s[j] = c;
            ++j;
        }
    }
    if (c == '\n')
    {
        s[j] = c;
        ++i;
        ++j;
    }
    s[j] = '\0';
    return i;
}
//原书作者源代码
#include<stdio.h>

#define MINLENGTH 81

int readbuff(char *buffer)
{
    size_t i = 0;
    int c;
    while (i < MINLENGTH)
    {
        c = getchar();
        if (c == EOF) return -1;
        if (c == '\n') return 0;
        buffer[i++] = c;
    }
    return 1;
}

int copyline(char *buffer)
{
    size_t i;
    int c;
    int status = 1;
    for (i = 0; i < MINLENGTH; i++)
    {
        putchar(buffer[i]);
    }
    while (status == 1)
    {
        c = getchar();
        if (c == EOF)
        {
            status = -1;
        }
        else if (c =='\n')
        {
            status = 0;
        }
        else
        {
            putchar(c);
        }
    }
    putchar('\n');
    return status;
}

int main()
{
    char buffer[MINLENGTH];
    int status = 0;
    while (status != -1)
    {
        status = readbuff(buffer);
        if (status == 1)
        {
            status = copyline(buffer);
        }
    }
    return 0;
}

题目8:1-18,编写一个程序,删除每个输入行末尾的空格及制表符,并删除完全是空格的行。

题目9:1-19,编写函数reverse(s),将字符串s中的字符顺序倒过来。使用该函数编写一个程序,每次颠倒一个输入行中的字符串顺序。


题目10:1-20,编写程序detab,将输入中的制表符替换为适当数目的空格,使空格充满到下一个制表符终止位的地方,假设制表符终止位的位置是固定的,比如每隔n列就会出现一个制表符的终止位。n应该作为变量还是符号常量呢?


题目11:1-21,编写程序entab,将空格串替换为最少数量的制表符和空格,但要保持单词之间的间隔不变。假设制表符终止位的位置与练习1-20的detab程序的情况相同。当使用一个制表符或者一个空格都可以达到下一个制表符的终止位时,选用哪一种替换字符比较好?


题目12:1-22,编写一个程序,把较长的输入行“折”成短一些的两行或者多行,折行的位置在输入行的第n列之前的最后一个非空格之后。要保证程序能够智能的处理输入行很长以及在指定的列前没有空格都可以达到下一个制表符时的情况。


题目13:1-23,编写一个删除C语言程序中所有的注释语句。要正确处理带引号的字符串和字符常量。在C语言中,注释不允许嵌套。


题目14:1-24,编写一个程序,查找C语言程序中的基本语法错误,如圆括号,方括号,花括号不配对等。要正确处理引号(包括单引号和双引号)、转义字符序列与注释。(如果读者想把该程序编写成完全通用的程序,难度会比较大)。


题目11:2-1,编写一个程序以确定分别由signed及unsigned限定的char、short、int与long类型变量的取值范围。采用打印标准头文件中的相应的值以及直接计算两种方式实现。后一种方法的实现比较困难,因为要确定各种浮点类型的取值范围。

//搬运答案
//通过打印标准头文件实现
#include<stdio.h>
#include<limits.h>

int main()
{
    //signed types

    printf("signed char min = %d\n", SCHAR_MIN);
    printf("signed char max = %d\n", SCHAR_MAX);
    printf("signed short min = %d\n", SHRT_MIN);
    printf("signed short max = %d\n", SHRT_MAX);
    printf("signed int min = %d\n", INT_MIN);
    printf("signed int max = %d\n", INT_MAX);
    printf("signed long min = %d\n", LONG_MIN);
    printf("signed int max = %d\n", LONG_MAX);

    //unsigned types


    printf("unsigned char max = %d\n", UCHAR_MAX);
    printf("unsigned short max = %d\n", USHRT_MAX);
    printf("unsigned int max = %d\n", UINT_MAX);
    printf("unsigned int max = %d\n", ULONG_MAX);
}

//搬运答案
//直接计算方式实现
#include<stdio.h>

int main()
{
    //signed ranges of types
    printf("signed char min = %d\n", -(char)((unsigned char) ~ 0 >> 1));

    printf("signed char max = %d\n", (char)((unsigned char) ~ 0 >> 1));

    printf("signed short min = %d\n", -(short)((unsigned short) ~ 0 >> 1));

    printf("signed short max = %d\n", (short)((unsigned short) ~ 0 >> 1));

    printf("signed int min = %d\n", -(int)((unsigned int) ~ 0 >> 1));

    printf("signed int max = %d\n", (int)((unsigned int) ~ 0 >> 1));

    printf("signed long min = %d\n", -(long)((unsigned long) ~ 0 >> 1));

    printf("signed long max = %d\n", (long)((unsigned long) ~ 0 >> 1));



    //unsigned types
    printf("unsigned char max = %d\n", (unsigned char) ~ 0 );

    printf("unsigned int max = %d\n", (unsigned int) ~ 0 );

    printf("unsigned short max = %d\n", (unsigned short) ~ 0 );

    printf("unsigned long max = %d\n", (unsigned long) ~ 0 );
}

//占坑位置,并未理解这种方式

题目12:2-2,在不使用运算符&&或||的条件下编写一个与上面的for循环语句等价的循环。

//原循环语句
for (i = 0; i < lim - 1 && (c = getchar()) != '\n' && c != EOF; ++i)
{
        s[i] = c;
}

//不使用&&或者 || 版本V1.0
#include<stdio.h>

#define MAX_STRING_LENGTH 100

int main ()
{
    int i = 0,
        lim = MAX_STRING_LENGTH,
        c;

    char s[MAX_STRING_LENGTH];

    while (i < lim - 1)
    {
        c = getchar();

        if (c == EOF)        //思考一下,这里能否改为 c != EOF?
        {
            break;
        }
        else if (c == '\n')
        {
            break;
        }

        s[i++] = c;
    }
    s[i] = '\0';
    printf("%s",s);
    return 0;
}
//上面思考提出的改法
for ( i = 0; i < lim - 1; i++)
{
    if ((c = getchar()) != '\n')
    {
        if (c != EOF )
        {
            s[i] = c;
        }
    }


/*  答案是不建议这样改,因为这样会一直循环,直到最大行MAX_STRING_LENGTH。
//原书源代码
//不使用&&或者 || 版本V2
//还未理解哈
#include<stdio.h>

#define lim 80

int main()
{
    int i, c;
    char s[lim];

    /*  There is a sequence point after the first
     *   operand of ?:
     */

     for (i = 0; i < lim - 1 ? (c = getchar()) != '\n' ? c != EOF : 0 : 0; ++i)
     {
         s[i] = c;
     }

     return s[i] ^= s[i];
     printf("%s", s);
}

题目13:2-3,编写函数htoi(s),把由十六进制数字组成的字符串(包含可选的0x或0X)转换为与之等价的整型值。字符串中允许包含的数字包括:09、af以及A~F。

//原文作者源代码
//测试部分还未理解
#include<stdio.h>
#include<stdlib.h>
/* Here's a helper function to get me around
 * the problem of not having strchr
 */

 /*  处理十六进制中的字母部分 a~f和A~F*/
int hexalpha_to_int(int c)
{
    char hexalpha[] = "aAbBcCdDeEfF";
    int i;
    int answer = 0;

    for (i = 0; answer == 0 && hexalpha[i] != '\0'; i++)
    {
        if (hexalpha[i] == c)
        {
            answer = 10 + (i / 2);
        }
    }
    return answer;
}

unsigned int htoi(const char s[])
{
    unsigned int answer = 0;
    int i = 0;
    int valid = 1;
    int hexit;

    if (s[i] == '\0')   //处理可选的“0x"或者”0X"
    {
        ++i;
        if (s[i] == 'x' || s[i] == 'X')
        {
            ++i;
        }
    }

    while (valid && s[i] !='\0')
    {
        answer = answer * 16;
        if (s[i] >= '0' && s[i] <= '9')
        {
            answer = answer + (s[i] - '0');
        }
        else
        {
            hexit = hexalpha_to_int(s[i]);
            if (hexit == 0)
            {
                valid = 0;
            }
            else
            {
                answer = answer + hexit;
            }
        }
        ++i;
    }
    if (!valid)
    {
        answer = 0;
    }

    return answer;
}

/* Solution finished. This bit's just a test driver,
 * so I've relaxed the rules on what's allowed.
 */

 int main()
 {
     char *endp = NULL;
     char *test[] =
     {
         "F00",
         "bar",
         "0100",
         "0x1",
         "0xA",
         "0X0C0BE",
         "abcdef",
         "123456",
         "0x123456",
         "deadbeef",
         "zog_c"
     };

     unsigned int result;
     unsigned int check;

     size_t numtests = sizeof test / sizeof test[0];

     size_t thistest;

     for (thistest = 0; thistest < numtests; thistest++)
     {
         result = htoi(test[thistest]);
         check = (unsigned int)strtoul(test[thistest], &endp, 16);

         if ((*endp != '\0' && result == 0) || result == check)
         {
             printf("Testing %s. Correct. %u\n", test[thistest], result);
         }
         else
         {
             printf("Testing %s. Incorrect. %u\n", test[thistest], result);

         }
     }
     return 0;
 }

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

long hchartoi (char hexdig, int pos);    /* converts
    a hex char to decimal knowing its 0 based place value*/
long htoi (char hexstring[]);    /* converts a string of hex bits to integer */


int main()
 {
     char *endp = NULL;
     char *test[] =
     {
         "F00",
         "bar",
         "0100",
         "0x1",
         "0xA",
         "0X0C0BE",
         "abcdef",
         "123456",
         "0x123456",
         "deadbeef",
         "zog_c"
     };

     long int result;
     long int check;

     size_t numtests = sizeof test / sizeof test[0];

     size_t thistest;

     for (thistest = 0; thistest < numtests; thistest++)
     {
         result = htoi(test[thistest]);
         check = (unsigned int)strtoul(test[thistest], &endp, 16);

         if ((*endp != '\0' && result == 0) || result == check)
         {
             printf("Testing %s. Correct. %ld\n", test[thistest], result);
         }
         else
         {
             printf("Testing %s. Incorrect. %ld\n", test[thistest], result);

         }
     }
     return 0;
 }

long htoi(char s[])
{
    char *p = &s[strlen(s) - 1];
    long deci = 0, dig = 0;
    int pos = 0;

    while (p > s)
    {

        if ((dig = hchartoi(*p, pos)) < 0)
        {
            printf("Error\n");
            return -1;
        }
        deci += dig;
        --p;
        ++pos;
    }
    return deci;
}

long hchartoi (char hexdig, int pos)
{

    char hexdigits[] = "0123456789ABCDE";
    char *p = &hexdigits[0];
    long deci = 0;
    int i;

    while (*p != toupper(hexdig) && deci < 16)
    {
        ++p;
        ++deci;
    }

    if (*p == toupper(hexdig))
    {
        for (i = 0; i < pos; i++)
        {
            deci *= 16;
        }
        return deci;
    }
    return -1;
}

题目14:2-4,squeeze(s1, s2), 将字符串s1中任何与字符串s2中字符匹配的字符都删除。

#include<stdio.h>
#define MAXLENGTH 100

void squeeze(char t[], char f[]);
int main()
{
    char s1[]="abcdefghij";
    char s2[]="abcde";


    squeeze(s1, s2);
    return 0;
}
void squeeze(char to[], char from[])
{
    char new[MAXLENGTH];
    int i, j, n;

    i = j = n =0;

    while (to[i] != '\0')
    {
            j = 0;
            while (from[j] != '\0')
            {

                if (to[i] == from[j])
                {
                    break;
                }
                j++;
            }
            if (from[j] == '\0')
            {
                new[n++] = to[i];
            }

            i++;
    }
    new[n] = '\0';
    printf("%s", new);
}
//原书源代码,打印格式值得借鉴
/* squeeze2: delete all characters occurring in s2
 * from string s1.
 */

 void squeeze2(char s1[], char s2[])
 {
     int i, j, k;
     int instr2 = 0;

     for (i = j = 0; s1[i] != '\0'; i++)
     {
         instr2 = 0;
         for (k = 0; s2[k] != '\0' && !instr2; k++)
         {
             if (s2[k] == s1[i])
             {
                 instr2 = 1;
             }
         }

         if (!instr2)
         {
             s1[j++] = s1[i];
         }
     }
     s1[j] = '\0';
 }

 /* test driver */
#include<stdio.h>
#include<string.h>

int main()
{
    char *leftstr[]=
    {
        "",
        "a",
        "antidisetestablishmentarianism",
        "beautifications",
        "deterministically"
        "electroencephalography",
        "familiarisation",
        "gastrointestinal"
    };

    char *rightstr[]=
    {
        "",
        "a",
        "the",
        "quick",
        "brown"
        "dog",
        "jump",
        "over"
    };

    char buffer[32];
    size_t numlefts =sizeof leftstr / sizeof leftstr[0];
    size_t numrights =sizeof rightstr / sizeof rightstr[0];
    size_t left = 0;
    size_t right = 0;

    for (left = 0; left < numlefts; left++)
    {
        for (right = 0; right < numrights; right++)
        {
            strcpy(buffer, leftstr[left]);
            squeeze2(buffer, rightstr[right]);

            printf("[%s] - [%s] = [%s]\n", leftstr[left], rightstr[right], buffer);
        }
    }
    return 0;
}

题目15:2-5,编写函数any(s1, s2), 将字符串s2中的任一字符在s1中第一次出现的位置作为返回结果返回。如果s1中不包含s2中的字符,则返回-1。(标准库函数strpbrk具有同样的功能,但他返回的是指向该位置的指针。)

#include<stdio.h>

int any(char s1[], char s2[])
{
    int i, j, pos;

    pos = -1;

    for (i = 0; pos == -1 && s1[i] != '\0'; i++)
    {
        for (j = 0; pos == -1 && s2[j] != '\0'; j++)
        {
            if (s2[j] == s1[i])
            {
                pos = i;
            }
        }

    }
    return pos;
}

#include<string.h>

int main()
{
    char *leftstr[]=
    {
        "",
        "a",
        "antidisetestablishmentarianism",
        "beautifications",
        "deterministically"
        "electroencephalography",
        "familiarisation",
        "gastrointestinal"
    };

    char *rightstr[]=
    {
        "",
        "a",
        "the",
        "quick",
        "brown"
        "dog",
        "jump",
        "over"
    };

    size_t numlefts = sizeof leftstr / sizeof leftstr[0];
    size_t numrights = sizeof rightstr / sizeof rightstr[0];
    size_t left = 0;
    size_t right = 0;

    int passed = 0;
    int failed = 0;

    int pos = -1;
    char *ptr = NULL;

    for (left = 0; left < numlefts; left++)
    {
        for (right = 0; right < numrights; right++)
        {
            pos = any(leftstr[left], rightstr[right]);
            ptr = strpbrk(leftstr[left], rightstr[right]);

            if (-1 == pos)
            {
                if (ptr != NULL)
                {
                    printf("Test %d/%d failed.\n", left, right);
                    ++failed;
                }
                else
                {
                    printf("Test %d/%d passed.\n", left, right);
                    ++passed;
                }
            }
            else
            {
                if (ptr == NULL)
                {
                    printf("Test %d/%d failed.\n", left, right);
                    ++failed;
                }
                else
                {
                    if (ptr - leftstr[left] == pos)
                    {
                        printf("Test %d/%d passed.\n", left, right);
                        ++passed;
                    }
                    else
                    {
                        printf("Test %d/%d failed.\n", left, right);
                        ++failed;
                    }
                }
            }
        }
    }
    printf("\n\nTotal passes %d, fails %d, total tests %d\n",
            passed,
            failed,
            passed + failed
           );

 return 0;
 }
//源代码,需要再理解
#include<stdio.h>  /* for NULL */

int any(char *s1, char *s2)
{
    char array[256];

    int i;
    if (s1 == NULL)
    {
        if (s2 == NULL)
        {
            return 0;
        }
        else
        {
            return -1;
        }
    }

    for (i = 0; i < 256; i++)
    {
        array[i] = 0;
    }

    while (*s2 != '\0')
    {
        array[*s2] = 1;
        s2++;
    }

    i = 0;
    while(s1[i] != '\0')
    {
        if (array[s1[i]] == 1)
        {
            return i;
        }
        i++;
    }
    return -1;
}

#include<string.h>

int main()
{
    char *leftstr[]=
    {
        "",
        "a",
        "antidisetestablishmentarianism",
        "beautifications",
        "deterministically"
        "electroencephalography",
        "familiarisation",
        "gastrointestinal"
    };

    char *rightstr[]=
    {
        "",
        "a",
        "the",
        "quick",
        "brown"
        "dog",
        "jump",
        "over"
    };

    size_t numlefts = sizeof leftstr / sizeof leftstr[0];
    size_t numrights = sizeof rightstr / sizeof rightstr[0];
    size_t left = 0;
    size_t right = 0;

    int passed = 0;
    int failed = 0;

    int pos = -1;
    char *ptr = NULL;

    for (left = 0; left < numlefts; left++)
    {
        for (right = 0; right < numrights; right++)
        {
            pos = any(leftstr[left], rightstr[right]);
            ptr = strpbrk(leftstr[left], rightstr[right]);

            if (-1 == pos)
            {
                if (ptr != NULL)
                {
                    printf("Test %d/%d failed.\n", left, right);
                    ++failed;
                }
                else
                {
                    printf("Test %d/%d passed.\n", left, right);
                    ++passed;
                }
            }
            else
            {
                if (ptr == NULL)
                {
                    printf("Test %d/%d failed.\n", left, right);
                    ++failed;
                }
                else
                {
                    if (ptr - leftstr[left] == pos)
                    {
                        printf("Test %d/%d passed.\n", left, right);
                        ++passed;
                    }
                    else
                    {
                        printf("Test %d/%d failed.\n", left, right);
                        ++failed;
                    }
                }
            }
        }
    }
    printf("\n\nTotal passes %d, fails %d, total tests %d\n",
            passed,
            failed,
            passed + failed
           );

 return 0;
 }

题目16:2-6, 编写一个函数setbits(x, p, n, y),该函数返回对x执行下列操作后的结果值:将x中从第p位开始的n个(二进制)位设置为y中最右边n位的值,x的其余各位保持不变。

//源代码,不理解意思
#include<stdio.h>

unsigned setbits(unsigned x, int p, int n, unsigned y)
{
    return (x & ((~0 << (p + 1)) | (~(~0 << (p + 1 - n))))) | ((y & ~(~0 << n)) << (p + 1 - n));
}

int main()
{
    unsigned i, j, k;
    int p, n;

    for (i = 0; i < 30000; i += 511)
    {
        for (j = 0; j < 1000; j += 37)
        {
            for (p = 0; p < 16; p++)
            {
                for (n = 1; n <= p + 1; n++)
                {
                    k = setbits(i, p, n, j);
                    printf("setbits(%u, %d, %d, %u) = %u\n", i, p, n, j, k);
                }
            }
        }
    }
    return 0;
}


题目17:2-7, 编写一个函数invert(x, p, n),该函数返回对x执行下列操作后的结果值:将x中从第p位开始的n个(二进制)位求反(即,1变成0,0变成1),x的其余各位保持不变。

//源代码
unsigned invert(unsigned x, int p, int n)
{
    return x ^ (~(~0U << n) << p);
}

/* main driver added, in a hurry while tried, by RJH.
 * Better test driver suggestion are welcomed
 */

 #include<stdio.h>

 int main()
 {
     unsigned x;
     int p, n;

     for (x = 0; x < 700; x += 49)
     {
         for (n = 1; n < 8; n++)
         {
             for (p = 1; p < 8; p++)
             {
                 printf("%u, %d, %d: %u\n", x, n, p, invert(x, n, p));
             }
         }
     }
     return 0;
 }



题目18:2-8, 编写一个函数rightrot(x, n),该函数返回将x循环右移,(即将从最右端移除的位将从最左端移入)n(二进制)位后所得到的值

//源代码
unsigned rightrot(unsigned x, unsigned n)
{
    while (n > 0)
    {
        if ((x & 1) == 1)
        {
            x = (x >> 1) | ~(~0U >> 1);
        }
        else
        {
            x = (x >> 1);
        }
        n--;
    }
    return x;
}

#include<stdio.h>

int main()
{
    unsigned x;
    int n;

    for (x = 0; x < 700; x += 49)
    {
        for (n = 1; n < 8; n++)
        {
            printf("%u, %d: %u\n", x, n,rightrot(x, n));
        }
    }
    return 0;
}


题目19:2-9,在求对二队的补码时,表达式x &= (x - 1)可以删除x中最右边值为1的一个二进制位。请解释这样做的道理。用这一方法重写bitcount函数,以加快其执行速度。

//bitcount is written like this

/* bitcount: count 1 bits in x (统计其整型参数的值为1的二进制位的个数)*/

int bitcount(unsigned x)
{
    int b;

    for (b = 0; x != 0; x >> 1)
    {
        if (x & 01)
        {
            b++;
        }
    }
    return b;
}

/* Answer: If x is odd, then (x - 1) has the same
 * bit representation as x except that the rightmost
 * 1-bit is now a 0. In this case, (x & (x - 1)) == (x - 1).
 * If x is even, then the representation of (x - 1) has the
 * rightmost zeros of x becoming ones and the rightmost one
 * becoming a zero. Anding the two clears the rightmost 1-bit
 * in x and all the rightmost 1-bits from (x - 1).Here's the new
 * version of bitcount:
 */

 //修改后
 int bitcount(unsigned x)
 {
     int b;

     for (b = 0; x != 0; x &= (x - 1))
        b++;
     return b;
 }


题目20:2-10,重新编写将大写字母转换为小写字母的函数lower,并用条件表达式替换其中的if-else结构。

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

#define TEST
#define ORIGINAL 0
#define SOLUTION 1
#define PORTABLE_SOLUTION 0

#if ORIGINAL
/* lower: convert c to lower case; ASCII only
 */

 int lower(int c)
 {
     if (c >= 'A' && c <= 'Z')
        return c + 'a' - 'A';
     else
        return c;
 }


#endif // ORIGINAL

/*
    the natural solution for simply making this a
conditional(ternary) return instead of an
    if ... else ...
*/

#if SOLUTION
/* lower: convert c to lower case: ASCII only */

int lower(int c)
{
    return c >='A' && c <= 'Z' ? c + 'a' - 'A' : c;
}
#endif // SOLUTION


/*
    the more portable solution, requiring string.h for
strchr but keep the idea of a conditional return
*/
#if PORTABLE_SOLUTION
/* loweer: convert c to a lower case */

int lower(int c)
{
    char *Uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char *Lowercase = "abcdefghijklmnopqrstuvwxyz";
    char *p = NULL;
    return NULL == (p = strchr(Uppercase,c)) ? c : *(Lowercase + (p - Uppercase));
}
#endif // PORTABLE_SOLUTION

/*
    ok, this bit is just a test driver... exclude as
required
*/

#ifdef TEST
int main()
{
    char *Tests = "AaBbcCD3EdFGHgIJKLhM2NOjPQRkSTlUVWfXYf0Z1";
    char *p = Tests;
    int Result = 0;

    while ('\0' != *p)
    {
        Result = lower(*p);
        printf("[%c] gives [%c]\n", *p, Result);
        ++p;
    }
/* and the obligatory boundary test */
Result = lower(0);
printf("'\\0' gives %d\n", Result);


return 0;
}
#endif // TEST

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容