《C语言入门经典(第4版)》课后练习参考答案

第1章 C语言编程

练习1.1 编写一个程序,用两个printf()语句分别输出自己的名字和地址。

#include <stdio.h>

int main(void) {
    printf("姓名:小狮子\n");
    printf("地址:月亮之上\n");
    return 0;
}

练习1.2 将上一个练习修改成所有的输出只用一个printf()语句。

#include <stdio.h>

int main(void) {
    printf("姓名:小狮子\n地址:月亮之上\n");
    return 0;
}

练习1.3 编写一个程序,输出下列文本,格式如下所示:"It's freezing in here," he said coldly.

#include <stdio.h>

int main(void) {
    printf("\"It's freezing in here,\" he said coldly.\n");
    return 0;
}

第2章 编程初步

习题2.1 编写一个程序,提示用户用英寸输入一个距离,然后将该距离值输出为码、英尺和英寸的形式。

#include <stdio.h>

/*
 * 1码=3英尺=36英寸
 */
int main()
{
    float len_inch = 0.0f;  // 英寸
    float len_foot = 0.0f;  // 英尺
    float len_yard = 0.0f;  // 码
    
    // 提示用户用英寸输入一个距离
    printf("请用英寸输入一个距离:");
    scanf("%f", &len_inch);
    
    // 计算英尺
    len_foot = len_inch / 12;
    
    // 计算码
    len_yard = len_foot / 3;
    
    // 输出计算后的结果
    printf("%.2f英寸 = %.2f英尺 = %.2f码\n", len_inch, len_foot, len_yard);
    
    return 0;
}

习题2.2 编写一个程序,提示用户用英尺和英寸输入一个房间的长和宽,然后计算并输出面积,单位是平方码,精度为小数点后两位数。

#include <stdio.h>

int main()
{
    float length_in_foot = 0.0f;    // 房间的宽度 单位英尺
    float width_in_inch = 0.0f; // 房间的宽度 单位英寸
    float area_in_yard = 0.0f;  // 房间的面积 单位平方码
    
    // 提示用户输入房间的长度
    printf("请输入房间的长度(单位:foot):");
    scanf("%f", &length_in_foot);
    
    // 提示用户输入房间的宽度
    printf("请输入房间的宽度(单位:inch):");
    scanf("%f", &width_in_inch);
    
    // 计算房间的面积 1码=3英尺=36英寸
    area_in_yard = (length_in_foot / 3) * (width_in_inch / 36);
    
    // 输出房间的面积
    printf("房间的面积是:%.2f平方码。\n", area_in_yard);
    
    return 0;
}

习题2.3 一个产品有两个版本:其一是标准版,价格是$3.5,其二是豪华版,价格是$5.5。编写一个程序,使用学到的知识提示用户输入产品的版本和数量,然后根据输入的产品数量,计算并输出价格。

#include <stdio.h>

int main()
{
    float price_of_normal = 3.5;    // 普通版单价
    float price_of_deluxe = 5.5f;   // 豪华版单价
    int number_of_normal = 0;    // 普通版的数量
    int number_of_deluxe = 0;   // 豪华版的数量
    float total_price = 0.0f;   // 总价
    
    // 提示用户输入产品的数量
    printf("请输入普通版的数量:");
    scanf("%d", &number_of_normal);
    printf("请输入豪华版的数量:");
    scanf("%d", &number_of_deluxe);
    
    // 计算总价
    total_price = number_of_normal * price_of_normal + number_of_deluxe + price_of_deluxe;
    
    // 输出总价
    printf("总价为:$%.2f\n", total_price);
    
    return 0;
}

习题2.4 编写一个程序,提示用户从键盘输入一个星期的薪水(以美元为单位)和工作时数,它们均为浮点数,然后计算并输出每个小时的平均时薪,输出格式如下所示:

Your average hourly pay rate is 7 dollars and 54 cents.

#include <stdio.h>

int main()
{
    float salary = 0.0f;    // 一个星期的薪水(以美元为单位)
    float hours = 0.0f; // 工作时数
    float salary_per_hour = 0.0f;   // 每个小时的平均时薪
    
    // 提示用户输入一个星期的薪水
    printf("请输入一个星期的薪水(以美元为单位):");
    scanf("%f", &salary);
    
    // 提示用户输入工作时数
    printf("请输入工作时数:");
    scanf("%f", &hours);
    
    // 计算每个小时的平均时薪
    salary_per_hour = salary / hours;
    
    // 输出结果
    printf("Your average hourly pay rate is %d dollars and %d cents.\n", (int)salary_per_hour, (int)(salary_per_hour * 100) % 100);
    
    return 0;
}

第3章 条件判断

习题3.1 编写一个程序,首先给用户以下两种选择:

(1)将温度从摄氏度转换为华氏度。

(2)将温度从华氏度转换为摄氏度。

接着,程序提示用户输入温度值,并输出转换后的数值。从摄氏度转换为华氏度,可以乘以 1.8 再加上 32。从华氏度转换为摄氏度,可以先减去 32 后,再乘以 5,除以 9。

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

int main()
{
    float temperature = 0.0f;   // 用户输入的温度值
    char ch = '\0';
    float result = 0.0f;    // 转换后的温度值

    // 提示用户都有哪种转换方式
    printf("程序提供如下两种转换方式:\n");
    printf("    A. 将温度从摄氏度转换为华氏度\n    B. 将温度从华氏度转换为摄氏度\n");

    // 提示用户输入选择的转换方式
    printf("请选择转换方式(A or B):");
    scanf("%c", &ch);

    if (tolower(ch) == 'a')
    {
        printf("请输入温度值:");
        scanf("%f",  &temperature);
        result = temperature * 1.8 + 32;
        printf("%.2f摄氏度 = %.2f华氏度\n", temperature, result);
    }
    else if (tolower(ch) == 'b')
    {
        printf("请输入温度值:");
        scanf("%f", &temperature);
        result = (temperature - 32) * 5 / 9;
        printf("%.2f华氏度 = %.2f摄氏度\n", temperature, result);
    } 
    else
    {
        printf("选择错误\n");
    }

    return 0;
}

习题3.2 编写一个程序,提示用户输入3个整数值,分别代表月、日、年。例如用户输入了12、31、2003,程序就以31st December 2003 的格式输出该日期。

必须在日期值的后面加上th、nd、st 和 rd。例如1st、2nd、3rd、4th、11th、12th、13th、14th、21st、22nd、23rd、24th。

#include <stdio.h>

int main()
{
    int year = 0;
    int month = 0;
    int day = 0;
    // 定义一个代表12个月份的枚举类型,枚举器值从1开始
    enum Month { January = 1, February, March, April, May, June, July, August, September, October, November, December };    

    // 提示用户输入月、日、年
    printf("请输入月、日、年:");
    scanf("%d%d%d", &month, &day, &year);

    // 输出日
    if (day < 1 || day > 31)
    {
        printf("输入日期有误 ");
    } 
    else if (day % 10 == 1 && day != 11)
    {
        printf("%dst ", day);
    }
    else if (day % 10 == 2 && day != 12)
    {
        printf("%dnd ", day);
    }
    else if (day % 10 == 3 && day != 13)
    {
        printf("%drd ", day);
    }
    else 
    {
        printf("%dth ", day);
    }

    // 输出月
    switch (month)
    {
    case January:
        printf("January ");
        break;
    case February:
        printf("February ");
        break;
    case March:
        printf("March ");
        break;
    case April:
        printf("April ");
        break;
    case May:
        printf("May ");
        break;
    case June:
        printf("June ");
        break;
    case July:
        printf("July ");
        break;
    case August:
        printf("August ");
        break;
    case September:
        printf("September ");
        break;
    case October:
        printf("October ");
        break;
    case November:
        printf("November ");
        break;
    case December:
        printf("December ");
        break;
    default:
        printf("输入月份有误 ");
        break;
    }

    // 输出年
    printf("%d\n", year);

    return 0;
}

