• 抬起头,继续前进吧,去把这个不完美的故事,变成你成所期望的样子
  • 登山路上我们会放弃很多东西,但这些被我们丢掉在我们登上山顶之际,都会一一回来
  • 不论开发还是逆向,数学水平的高低直接决定了”你的饭碗里有没有肉”
  • 万丈高楼平地起,勿在浮沙筑高台

《C语言程序设计:现代方法》第十五章练习

C 菜鸟 11个月前 (11-22) 6870次浏览 已收录 0个评论
[隐藏]

        本篇为菜鸟之前在学习《C 语言程序设计:现代方法》中第十五章编写大规模程序时做的练习题,如果有错误或疑问的话,欢迎大家指正~

1、理解概念

15.1 节列出了把程序分割成多个源程序的优点
(1) 请描述其他几个优点
(2) 请描述一些缺点
答:
(1) 更改方便,只需编译
(2) 如果缺失某一份文件会报很多错误

2、规范

下列哪个不应该放置在头文件中?为什么?
(a) 函数原型
(b) 函数定义
(c) 宏定义
(d) 类型定义
答:(b),如果没有头保护且多个文件包含则会出现重复定义的错误

3、头文件格式

如果文件是我们已经编写好的,那么已经看到用#include <文件>代替#include “文件”可能无法工作。
如果文件是系统头文件,那么用#include “文件”代替#include <文件>是否有什么问题?
答:如果在本目录下没找到则会再去系统目录下寻找,如果本目录下有同名文件则会出现问题

4、变量共享

假设文件 foo.c 定义了外部变量 i 如下:
int i;
而且文件 bar.c 以下列方式声明此变量
extern long int i;
(a) 假设 sizeof(int)和 sizeof(long int)是完全一样的。如果文件 bar.c 中的一个函数给 i 赋值为 0,请解释会发生什么?
(b) 假设 sizeof(int)小于 sizeof(long int)。请重复(1)的问题
答:
(a) foo.c 中的 i 会受影响
(b) foo.c 中的 i 不会受影响

5、write_line

程序 fmt 通过在单词间插入额外的空格来调整行。当前编写的函数 write_line 的方法是,与开始处的单词间隔相比,
靠近行末尾单词的间隔略微宽一些。(例如,靠近末尾的单词彼此之间可能有 3 个空格,而靠近开始的单词彼此之间
可能只有 2 个空格)请通过提花逆函数 write_line 来改进此程序,替换后的函数可以在靠近行末尾处的单词之间
放置较大的空隙,而在行开始处的单词之间放置一般空隙
答:修改后的 write_line

void WriteLine(void)
{
    int iExtraSpace = 0;
    int iSpaceToInsert = 0;
    int cntI = 0;
    int cntJ = 0;
    int iAllWordsNum = iCurrentWordsNum;

    iExtraSpace = MAX_LINE_LEN - iCurrentLineLen;

    for (; cntI < iCurrentLineLen; cntI++)
    {
        if (szLine[cntI] != ' ')
        {
            putchar(szLine[cntI]);
        }
        else
        {
            if (iCurrentWordsNum < iAllWordsNum / 2)
            {
                iSpaceToInsert = iExtraSpace / (iCurrentWordsNum - 1);

                for (cntJ = 1; cntJ <= iSpaceToInsert + 1; cntJ++)
                {
                    putchar(' ');
                }
            }
            else
            {
                iSpaceToInsert = 0;
                putchar(' ');
            }

            iExtraSpace -= iSpaceToInsert;
            iCurrentWordsNum--;
        }
    }

    putchar('\n');
}

输出结果:

C is quirky, flawed, and an enormous     success.      While
accidents of history surely helped, it evidently satisfied a
nedd for a system implementation language  efficient  enough
to displace assembly language, yet sufficiantly abstract and
fluent to describe algorithms and interactions in   a   wide
variety of environments. -- Dennis M. Ritchie

6、逆波兰表达式

利用 15.2 节中的设计,编写实现你波兰表达式计算器的程序。使计算器可以实现双目运算+、-、*和/。
假设它们的含义和在 C 语言一样
答:
Macro.h

#pragma once
#ifndef MACRO_H_
#define MACRO_H_

typedef int BOOL;
#define TRUE 1
#define FALSE 0

#define STACK_LEN 255

#endif // !MACRO_H_

Launch.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "stack.h"
#include "showFun.h"
#include "workFun.h"
#include "Macro.h"

int main()
{
    int iCommand = 0;
    BOOL bQuit = FALSE; 

    do
    {
        iCommand = InitUI();

        switch (iCommand)
        {
            case 'a':
            {
                GetInput();
                break;
            }
            case 'b':
            {
                ShowResult(Calculation());
            }
            case 'c':
            {
                ClearStack();
                break;
            }
            case 'q':
            {
                bQuit = TRUE;
                break;
            }
            default:
            {
                printf("Input error.\r\n");
                break;
            }
        }

    } while (!bQuit);

    return 0;
}

showFun.c

#include <stdio.h>
#include "showFun.h"

