《C Prime Plus》编程练习11_11题目分析

151 阅读5分钟

题目

编写一个函数,读入10个字符串或者读到EOF时停止。该程序给用户提供一个5个选项的菜单:

  1. 打印源字符列表
  2. 以首字母ASCII顺序排列打印每个字符串
  3. 按长度递增的顺序打印每个字符串
  4. 按每个字符串第一个单词的长度递增顺序打印字符串
  5. 退出 除非用户选择退出的选项,否则要求菜单必须循环显示。

题目分析

这道题初见做起来非常的难,可以说是打击了我学C语言一个月以来所有的自信心。

程序结构

开头要有一堆头文件、常量,然后是一堆函数原型,然后是主函数,然后是函数定义。 主函数里,对于这样一个多功能选项,使用switch是最好不过了。为了反复显示选项菜单,用一个while贯穿主函数,结束循环的条件为用户输入了退出选项.

具体功能分析

存储用户输入的容器: 要读入10个字符串,那就意味着要有一个包含是个字符串的二维数组,字符串元素的长度可以设置大一些。

正确处理用户的输入: 读入是个字符串,以用户按下回车键为间隔存储一个字符串元素。字符串元素的输入可以使用书本前面提供的自定义输入函数s_gets(),而如何把这些输入的函数一个一个存进二维数组,则需要另一个函数把s_gets()封装起来。

正确处理用户的选项: 选项的数据类型可以是字符也可以是整数,出于简单化,让用户输入整数来选择选项,那么就要正确处理用户的选项,用scanf()接收用户的输入,并且及时处理掉留在缓冲区的换行符,那么就要用单独的函数包装scanf()来处理用户的选项输入

打印源字符列表: 这个直接用迭代的方式把二维数组里的每个字符串打印出来即可。

以首字母ASCII顺序排列打印每个字符串: 这需要比较每个字符串元素首字母的ASCII整数值,然后进行排序

按长度递增的顺序打印每个字符串: 这需要比较每个字符串元素的长度,然后进行排序

按每个字符串第一个单词的长度递增顺序打印字符串: 这里不同于前两个选项,要先用专门的函数先计算出每个字符串元素第一个单词的长度,然后再进行排序。

C语言细节分析

正确处理二维数组和数组元素排序的关系

题目的排序相关的功能是特定要求的排序每个字符串,并非改变字符串内部的数据,根据C语言的定义,数组名就是字符串的首元素地址,改变排序,实际上就是改变这些字符串元素首字符的之间的排序,更形象的表述--每个字符串元素的指针相当于标签,我们把标签按特定要求排序,也就改变了二维数组里面的字符串元素的排序。

所以,这道题的关键在于建立一个由指向字符串的指针作为元素的数组!!!!

字符串元素排序的算法

明确了排序字符串是利用存储了它们地址的指针数组,那么如何进行排序呢?利用二重for循环,依次在每个位置处进行整个数组内最值的寻找,单次内循环的目的是将本次内循环中的最值与这个位置的值进行互换,然后下一次外循环,只在下一个位置开始到数组末尾这段中寻找最值。

形参的指针类型

既然要创建一个指针数组和一个二维数组,那么他们作为参数传递给函数时,就要注意:

  1. 指针数组作为参数,形参就是指向指针的指针(char **)
  2. 二维数组作为参数,形参就是指向字符串的指针(char (*)[])

代码展示

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

#define ROWS 10 //十个字符串
#define COLS 10 //每个字符串长度不超过10

void user_input(char (*)[], char **, int); //处理用户输入的字符串信息,第一个形参是指向二维数组的指针,第二个形参是指针数组里的指针,第三个整数形参是数组第一维度

void menu(void); //显示菜单

int user_select(void); //处理用户的选项信息

int word_length(char *); //计算字符串元素里第一个单词的长度,要省略掉开头的空白符

void origin_print(char (*)[], int); //直接打印源字符串数组

void ascll_print(char **, int); //按ASCII排列首字母并打印

void length_print(char **str, int); //按字符串元素长度递增来打印

void first_length(char **str, int); //按首单词长度递增来打印

int main(void) {
    char string[ROWS][COLS]; //声明存储用户输入内容的二维数组
    char *str[ROWS]; //声明指针数组
    int select;
    printf("Please enter your 10 string:\n");
    user_input(string, str, ROWS);
    menu();
    while ((select = user_select()) != 5) {
        switch (select) {
            case 1:
                origin_print(string, ROWS);
                break;
            case 2:
                ascll_print(str, ROWS);
                break;
            case 3:
                length_print(str, ROWS);
                break;
            case 4:
                first_length(str, ROWS);
                break;
            default:
                break;
        }
        menu();
    }
    return 0;
}

void user_input(char (*string)[COLS], char **str, int n) {
    for (int i = 0; i < n; ++i) {
        s_gets(string[i], ROWS);
        str[i] = string[i]; //str指针数组里的指针指向string每个字符串元素的首字符地址
    }
}

void menu(void) {
    printf("*********************************************\n");
    printf("Selection:\n");
    printf("1)print str             2)paixu form ascii   \n");
    printf("3)an length pai xu      4)printf for 1st word\n");
    printf("5)quit\n");
    printf("*********************************************\n");
    printf("Your selecttion: ");
}

int user_select(void) {
    int i;
    scanf("%d", &i);
    while (getchar() != '\n') continue; //消除缓冲区的换行符
    return i;
}

int word_length(char *str) {
    int length = 0;
    bool inwords = false;
    while (*str) {
        if (!isspace(*str) && !inwords) {
            inwords = true;
            length++;
        } else if (!isspace(*str) && !inwords) length++;
        else if (isspace(*str) && inwords) break;
        str++;//str指向下一个字符元素
    }
    return length;
}

void origin_print(char (*string)[COLS], int n) {
    printf("Origin string are:\n");
    for (int i = 0; i < n; ++i) {
        puts(string[i]);
    }
}

void ascll_print(char **str, int n) {
    char *temp;
    for (int i = 0; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
            if (strcmp(str[i], str[j]) > 0) {
                temp = str[i];
                str[i] = str[j];
                str[j] = temp;
            }
        }
    }
    for (int i = 0; i < n; ++i) {
        puts(str[i]);
    }
}

void length_print(char **str, int n) {
    char *temp;
    for (int i = 0; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
            if (strlen(str[i]) > strlen(str[j])) {
                temp = str[i];
                str[i] = str[j];
                str[j] = temp;
            }
        }
    }
    for (int i = 0; i < n; ++i) {
        puts(str[i]);
    }
}

void first_length(char **str, int n) {
    char *temp;
    for (int i = 0; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
            if (word_length(str[i]) > word_length(str[j])) {
                temp = str[i];
                str[i] = str[j];
                str[j] = temp;
            }
        }
    }
    for (int i = 0; i < n; ++i) {
        puts(str[i]);
    }
}
```CPrimePlus-编程练习11_11分