习题3.3 编写一个程序,根据从键盘输入的一个数值,计算总价(单价是$5),数值超过30的折扣是10%,数值超过50的折扣是15%。

#include <stdio.h>

int main()
{
    float unit_price = 5.0f;    // 商品单价
    float discount = 0.0f;  // 商品折扣
    int number = 0; // 商品数量

    // 提示用户输入商品数量
    printf("请输入商品数量:");
    scanf("%d", &number);

    // 计算折扣
    if (number <= 30)
    {
        discount = 0.0f;
    }
    else if (number <= 50)
    {
        discount = 0.1f;
    }
    else
    {
        discount = 0.15f;
    }

    // 输出总价
    printf("商品的总价为:%.2f\n", number * unit_price * (1 - discount));

    return 0;
}

习题3.4 修改本章最后的计算器例子,让用户选择输入y或Y,以执行另一个计算,输入n或N就结束程序。(注意:这需要实用goto语句,下一章将介绍一个更好的方法。)

#include <stdio.h>

int main()
{
    double number1 = 0.0;
    double number2 = 0.0;
    char operation = 0;
    char choice = 0;

    begin:
    printf("Enter the caculation\n");
    scanf("%lf %c %lf", &number1, &operation, &number2);

    switch (operation)
    {
    case '+':
        printf("= %lf\n", number1 + number2);
        break;
    case '-':
        printf("= %lf\n", number1 - number2);
        break;
    case '*':
        printf("= %lf\n", number1 * number2);
        break;
    case '/':
        if (number2 == 0)
            printf("\n\n\aDivision by zero error!\n");
        else
            printf("= %lf\n", number1 / number2);
        break;
    case '%':
        if ((long)number1 == 0)
            printf("\n\n\aDivision by zero error!\n");
        else
            printf("= %ld\n", (long)number1 % (long)number2);
        break;
    default:
        printf("\n\n\aIllegal operation!\n");
        break;
    }

    printf("Do you want to continue? (y or n): ");
    scanf(" %c", &choice);  // 注意:%c 前面的空格不能去掉

    if (choice == 'y' || choice == 'Y')
        goto begin;

    return 0;
}

第4章 循环

习题4.1 编写一个程序,生成一个乘法表,其大小由用户输入来决定。例如,如果表的大小是4,该表就有4行4列。行和列标记为1~4.表中的每一个单元格都包含行列之积,因此第三行第4列的单元格包含12。

#include <stdio.h>

int main()
{
    int num_row = 0;
    int num_col = 0;
    
    printf("请输入行数和列数:");
    scanf("%d%d", &num_row, &num_col);
    
    printf("    ");
    for (int i = 1; i <= num_col; i++)
    {
        printf("%3d ", i);
    }
    printf("\n");
    
    for (int i = 1; i <= num_row; i++)
    {
        printf("%-4d", i);
        for (int j = 1; j <= num_col; j++)
        {
            printf("%3d ", i * j);
        }
        printf("\n");
    }
    return 0;
}

习题4.2 编写一个程序,为0~127之间的字符码输出可打印的字符。输出每个字符码和它的符号,这两个字符占一行。列要对齐(提示:可以使用在ctype.h中声明的isgraph()函数,确定哪个字符是可以打印的)。

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

int main()
{
    for (int i = 0; i <= 127; i++)
    {
        if (isgraph(i))
        {
            printf("%d  %c\n", i, i);
        }
    }
    return 0;
}

习题4.3 扩展上一题,给每个空白字符输出对应的名称,例如newline,space,tab等。

// 本题略

习题4.4 使用嵌套循环输出一个用星号绘制的盒子,与程序4.2类似,但是它的宽和高由用户输入。

#include <stdio.h>

int main()
{
    int height = 0;
    int width = 0;
    
    printf("请输入盒子的宽和高:");
    scanf("%d%d", &width, &height);
    
    for (int i = 1; i <= height; i++)
    {
        for (int j = 1; j <= width; j++)
        {
            if (i == 1 || i == height)
            {
                printf("*");
            }
            else
            {
                if (j == 1 || j == width)
                {
                    printf("*");
                }
                else
                {
                    printf(" ");
                }
            }
        }
        printf("\n");
    }
    return 0;
}

习题4.5 修改程序4.7的猜谜游戏,在玩家猜错数字后,可以用一个选项让玩家继续玩下去,且想玩多久就玩多久。

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

int main()
{
    int chosen = 0;
    int guess = 0;
    int limit = 20;
    char another_game = 'Y';
    
    srand(time(NULL));
    chosen = 1 + rand() % limit;
    
    printf("\nThis is a guessing game."
           "\nI have chosen a number between 1 and 20 which you must guess.\n");
    
    do
    {
        printf("\nEnter a guess: ");
        scanf("%d", &guess);
        
        if (guess == chosen)
        {
            printf("\nYou guessed it!\n");
            return 0;
        }
        
        if (guess < 1 || guess > 20)
        {
            printf("\nI said between 1 and 20.\n");
        }
        else
        {
            printf("\nSorry. %d is wrong.\n", guess);
        }
        
        printf("\nDo you want to play again(y/n)? ");
        scanf(" %c", &another_game);
    }while(toupper(another_game) == 'Y');
    return 0;
}

第5章 数组

习题5.1 编写一个程序,从键盘上读入5个double类型的值,将它们存储到一个数组中。计算每个值的倒数(值x的倒数是 1.0/x),将结果存储到另一个数组中。输出这些倒数,并计算和输出倒数的总和。

#include <stdio.h>

int main()
{
    double original[5] = { 0.0 };
    double result[5] = { 0.0 };
    double sum = 0.0;

    for (int i = 0; i < 5; i++)
    {
        printf("%d -> ", i + 1);
        scanf("%lf", &original[i]);
    }

    for (int i = 0; i < 5; i++)
    {
        result[i] = 1.0 / original[i];
    }

    for (int i = 0; i < 5; i++)
    {
        printf("result[%d] = %lf\n", i, result[i]);
        sum += result[i];
    }

    printf("sum = %lf\n", sum);

    return 0;
}

习题5.2 定义一个数组 data,它包含 100 个 double 类型的元素。编写一个循环,将以下的数值序列存储到数组的对应元素中:

1/(2*3*4) 1/(4*5*6) 1/(6*7*8) ... up to 1/(200*201*202)

编写另一个循环,计算:

data[0] - data[1] + data[2] - data[3] + ... - data[99]

将这个结果乘以 4.0,加 3.0,输出最后的结果。

#include <stdio.h>

int main()
{
    double data[100] = { 0.0 };
    double sum = 0.0;
    double result = 0.0;
    
    for (int i = 1; i <= 100; i++)
    {
        data[i - 1] = 1.0 / ((2 * i) * (2 * i + 1)*(2 * i + 2));
    }
    
    for (int i = 0; i < 100; i++)
    {
        sum += (i % 2 ? -1 : 1) * data[i];
    }
    
    result = sum * 4.0 + 3.0;
    
    printf("计算结果为:%lf\n", result);
    return 0;
}