int InitUI()
{
    int iInputContent = 0;

    printf("a. Input\r\n"
           "b. Result\r\n"
           "c. Renew\r\n"
           "q. Quit\r\n\r\n");
    rewind(stdin);
    iInputContent = getchar();

    return iInputContent;
}

void ShowResult(int iResult)
{
    int iChoise = 0;
    printf("Result: %d\r\n" , iResult);
}

stack.c

#include "Macro.h"
#include "stack.h"

int iTopNumberStack = 0;
int aiNumberStack[STACK_LEN] = { 0 };
int iTopOperatorStack = 0;
int aiOperatorStack[STACK_LEN] = { 0 };

void PushNumber(int iNumber)
{
    aiNumberStack[iTopNumberStack++] = iNumber;
}

void PushOperator(int iOperator)
{
    aiOperatorStack[iTopOperatorStack++] = iOperator;
}

int PopNumber()
{
    return aiNumberStack[--iTopNumberStack];
}

int PopOperator()
{
    return aiOperatorStack[--iTopOperatorStack];
}

void ClearStack()
{
    iTopNumberStack = 0;
    iTopOperatorStack = 0;
}

workFun.c

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "Macro.h"
#include "stack.h"
#include "workFun.h"

extern int iTopNumberStack;
extern int iTopOperatorStack;

int ReadChar()
{
    int iChar = 0;

    do
    {
        iChar = getchar();

        if (!isprint(iChar))
        {
            iChar = -1;
        }
    } while (iChar == ' ');

    return iChar;
} //! ReadChar() END

void GetInput()
{
    int iInputContent = 0;
    int iChar = 0;

    rewind(stdin);
    do
    {
        printf("(. call menu) Input: ");

        while ((iChar = ReadChar()) != -1)
        {
            if (iChar == '.')
            {
                return;
            }

            if (isdigit(iChar))
            {
                PushNumber(atoi((char *)&iChar));
            }
            else
            {
                PushOperator(iChar);
            }
        }

    } while (TRUE);
} //! GetInput() END

int Calculation()
{
    int iResult = 0;
    int iNumberOne = 0;
    int iNumberTwo = 0;
    int iOperator = 0;

    // Has number and operator.
    if (0 != iTopNumberStack && 0 != iTopOperatorStack)
    {
        do
        {
            iNumberOne = PopNumber();
            iNumberTwo = PopNumber();

            switch (PopOperator())
            {
                case '+':
                {
                    iResult = iNumberOne + iNumberTwo;
                    break;
                }
                case '-':
                {
                    iResult = iNumberOne - iNumberTwo;
                    break;
                }
                case '*':
                {
                    iResult = iNumberOne * iNumberTwo;
                    break;
                }
                case '/':
                {
                    iResult = iNumberOne / iNumberTwo;
                    break;
                }
                default:
                {
                    break;
                }
            }

            PushNumber(iResult);
        } while (0 != iTopOperatorStack);
    } //! if "Has number and operator" END

    return PopNumber();
} //! Calculation() END

7、makefile1

假设程序有 3 个源文件构成:main.c、f1.c 和 f2.c,此外还包括两个头文件 f1.h 和符 f2.h。全部 3 个源文件都包含
f1.h,但是只有 f1.c 和 f2.c 包含 f2.h。为此程序编写 UNIX makefile。假设需要可执行文件名为 demo
答:

demo: main.o f1.o f2.o
        gcc -o demo main.o f1.o f2.o
main.o: main.c f1.h
        gcc -c main.c
f1.o: f1.c f1.h f2.h
        gcc -c f1.c
f2.o: f2.c f1.h f2.h
        gcc -c f2.c

8、makefile2

下面的问题引用了练习 7 描述的程序
(a) 当程序第一次构建时,需要对哪些文件进行编译?
(b) 如果在程序构建后对 f1.c 进行了修改,那么需要对哪个(些)文件进行重新编译?
(c) 如果在程序构建后对 f1.h 进行修改,那么需要对哪个(些)文件进行重新编译?
(d) 如果在程序构建后对 f2.c 进行了修改,那么需要对那个(些)文件进行重新编译?
答:
(a) 所有文件
(b) f1.o 和 demo
(c) 所有文件
(d) f2.o 和 demo

9、修改 fmt

(a) 如果修改程序 fmt,使函数 read_word(代替 main 函数)在被截短的单词的末尾存储*字符
(b) 如果按照(a)进行了修改,那么需要对哪个(些)文件进行重新编译?
答:
(a)

void ReadWord(char *szWord, int ilen)
{
    int iChar = 0;
    int iPos = 0;

    while ((iChar = ReadChar()) == ' ');

    while (iChar != ' ' && iChar != EOF)
    {
        if (iPos < ilen)
        {
            szWord[iPos++] = iChar;
        }
        else
        {
            szWord[iPos - 1] = '*';
        }
        
        iChar = ReadChar();
    }

    szWord[iPos] = '\0';
} 

(b) word.o、fmt.o 和 fmt 需要重新编译


学习心得 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明《C 语言程序设计:现代方法》第十五章练习
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址