习题5.3 编写一个程序,从键盘上读入 5 个值,将它们存储到一个 float 类型的数组 amounts 中。创建两个包含 5 个 long 元素的数组 dollars 和 cents。将 amounts 数组元素的整数部分存储到 dollars 的对应元素中,amounts 数组元素的小数部分存储到 cents 中,只保存两位数字(例如:amounts[1] 的值是 2.75,则把 2 存储到 dollars[1] 中,把 75 存储 cents[1]中)。以货币格式输出这两个 long 类型数组的值(如$2.75)。

#include <stdio.h>

int main()
{
    float amounts[5] = {0.0f};
    long dollars[5] = {0L};
    long cents[5] = {0L};
    
    for (int i = 0; i < 5; i++)
    {
        printf("%d -> ", i + 1);
        scanf("%f", &amounts[i]);
    }
    
    for (int i = 0; i < 5; i++)
    {
        dollars[i] = (long) amounts[i];
        cents[i] = (long)(amounts[i] * 100) % 100;
    }
    
    for (int i = 0; i < 5; i++)
    {
        printf("$%ld.%ld\n", dollars[i], cents[i]);
    }
    return 0;
}

习题5.4 定义一个 double 类型的二维数组 data[11][5]。用 2.0~3.0 的值初始化第一列元素(每步增加 0.1)。如果行中的第一个元素值是 x,改行的其它元素值分别是 1/x,x²,x³ 和 x⁴。输出数组中的值,每一行放在一行上,每一列要有标题。

#include <stdio.h>
#include <math.h>

int main()
{
    double data[11][5] = {0.0};
    
    for (int i = 0; i < 11; i++)
    {
        data[i][0] = (1 + 0.1 * i);
    }
    
    for (int i = 0; i < 11; i++)
    {
        data[i][1] = 1 / data[i][0];
        for (int j = 2; j < 5; j++)
        {
            data[i][j] = pow(data[i][0], i);
        }
    }
    
    printf("        ");
    for (int i = 0; i < 5; i++)
    {
        printf("   %02d   ", i + 1);
    }
    printf("\n");
    
    for (int i = 0; i < 11; i++)
    {
        printf("   %02d   ", i + 1);
        for (int j = 0; j < 5; j++)
        {
            printf(" %6.2lf ", data[i][j]);
        }
        printf("\n");
    }
    
    return 0;
}

习题5.5 编写一个程序,计算任意多个班级的学生的平均分。该程序应读取所有班级里学生的所有成绩,再计算平均值。给每个班级输出每个学生的平均分,以及班级的平均分。

#include <stdio.h>
#define CLASS_NUM 2
#define STUDENT_NUM 2
#define COURSE_NUM 2

int main()
{
    int score[CLASS_NUM][STUDENT_NUM][COURSE_NUM] = {0};
    int average_class = 0;
    int average_student = 0;
    
    for (int i = 0; i < CLASS_NUM; i++)
    {
        for (int j = 0; j < STUDENT_NUM; j++)
        {
            for (int k = 0; k < COURSE_NUM; k++)
            {
                printf("Class %02d  Student %02d  Course %02d  -> ", i, j, k);
                scanf("%d", &score[i][j][k]);
            }
        }
    }
    
    for (int i = 0; i < CLASS_NUM; i++)
    {
        average_class = 0;
        for (int j = 0; j < STUDENT_NUM; j++)
        {
            average_student = 0;
            for (int k = 0; k < COURSE_NUM; k++)
            {
                average_class += score[i][j][k];
                average_student += score[i][j][k];
            }
            printf("Class %02d Student %02d 的平均分是 %.2f\n", i, j, average_student * 1.0 / COURSE_NUM);
        }
        printf("Class %02d 的平均分是 %.2f\n", i, average_class * 1.0 / STUDENT_NUM / COURSE_NUM);
    }
    return 0;
}

第6章 字符串和文本的应用

习题6.1 编写一个程序,从键盘上读入一个小于1000的正整数,然后创建并输出一个字符串,说明该整数的值。例如,输入941,程序产生的字符串是“Nine hundred and forty one”。

#include <stdio.h>

void one2nineteen(int n)
{
    switch (n)
    {
        case 1:
            printf("one");
            break;
        case 2:
            printf("two");
            break;
        case 3:
            printf("three");
            break;
        case 4:
            printf("four");
            break;
        case 5:
            printf("five");
            break;
        case 6:
            printf("six");
            break;
        case 7:
            printf("seven");
            break;
        case 8:
            printf("eight");
            break;
        case 9:
            printf("nine");
            break;
        case 10:
            printf("ten");
            break;
        case 11:
            printf("eleven");
            break;
        case 12:
            printf("twelve");
            break;
        case 13:
            printf("thirteen");
            break;
        case 14:
            printf("fourteen");
            break;
        case 15:
            printf("fifteen");
            break;
        case 16:
            printf("sixteen");
            break;
        case 17:
            printf("seventeen");
            break;
        case 18:
            printf("eighteen");
            break;
        case 19:
            printf("nineteen");
            break;
            
        default:
            printf("one2nineteen操作失败");
            break;
    }
}

void fun(int n)
{
    switch (n) {
        case 20:
            printf("twenty");
            break;
        case 30:
            printf("thirty");
            break;
        case 40:
            printf("fourty");
            break;
        case 50:
            printf("fifty");
            break;
        case 60:
            printf("sixty");
            break;
        case 70:
            printf("seventy");
            break;
        case 80:
            printf("eighty");
            break;
        case 90:
            printf("ninety");
            break;
        default:
            printf("fun执行出错");
            break;
    }
}

void fun2(int n)
{
    if (n < 20)
    {
        one2nineteen(n);
    }
    else if (n < 100)
    {
        if (n % 10 == 0)
        {
            fun(n);
        }
        else
        {
            fun(n - n % 10);
            printf("-");
            one2nineteen(n % 10);
        }
    }
}

void int2str(int n)
{
    if (n < 100)
    {
        fun2(n);
    }
    else if (n < 1000)
    {
        if (n % 100 == 0)
        {
            one2nineteen(n / 100);
            printf(" hundred");
        }
        else
        {
            one2nineteen(n / 100);
            printf(" hundred and ");
            fun2(n % 100);
        }
    }
}

int main()
{
    for (int i = 1; i < 1000; i++)
    {
        printf("%3d -> ", i);
        int2str(i);
        printf("\n");
    }
    return 0;
}

习题6.2 编写一个程序,输入一系列单词,单词之间以逗号分割,然后提取这些单词,并将它们分行输出,删除头尾的空格。例如,如果输入是

John , Jack , Jill

输出将是:

John

Jack

Jill

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

int main()
{
    char sequence[100] = { 0 };
    bool first = true;
    
    printf("请输入一系列单词,单词之间以逗号分隔:\n");
    if (fgets(sequence, sizeof(sequence), stdin) == NULL)
    {
        printf("输入过程出错\n");
        return 1;
    }
    else
    {
        for (int i = 0; i < 100 && sequence[i] != '\0'; i++)
        {
            if (isalpha(sequence[i])) {
                first = true;
                printf("%c", sequence[i]);
            }
            else
            {
                if (first)
                {
                    first = false;
                    printf("\n");
                }
            }
        }
        printf("\n");
    }
    return 0;
}

习题6.3 编写一个程序,从一组至少有5个字符串的数组里,输出任意挑选的一个字符串。

#include <stdio.h>

int main()
{
    char arr[][50] = {
        "Hello",
        "Hello World",
        "Hello World, Hello World!"
    };
    
    printf("%s\n", arr[2]);
    return 0;
}

习题6.4 回文是正读反读均相同的句子,忽略空白和标点符号。例如,“Madam, I'm Adam”和“Are we no drawn onward, we few? Drawn onward to new era?”都是回文。编写一个程序,确定从键盘输入的字符串是否是回文。

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

int main()
{
    char sequence[100] = { 0 };
    unsigned long head = 0;
    unsigned long last = 0;
    bool flag = true;
    
    printf("请输入一个字符串:\n");
    if (gets(sequence) == NULL)
    {
        printf("输入过程出错\n");
        return 1;
    }
    else
    {
        last = strlen(sequence);
        
        for (; head < last; )
        {
            for (;!isalpha(sequence[head]);)
            {
                head++;
            }
            
            for (; !isalpha(sequence[last]);)
            {
                last--;
            }
            
            if (toupper(sequence[head]) == toupper(sequence[last]))
            {
                head++;
                last--;
            }
            else
            {
                flag = false;
                break;
            }
        }
        
        if (flag)
        {
            printf("是回文\n");
        }
        else
        {
            printf("不是回文\n");
        }
    }
    return 0;
}

第7章 指针

习题7.1 编写一个程序,计算从键盘输入的任意个浮点数的平均值。将所有的数存储到动态分配的内存中,之后计算并显示平均值。用户不需要事先指定要输入多少个数。

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

int main()
{
    float number = 0.0f;
    float *pNumber = NULL;
    int count = 0;
    float sum = 0.0f;

    pNumber = (float *)malloc(sizeof(float));
    if (pNumber == NULL)
    {
        printf("内存分配失败\n");
        return 1;
    }

    do
    {
        scanf("%f", &number);
        count++;
        pNumber = realloc(pNumber, count * sizeof(float));

        *(pNumber + count - 1) = number;
    } while(number != 0.0f);

    for (int i = 0; i < count - 1; i++)
    {
        sum += *(pNumber + i);
    }

    printf("平均值是 %f\n", sum / (count - 1));

    free(pNumber);
    return 0;
}

习题7.2 编写一个程序,从键盘读入任意个谚语,并将它们存储到执行期间分配的内存中。然后,将它们以字长顺序由短到长地输出。

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

int main()
{
    char **pStr = NULL;
    char *pBuffer = NULL;
    int count = 0;

    pStr = malloc(sizeof(char *));

    do
    {
        pBuffer = malloc(100 * sizeof(char));
        gets(pBuffer);
        count++;
        pStr = realloc(pStr, count * sizeof(char *));
        *(pStr + count - 1) = pBuffer;
    }while(strlen(pBuffer) != 0);

    for (int i = 0; i < count - 2; i++)
    {
        for (int j = 0; j < count - 2 - i; j++)
        {
            if (strlen(*(pStr + j)) > strlen(*(pStr + j + 1)))
            {
                pBuffer = *(pStr + j);
                *(pStr + j) = *(pStr + j + 1);
                *(pStr + j + 1) = pBuffer;
            }
        }
    }

    for (int i = 0; i < count - 1; i++)
    {
        printf("%s\n", *(pStr + i));
    }
    return 0;
}

习题7.3 编写一个程序,从键盘读入一个字符串,显示删除了所有空格和标点符号的字符串。所有的操作都使用指针完成。

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

int main()
{
    char *pStr = NULL;

    pStr = malloc(100*sizeof(char));

    gets(pStr);

    while(*pStr)
    {
        if (isalpha(*pStr))
        {
            putchar(*pStr);
        }
        pStr++;
    }

    putchar('\n');

    return 0;
}

习题7.4 编写一个程序,读入任意天数的浮点温度记录值,每天有6个记录。温度记录存储在动态分配内存的数组中,数组的大小刚好等于输入的温度数。计算出每天的平均温度,然后输出每天的记录,在单独一行上输出平均值,该平均值精确到小数点后一位。

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

int main()
{
    float **pTemp = NULL;
    float sum = 0.0f;
    int count = 0;
    
    pTemp = malloc(sizeof(float));
    
    do
    {
        count++;
        pTemp = realloc(pTemp, count * sizeof(float *));
        *(pTemp + count - 1) = malloc(6 * sizeof(float));
        
        printf("Day %d :\n", count);
        for (int i = 0; i < 6; i++)
        {
            printf("%d -> ", i + 1);
            scanf("%f", (*(pTemp + count - 1) + i));
        }
    }while(**(pTemp + count - 1) != 0.0f);
    
    for (int i = 0; i < count - 1; i++)
    {
        printf("Day %d :\n", i + 1);
        sum = 0;
        for (int j = 0; j < 6; j++)
        {
            sum += *(*(pTemp+i) + j);
            printf("%d -> %f\n", j + 1, *(*(pTemp+i) + j));
        }
        printf("average = %.1f\n", sum / 6);
    }
    return 0;
}

第8章 程序的结构

习题8.1 定义一个函数,给函数传送任意多个浮点数,计算出这些数的平均值。从键盘输入任意个值,并输出平均值,以说明这个函数的执行过程。

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

float average(float *, int);

int main()
{
    float *pNum = NULL;
    int count = 0;
    pNum = malloc(count * sizeof(float));

    do
    {
        count++;
        pNum = realloc(pNum, count * sizeof(float));
        scanf("%f", pNum + count - 1);
    } while(*(pNum + count - 1) != 0.0f);

    printf("average = %f\n", average(pNum, count - 1));

    return 0;
}

float average(float *pNum, int count)
{
    float sum = 0.0f;
    for (int i = 0; i < count; i++)
    {
        sum += *(pNum + i);
    }
    return sum / count;
}

习题8.2 定义一个函数,返回其整数变元的字符串表示。例如,如果这个变元是25,函数就返回"25"。如果变元是-98,函数就返回"-98"。用适当的main()版本说明函数的执行过程。

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

char *intToString(int);

int main()
{
    printf("%s\n", intToString(-32768));
    return 0;
}

char *intToString(int number)
{
    char *pStr = malloc(7 * sizeof(char));
    int var = 10000;
    int weishu = 5;
    int count = 0;
    if (number < 0)
    {
        *(pStr + 0) = '-';
        count = 1;
        number = -number;
    }

    while (number / var == 0) {
        weishu--;
        var /= 10;
    }

    for (; count < 7; count++)
    {
        *(pStr + count) = '0' + number / (int)(pow(10, weishu - 1));
        number %= (int)(pow(10, weishu - 1));
        weishu--;
        if (weishu <= 0) {
            break;
        }
    }
    *(pStr + count + 1) = '\0';

    return pStr;
}

习题8.3 扩展为上一题定义的函数,使函数接受第二个变元,以指定结果的字段宽度,使返回的字符串表示右对齐。例如,如果第一个变元的值是-98,字段宽度变元是5,返回的字符串就应该是" -98"。用适当的main()版本说明函数的执行过程。

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

char *intToString(int, int);

int main()
{
    printf("%s\n", intToString(-98, 5));
    return 0;
}

char *intToString(int number, int width)
{
    char *pStr = malloc(7 * sizeof(char));
    int var = 10000;
    int weishu = 5;
    int count = 0;
    int len = 0;
    if (number < 0)
    {
        *(pStr + 0) = '-';
        count = 1;
        number = -number;
    }

    while (number / var == 0) {
        weishu--;
        var /= 10;
    }

    for (; count < 7; count++)
    {
        *(pStr + count) = '0' + number / (int)(pow(10, weishu - 1));
        number %= (int)(pow(10, weishu - 1));
        weishu--;
        if (weishu <= 0) {
            break;
        }
    }
    *(pStr + count + 1) = '\0';

    len = (int)strlen(pStr);
    if (len < width)
    {
        pStr = realloc(pStr, (width + 1) * sizeof(char));
        *(pStr + width) = '\0';
        int j = width - 1;
        for (int i = len; i > 0; i--, j--)
        {
            *(pStr + j) = *(pStr + i - 1);
        }
        for (;j >= 0; j--)
        {
            *(pStr + j) = ' ';
        }
    }

    return pStr;
}

习题8.4 定义一个函数,其参数是一个字符串,返回该字符串中的单词数(单词以空格或标点符号来分隔。假设字符串不包含单双引号,也就是数没有像isn't这样的单词)。定义第二个函数,它的第一个参数是一个字符串,第二个参数是一个数组,该函数将第一个字符串变元分隔成单词,把这些单词存储在第二个数组变元中,最后返回存储在数组中的单词。定义第三个函数,其参数是一个字符串,返回该字符串中的字母数。使用这些函数实现一个程序,从键盘读入含有文本的字符串,输出文本中的所有单词,输出顺序是按照单词中的字母数,由短到长。

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

int wordCount(const char *);
void stringToArray(char *, char **);
int alphaCount(char *);

int main()
{
    char buffer[100] = "";
    char *pStr = buffer;
    char **pWord = NULL;
    char *pTemp = NULL;
    int words = 0;
    pWord = malloc(20 * sizeof(char *));
    gets(buffer);
    words = wordCount(pStr);
    stringToArray(pStr, pWord);

    for (int i = 0; i < words - 1; i++)
    {
        for (int j = 0; j < words - 1 - i; j++)
        {
            if (strlen(*(pWord + j)) > strlen(*(pWord + j + 1)))
            {
                pTemp = *(pWord + j);
                *(pWord + j) = *(pWord + j + 1);
                *(pWord + j + 1) = pTemp;
            }
        }
    }

    for (int i = 0; i < words; i++)
    {
        printf("%s\n", *(pWord + i));
    }

    return 0;
}

int wordCount(const char *pStr)
{
    int count = 0;
    bool isFirst = true;
    while (*pStr) {
        if (isalpha(*pStr)) {
            if (isFirst) {
                isFirst = false;
                count++;
            }
        }
        else
        {
            isFirst = true;
        }
        pStr++;
    }
    return count;
}

void stringToArray(char *pStr, char **pWord)
{
    char *pBuffer = malloc(20 * sizeof(char));
    int wordCount = 0;
    int i = 0;

    while (*pStr) {
        if (isalpha(*pStr))
        {
            while (isalpha(*pStr)) {
                *(pBuffer + i) = *pStr;
                i++;
                pStr++;
            }
            *(pBuffer + i) = '\0';
            *(pWord + wordCount) = pBuffer;
            wordCount++;
            pBuffer = malloc(20 * sizeof(char));
            i = 0;
        }
        else
        {
            pStr++;
        }
    }
}

int alphaCount(char *pStr)
{
    int count = 0;
    while (*pStr++) {
        count++;
    }
    return count;
}

第9章 函数再探

习题9.1 函数原型:

double power(doulbe x, int n);

会计算并返回xn。因此power(5.0, 4)会计算5.0*5.0*5.0*5.0,它的结果是625.0。将power()函数实现为递归函数,再用适当的main版本演示它的操作。

#include <stdio.h>

double power(double, int);

int main()
{
    printf("power(5.0, 4) = %lf\n", power(5.0, 4));
    return 0;
}

double power(double x, int n)
{
    if (n == 1)
    {
        return x;
    }
    else
    {
        return x * power(x, n - 1);
    }
}

习题9.2 函数原型:

double add(double a, double b); // returns a + b
double subtract(double a, double b);  // returns a - b
double multiply(double a, double b);  // returns a * b
double array_op(double array[], int size, double (\*pfun) (double, double));

array_op()函数的参数是:要运算的数组、数组元素数目以及一个函数指针,该函数指针指向的函数定义了在连续几个元素上进行的操作。在实现array_op()函数时,将subtract()函数传送为第三个参数,subtract()函数会用交替符号组合这些元素。因此,对于有4个元素x1、x2、x3、x4的数组,subtract()函数会计算x1-x2+x3-x4的值。

用适当的main()版本演示这些函数的运作。

#include <stdio.h>

double add(double, double);
double subtract(double, double);
double multiply(double, double);
double array_op(double[], int, double (*) (double, double));

int main()
{
    double array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    printf("array_op() = %lf\n", array_op(array, 5, subtract));
    return 0;
}

double add(double a, double b)
{
    return a + b;
}

double subtract(double a, double b)
{
    return a - b;
}

double multiply(double a, double b)
{
    return a * b;
}

double array_op(double array[], int size, double (*pfun) (double, double))
{
    double sum = 0.0;
    for (int i = 0; i < size / 2; i++)
    {
        sum += subtract(array[i * 2], array[i * 2 + 1]);
    }
    if (size % 2 != 0) {
        sum += array[size - 1];
    }
    return sum;
}

习题9.3 定义一个函数,它的参数是字符串数组指针,返回一个将所有字符串合并起来的字符串指针,每个字符串都用换行符来终止。如果输入数组中的原字符串将换行符作为最后一个字符,函数就不能给字符串添加另一个换行符。编写一个程序,从键盘读入几个字符串,用这个函数输出合并后的字符串。

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

#define ARR_LEN 5
#define BUF_LEN 100

char *custom_concat(char *[]);

int main()
{
    char *pStr[ARR_LEN] = { NULL };
    for (int i = 0; i < ARR_LEN; i++)
    {
        pStr[i] = malloc(BUF_LEN * sizeof(char));
        gets(pStr[i]);
    }

    printf("%s\n", custom_concat(pStr));
    return 0;
}

char *custom_concat(char *pStr[])
{
    char *pResult = NULL;
    char *pTemp = NULL;
    int totalLen = 0;
    for (int i = 0; i < ARR_LEN; i++)
    {
        totalLen += strlen(pStr[i]);
    }
    pResult = malloc((totalLen + 1) * sizeof(char));
    pTemp = pResult;
    for (int i = 0; i < ARR_LEN; i++)
    {
        strncpy(pTemp, pStr[i], strlen(pStr[i]));
        pTemp += strlen(pStr[i]);
    }

    return pResult;
}

习题9.4 一个函数的原型是:

char *to_string(int count, double first, ...);

这个函数返回一个字符串,这个字符串含有第二及其后参数的字符串表示,每个参数都有两位小数,参数间用逗号隔开。第一个参数是从第二个参数算起的参数个数。编写一个main()函数,演示这个函数的运作。

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

char *to_string(int , double, ...);

int main()
{
    printf("%s\n", to_string(4, 1.0, 2.0, 3.0, 4.0));
    return 0;
}

char *to_string(int count, double first, ...)
{
    char *pStr = malloc(100 * sizeof(char));
    char buffer[100] = "";
    va_list parg;

    va_start(parg, first);
    sprintf(buffer, "%.2f", first);
    strcat(pStr, buffer);

    for (int i = 1; i < count; i++) {
        sprintf(buffer, ", %.2f", va_arg(parg, double));
        strcat(pStr, buffer);
    }

    va_end(parg);
    return pStr;
}

第10章 基本输入输出操作

习题10.1 编写一个程序,读入、存储以及输出下列5种类型的字符串,每个字符串占一行,字符串间不能有空格。

  • 类型1:一串小写字母,后跟一个数字(如 number1)
  • 类型2:两个单词,每个单词的第一个字母大写,单词间用-分隔(如Seven-Up)
  • 类型3:小数(如7.35)
  • 类型4:一串大小写字母以及空格(如Oliver Hardy)
  • 类型5:一串除了空格及数字外的任何字符(如floating-point)

以下是这5种输入类型的例子,要分开读入这些字符串:

baby1on5Jhon-Boy3.14159Stan Laurel'Winner!'

#include <stdio.h>

int main()
{
    char str[5][100] = {""};
    for (int i = 0; i < 5; i++)
    {
        printf("%d -> ", i + 1);
        gets(str[i]);
    }

    for (int i = 0;i < 5; i++)
    {
        printf("%s", str[i]);
    }
    printf("\n");
    return 0;
}

习题10.2 编写一个程序,读入以下数值,并输出它们的和:

$3.50, $ 0.75, %9.95, %2. 50

#include <stdio.h>

int main()
{
    float number[4] = { 0.0f };
    float sum = 0.0f;
    char str[100] = "";
    int i = 0;
    for ( ; i < 99; )
    {
        str[i] = getchar();
        if (('0' <= str[i] && str[i] <= '9') || str[i] == '.')
        {
            i++;
        }
        else if (str[i] == '\n')
        {
            break;
        }
    }
    str[i] = '\0';

    sscanf(str, "%4f%4f%4f%4f", &number[0], &number[1], &number[2], &number[3]);

    for (int i = 0;i < 4; i++)
    {
        sum += number[i];
    }

    printf("average = %.2f\n", sum / 4);
    return 0;
}

习题10.3 定义一个函数,其参数是一个double类型的数组,输出该数组和数组中的元素个数。这个函数的原型如下:

void show(double array[], int array_size, int field_width);

输出的值5个一行,每个值有两位小数,字符宽度是12。在程序中使用这个函数输出从1.5到4.5的值,每次增加0.3(如:1.5、1.8、2.1、...、4.5)。

#include <stdio.h>

void show(double[], int, int);

int main()
{
    double array[] = {1.5, 1.8, 2.1, 2.4, 2.7, 3.0, 3.3, 3.6, 3.9, 4.2, 4.5};
    show(array, 11, 12);

    return 0;
}

void show(double array[], int array_size, int field_width)
{
    char buffer[10] = "";
    sprintf(buffer, "%%%d.2f", field_width);
    for (int i = 0; i < array_size; i++)
    {
        if (i % 5 == 0) {
            printf("\n");
        }
        printf(buffer, array[i]);
    }
    printf("\n");
}

习题10.4 定义一个函数,使用getchar()函数从stdin中读入一个字符串,这个字符串用特定的字符终止,这个特定的终止字符作为第二个变元传给这个函数。因此,函数的原型如下:

char *getString(char *buffer, char end_char);

返回值是一个指针,它是这个函数的第一个变元。编写一个程序,使用这个函数从键盘上读取并输出5个以冒号终止的字符串。

#include <stdio.h>

char *getString(char *, char);

int main()
{
    char buffer[5][100];
    for (int i = 0; i < 5; i++)
    {
        getString(buffer[i], ':');
    }

    for (int i = 0; i < 5; i++)
    {
        printf("%s\n", buffer[i]);
    }

    return 0;
}

char *getString(char *buffer, char end_char)
{
    char *pStr = buffer;
    char ch = '\0';
    for (;;)
    {
        ch = getchar();
        if (ch != end_char) {
            *pStr++ = ch;
        }
        else
        {
            *pStr = '\0';
            break;
        }
    }
    return buffer;
}

第11章 结构化数据

习题11.1 定义一个结构类型Length,它用码、英尺和英寸表示长度。定义一个add()函数,它相加两个Length变元,返回Length类型的总和。定义第二个函数show(),显示其Length变元的值。编写一个程序,从键盘输入任意个单位的码、英尺以及英寸的长度,使用Length类型、add()、和show()函数去汇总这些长度,并输出总长。

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

struct Length
{
    int yard;
    int foot;
    int inch;
};

struct Length *add(struct Length *, struct Length *);
void show(struct Length *);

int main()
{
    struct Length *pSum = NULL;
    struct Length **pLength = NULL;
    int count = 0;
    char ch = '\0';

    pSum = malloc(sizeof(struct Length));
    pSum->yard = 0;
    pSum->foot = 0;
    pSum->inch = 0;
    pLength = (struct Length **) malloc(sizeof(struct Length *));
    do
    {
        count++;
        pLength = (struct Length **) realloc(pLength, count * sizeof(struct Length *));
        *(pLength + count - 1) = malloc(sizeof(struct Length));
        printf("请输入Length:\n");
        printf("Length.yard -> ");
        scanf("%d", &(*(pLength + count - 1))->yard);
        printf("Length.foot -> ");
        scanf("%d", &(*(pLength + count - 1))->foot);
        printf("Length.inch -> ");
        scanf("%d", &(*(pLength + count - 1))->inch);
        getchar();
        ch = getchar();
    } while(tolower(ch) == 'y');

    for (int i = 0; i < count; i++)
    {
        pSum = add(pSum, *(pLength + i));
    }

    show(pSum);
    return 0;
}

struct Length *add(struct Length *a, struct Length *b)
{
    struct Length *pLength = (struct Length *)malloc(sizeof(struct Length));

    pLength->yard = a->yard + b->yard;
    pLength->foot = a->foot + b->foot;
    pLength->inch = a->inch + b->inch;

    return pLength;
}

void show(struct Length *length)
{
    printf("yard=%d, foot=%d, inch=%d\n", length->yard, length->foot, length->inch);
}

习题11.2 定义一个结构类型,它含有一个人的姓名及电话号码。在程序中使用这个结构,输入一个或多个姓以及对应的电话号码,将输入的数据存储到一个结构数组中。程序允许输入姓氏,输出对应于该姓氏的所有电话号码,可以选择是否要输出所有的姓名及他们的电话号码。

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

struct Contacts
{
    char *name;
    int phoneCount;
    char **phone;
};

struct Contacts *newContacts();
void printContacts(struct Contacts *);

int main()
{
    struct Contacts **pContacts = NULL;
    char isContinue = '\0';
    int count = 0;
    char buffer[100] = "";

    pContacts = malloc(sizeof(struct Contacts *));
    do
    {
        count++;
        pContacts = realloc(pContacts, count * sizeof(struct Contacts *));
        *(pContacts + count - 1) = newContacts();
        printf("是否继续输入联系人信息(y/n):");
        isContinue = getchar();
        getchar();
    } while (tolower(isContinue) == 'y');

    printf("请输入姓名:");
    gets(buffer);
    for (int i = 0; i < count; i++)
    {
        if (strcmp(buffer, (*(pContacts + i))->name) == 0) {
            printContacts(*(pContacts + i));
        }
    }

    return 0;
}

struct Contacts *newContacts()
{
    struct Contacts *pContacts = NULL;
    char buffer[100] = "";
    int count = 0;
    char isContinue = '\0';
    pContacts = malloc(sizeof(struct Contacts));

    printf("请输入姓名:");
    gets(buffer);
    pContacts->name = malloc((strlen(buffer) + 1) * sizeof(char));
    strcpy(pContacts->name, buffer);

    pContacts->phone = malloc(sizeof(char *));
    do
    {
        count++;
        pContacts->phone = realloc(pContacts->phone, count * sizeof(char *));
        printf("请输入电话号码:");
        gets(buffer);
        *(pContacts->phone + count - 1) = malloc((strlen(buffer) + 1) * sizeof(char));
        strcpy(*(pContacts->phone + count - 1), buffer);
        printf("是否继续输入电话号码(y/n):");
        isContinue = getchar();
        getchar();
    } while(tolower(isContinue) == 'y');
    pContacts->phoneCount = count;
    return pContacts;
}

void printContacts(struct Contacts *pContacts)
{
    printf("==========\n");
    printf("name = %s\n", pContacts->name);
    for (int i = 0; i < pContacts->phoneCount; i++)
    {
        printf("phone = %s\n", *(pContacts->phone + i));
    }
    printf("==========\n");
}

习题11.3 修改上一题的程序,将数据存储到链表中,按照姓名的字母顺序由小到大排序。

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

struct Contacts
{
    char *name;
    int phoneCount;
    char **phone;
    struct Contacts *next;
};

struct Contacts *newContacts();
void printContacts(struct Contacts *);

int main()
{
    struct Contacts *pHead = NULL;
    struct Contacts *pCurrent = NULL;
    struct Contacts *p = NULL;
    struct Contacts *q = NULL;
    char isContinue = '\0';
    int count = 0;

    pHead = malloc(sizeof(struct Contacts));
    do
    {
        count++;
        pCurrent = newContacts();
        if (count == 1) {
            pHead->next = pCurrent;
        }
        else
        {
            p = pHead;
            q = pHead->next;
            while (q) {
                if (strcmp(pCurrent->name, q->name) > 0) {
                    p = q;
                    q = q->next;
                }
                else
                {
                    break;
                }
            }
            pCurrent->next = q;
            p->next = pCurrent;
        }
        printf("是否继续输入联系人信息(y/n):");
        isContinue = getchar();
        getchar();
    } while (tolower(isContinue) == 'y');

    pCurrent = pHead;
    for (int i = 0; i < count; i++)
    {
        printContacts(pCurrent->next);
        pCurrent = pCurrent->next;
    }

    return 0;
}

struct Contacts *newContacts()
{
    struct Contacts *pContacts = NULL;
    char buffer[100] = "";
    int count = 0;
    char isContinue = '\0';
    pContacts = malloc(sizeof(struct Contacts));

    printf("请输入姓名:");
    gets(buffer);
    pContacts->name = malloc((strlen(buffer) + 1) * sizeof(char));
    strcpy(pContacts->name, buffer);

    pContacts->phone = malloc(sizeof(char *));
    do
    {
        count++;
        pContacts->phone = realloc(pContacts->phone, count * sizeof(char *));
        printf("请输入电话号码:");
        gets(buffer);
        *(pContacts->phone + count - 1) = malloc((strlen(buffer) + 1) * sizeof(char));
        strcpy(*(pContacts->phone + count - 1), buffer);
        printf("是否继续输入电话号码(y/n):");
        isContinue = getchar();
        getchar();
    } while(tolower(isContinue) == 'y');
    pContacts->phoneCount = count;
    pContacts->next = NULL;
    return pContacts;
}

void printContacts(struct Contacts *pContacts)
{
    printf("==========\n");
    printf("name = %s\n", pContacts->name);
    for (int i = 0; i < pContacts->phoneCount; i++)
    {
        printf("phone = %s\n", *(pContacts->phone + i));
    }
    printf("==========\n");
}

习题11.4 编写一个程序,从键盘上输入一段文本,然后使用结构计算每个单词的出现次数。

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

struct WordUnit
{
    int count;
    char *word;
    struct WordUnit *next;
};

void statistics(struct WordUnit *, char *);
void printWordUnit(struct WordUnit *);

int main()
{
    char buffer[100] = "";
    char temp[10] = "";
    struct WordUnit *pHead = NULL;
    struct WordUnit *pCurrent = NULL;

    pHead = malloc(sizeof(struct WordUnit));
    pHead->next = NULL;
    gets(buffer);

    for (int i = 0, j = 0; i < strlen(buffer) && j < strlen(buffer);)
    {
        for (int i = 0; i < 10; i++)
        {
            temp[i] = '\0';
        }

        if (isalpha(buffer[i]))
        {
            for (j = i; j < strlen(buffer) && isalpha(buffer[j]); j++)
                ;

            for (int k = i; k < j; k++)
            {
                temp[k - i] = buffer[k];
            }
            statistics(pHead, temp);
            i = j;
        }
        else
        {
            i++;
        }
    }

    printWordUnit(pHead->next);

    return 0;
}

void statistics(struct WordUnit *head, char *word)
{
    bool isNewWord = true;
    struct WordUnit *p = head->next;
    struct WordUnit *q = head;
    while (p) {
        if (strcmp(p->word, word) == 0) {
            p->count++;
            isNewWord = false;
            break;
        }
        q = p;
        p = p->next;
    }
    if (isNewWord) {
        p = malloc(sizeof(struct WordUnit));
        p->count = 1;
        p->word = malloc((strlen(word) + 1) * sizeof(char));
        strcpy(p->word, word);
        q->next = p;
    }
}

void printWordUnit(struct WordUnit *p)
{
    while (p) {
        printf("%10s %2d\n", p->word, p->count);
        p = p->next;
    }
}

习题11.5 编写一个程序,读取任意多个姓名。用一个二叉树按升序输出所有的姓名,排序时先排姓氏,后排名字(例如 Ann Choosy 在 Bill Champ 的后面,在 Arthur Choosy 的前面)。

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

struct Name
{
    char *firstName;
    char *lastName;
    struct Name *leftChild;
    struct Name *rightChild;
};

struct Name *readName();
void printName(struct Name *);
void insertName(struct Name *, struct Name *);

int main()
{
    struct Name *root = NULL;
    char isContinue = '\0';
    int count = 0;
    do
    {
        if (count == 0) {
            root = readName();
        }
        else
        {
            insertName(root, readName());
        }
        count++;
        printf("是否继续输入姓名:");
        isContinue = getchar();
        getchar();
    } while(tolower(isContinue) == 'y');

    printName(root);

    return 0;
}

struct Name *readName()
{
    struct Name *p = malloc(sizeof(struct Name));
    char buffer[20] = "";
    printf("请输入姓氏:");
    gets(buffer);
    p->lastName = malloc((strlen(buffer) + 1) * sizeof(char));
    strcpy(p->lastName, buffer);
    printf("请输入名字:");
    gets(buffer);
    p->firstName = malloc((strlen(buffer) + 1) *sizeof(char));
    strcpy(p->firstName, buffer);
    p->leftChild = NULL;
    p->rightChild = NULL;

    return p;
}

void printName(struct Name *p)
{
    if (p != NULL) {
        printName(p->leftChild);
        printf("%s %s\n", p->lastName, p->firstName);
        printName(p->rightChild);
    }
    return;
}

void insertName(struct Name *root, struct Name *p)
{
    if (root != NULL) {
        if (strcmp(root->lastName, p->lastName) >= 0)
        {
            if (root->leftChild != NULL) {
                insertName(root->leftChild, p);
            }
            else{
                root->leftChild = p;
            }
        }
        else
        {
            if (root->rightChild != NULL) {
                insertName(root->rightChild, p);
            }
            else
            {
                root->rightChild = p;
            }
        }
    }
    return ;
}

第12章 处理文件

习题12.1 编写一个程序,将任意数目的字符串写入文件。字符串由键盘输入,程序不能删除这个文件,因为下一题还要使用这个文件。

#include <stdio.h>
#include <stdbool.h>

int main()
{
    char buffer[100] = "";
    const char fileName[10] = "data.txt";
    FILE *pFile = NULL;

    pFile = fopen(fileName, "a");
    if (!pFile) {
        printf("打开文件失败\n");
        return 1;
    }
    do {
        fgets(buffer, 100, stdin);
        if (buffer[0] == '\n')
        {
            break;
        }
        fputs(buffer, pFile);
    } while (true);

    fclose(pFile);
    return 0;
}

习题12.2 编写一个程序,读取上一题创建的文件。每次都以反向的顺序读取一个字符串,然后按照读取顺序将它们写入一个新文件。例如,程序读取最后一个字符串,将它写入新文件,再读取倒数第二个字符串,将它写入新文件,依次类推。

#include <stdio.h>
#include <stdbool.h>

int count(char *);

int main()
{
    char buffer[100] = "";
    char fileName[10] = "data.txt";
    char fileNameNew[10] = "data2.txt";
    FILE *pFile = NULL;
    FILE *pFileNew = NULL;

    pFile = fopen(fileName, "a");
    if (!pFile) {
        printf("打开文件失败\n");
        return 1;
    }
    do {
        fgets(buffer, 100, stdin);
        if (buffer[0] == '\n')
        {
            break;
        }
        fputs(buffer, pFile);
    } while (true);

    fclose(pFile);

    pFile = fopen(fileName, "r");
    if (!pFile) {
        printf("打开文件失败\n");
        return 1;
    }
    fclose(pFile);

    pFileNew = fopen(fileNameNew, "a");
    for (int i = count(fileName) - 1; i >= 0; i--)
    {
        pFile = fopen(fileName, "r");
        for (int j = 0; j < i; j++)
        {
            fgets(buffer, 100, pFile);
        }

        fgets(buffer, 100, pFile);
        fclose(pFile);
        fputs(buffer, pFileNew);
    }
    fclose(pFileNew);

    return 0;
}

int count(char *pName)
{
    FILE *pFile = NULL;
    pFile = fopen(pName, "r");
    int count = 0;
    char buffer[100] = "";
    while (fgets(buffer, 100, pFile)) {
        count++;
    }
    fclose(pFile);
    return count;
}

习题12.3 编写一个程序,从键盘读入姓名和电话号码,将它们写入一个文件。如果这个文件不存在,就写入一个新文件。如果文件已存在,就将它们写入该文件。这个程序需要提供列出所有数据的选项。

#include <stdio.h>

struct Contacts
{
    char name[20];
    char phone[3][15];
};

char fileName[20] = "contacts.txt";

void add();

int main()
{
    add();
    return 0;
}

void add()
{
    struct Contacts con;
    FILE *pFile = NULL;
    pFile = fopen(fileName, "a");
    printf("\n请输入姓名:");
    fgets(con.name, 20, stdin);
    for (int i = 0; i < 3; i++)
    {
        printf("请输入第 %d 个电话号码:", i + 1);
        fgets(con.phone[i], 15, stdin);
    }

    fprintf(pFile, "%20s%15s%15s%15s", con.name, con.phone[0], con.phone[1], con.phone[2]);
    fclose(pFile);
}

习题12.4 扩展上一题的程序,提取对应指定的姓名的所有电话号码。这个程序允许进一步查询,添加新的姓名和电话号码,删除已有的项。

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

struct Contacts
{
    char name[20];
    char phone[3][15];
};

char fileName[20] = "contacts.txt";

void add();
void printContacts(struct Contacts *);
bool searchByContactsName(char *, struct Contacts *, char *);
void printAll(char *);
void deleteByContactsName(char *fileName, char *contactsName);

int main()
{
    // 此处省略了函数的调用
    return 0;
}

void add()
{
    struct Contacts con;
    FILE *pFile = NULL;
    pFile = fopen(fileName, "a");
    printf("\n请输入姓名:");
    fgets(con.name, 20, stdin);
    for (int i = 0; i < 3; i++)
    {
        printf("请输入第 %d 个电话号码:", i + 1);
        fgets(con.phone[i], 15, stdin);
    }

    fprintf(pFile, "%20s%15s%15s%15s", con.name, con.phone[0], con.phone[1], con.phone[2]);
    fclose(pFile);
}

void printContacts(struct Contacts *p)
{
    printf("姓名:%s\n\t电话1:%s\n\t电话2:%s\n\t电话3:%s\n", p->name, p->phone[0], p->phone[1], p->phone[2]);
}

void deleteByContactsName(char *fileName, char *name)
{
    FILE *pFileOld = NULL;
    FILE *pFileNew = NULL;
    struct Contacts c;
    char tempFileName[20] = "temp.txt";
    if (!searchByContactsName(fileName, &c, name))
        return;

    pFileOld = fopen(fileName, "r");
    pFileNew = fopen(tempFileName, "a");

    while(fscanf(pFileOld, "%20s%15s%15s%15s", c.name, c.phone[0], c.phone[1], c.phone[2]) != EOF)
    {
        if (strcmp(name, c.name)) {
            fprintf(pFileNew, "%20s%15s%15s%15s", c.name, c.phone[0], c.phone[1], c.phone[2]);
        }
    }

    fclose(pFileOld);
    fclose(pFileNew);

    remove(fileName);
    rename(tempFileName, fileName);
}

bool searchByContactsName(char *fileName, struct Contacts *c, char *name)
{
    FILE *pFile = fopen(fileName, "r");
    while(fscanf(pFile, "%20s%15s%15s%15s", c->name, c->phone[0], c->phone[1], c->phone[2]) != EOF)
    {
        if (strcmp(c->name, name) == 0) {
            return true;
        }
    }
    return false;

}

void printAll(char *fileName)
{
    struct Contacts c;
    FILE *pFile = NULL;
    pFile = fopen(fileName, "r");
    while(fscanf(pFile, "%20s%15s%15s%15s", c.name, c.phone[0], c.phone[1], c.phone[2]) != EOF)
    {
        printContacts(&c);
    }
    fclose(pFile);
}

第13章 支持功能

习题13.1 定义一个COMPARE(x, y)宏。如果x<y,就返回-1,如果x==y,就返回0,如果x>y就返回1.编写一个例子,说明这个宏可以正常工。这个宏会优于完成相同任务的函数码?

#include <stdio.h>

#define COMPARE(x, y) (x) > (y) ? 1 : ((x) == (y) ? 0 : -1)

int main()
{
    printf("%d\n", COMPARE(5, 3));
    return 0;
}

习题13.2 定义一个函数,返回含有当前时间的字符串,如果变元是0,它的格式就是12小时制(a.m./p.m.),如果变元是1,它的格式就是24小时制。编写一个程序,说明这个函数可以正常工作。

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

char *getTimeString(int format);

int main()
{
    printf("%s\n%s\n", getTimeString(0), getTimeString(1));
    return 0;
}

char *getTimeString(int format)
{
    char *pStr = NULL;
    char buffer[20] = "";
    struct tm *t = NULL;
    time_t val = time(NULL);
    t = localtime(&val);
    if (format == 0) {
        sprintf(buffer, "%02d:%02d:%02d", t->tm_hour, t->tm_min, t->tm_sec);
    }
    else
    {
        sprintf(buffer, "%02d:%02d:%02d", t->tm_hour > 12 ? t->tm_hour - 12 : t->tm_hour, t->tm_min, t->tm_sec);
    }

    pStr = (char *)malloc((strlen(buffer) + 1) * sizeof(char));
    strcpy(pStr, buffer);
    return pStr;
}

习题13.3 定义一个print_value(expr)宏,在新的一行上输出 exp = result,其中result的值由expr算出。编写一个例子,说明这个宏可以正常工作。

#include <stdio.h>

#define print_value(expr) printf("exp = %d\n", expr)

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

推荐阅读更多精彩内容