• 第十一周作业



    这个作业属于哪个课程 C语言程序设计
    这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/software-engineering-class2-2018/homework/3201
    这个作业在哪个具体方面帮我实现了目标 合理定义程序的多函数结构;能够使用递归函数进行编程;掌握宏的基本用法;掌握编译预处理的概念
    参考文献 C语言程序设计和Cprimer plus


    1.[选择题]



    2.[7-1 汉诺塔问题]
    汉诺塔是一个源于印度古老传说的益智玩具。据说大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘,大梵天命令僧侣把圆盘移到另一根柱子上,并且规定:在小圆盘上不能放大圆盘,每次只能移动一个圆盘。当所有圆盘都移到另一根柱子上时,世界就会毁灭。

    请编写程序,输入汉诺塔圆片的数量,输出移动汉诺塔的步骤。
    输入格式

    圆盘数 起始柱 目的柱 过度柱
    

    输出格式

    移动汉诺塔的步骤
    每行显示一步操作,具体格式为:
    盘片号: 起始柱 -> 目的柱
    其中盘片号从 1 开始由小到大顺序编号。
    

    输入样例

    3
    a c b
    

    输出样例

    1: a -> c
    2: a -> b
    1: c -> b
    3: a -> c
    1: b -> a
    2: b -> c
    1: a -> c
    

    实验代码;

    #include<stdio.h>
    void hanio(int n,char a,char b,char c);
    int main (void)
    {
        int n;
        char a,b,c;
        scanf("%d
    ",&n);
        scanf("%c %c %c",&a,&b,&c);
        hanio(n,a,b,c);
        return 0;
    }
    void hanio (int n,char a,char b,char c)
    {
        if(n==1)
          printf("%d: %c -> %c
    ",n,a,b);
        else {
            hanio (n-1,a,c,b);
            printf("%d: %c -> %c
    ",n,a,b);
            hanio(n-1,c,b,a);
        }
    }
    

    正确截图;

    错误截图:

    错误原因:
    没有理解理解递归函数的真正意思,是调用函数本身,就单纯套用书本上的,移动方式虽然清楚但做起来就容易出现错误
    实验流程图:


    3.[7-2 估值一亿的AI核心代码:]


    以上图片来自新浪微博。
    本题要求你实现一个稍微更值钱一点的 AI 英文问答程序,规则是:
    无论用户说什么,首先把对方说的话在一行中原样打印出来;
    消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
    把原文中所有大写英文字母变成小写,除了 I;
    把原文中所有独立的 can you、could you 对应地换成 I can、I could—— 这里“独立”是指被空格或标点符号分隔开的单词;
    把原文中所有独立的 I 和 me 换成 you;
    把原文中所有的问号 ? 换成惊叹号 !;
    在一行中输出替换后的句子作为 AI 的回答。
    输入格式:

    输入首先在第一行给出不超过 10 的正整数 N,随后 N 行,每行给出一句不超过 1000 个字符的、以回车结尾的用户的对话,对话为非空字符串,仅包括字母、数字、空格、可见的半角标点符号。
    

    输出格式:

    按题面要求输出,每个 AI 的回答前要加上 AI: 和一个空格。
    

    输入样例:

    6
    Hello ?
     Good to chat   with you
    can   you speak Chinese?
    Really?
    Could you show me 5
    What Is this prime? I,don 't know
    

    输出样例:

    Hello ?
    AI: hello!
     Good to chat   with you
    AI: good to chat with you
    can   you speak Chinese?
    AI: I can speak chinese!
    Really?
    AI: really!
    Could you show me 5
    AI: I could show you 5
    What Is this prime? I,don 't know
    AI: what Is this prime! you,don't know
    

    本题不会做

    4.[***八皇后问题]
    在国际象棋中,皇后是最厉害的棋子,可以横走、直走,还可以斜走。棋手马克斯·贝瑟尔 1848 年提出著名的八皇后问题:即在 8 × 8 的棋盘上摆放八个皇后,使其不能互相攻击 —— 即任意两个皇后都不能处于同一行、同一列或同一条斜线上。
    现在我们把棋盘扩展到 n × n 的棋盘上摆放 n 个皇后,请问该怎么摆?请编写程序,输入正整数 n,输出全部摆法(棋盘格子空白处显示句点“.”,皇后处显示字母“Q”,每两格之间空一格)。
    输入格式

    正整数 n (0 < n ≤ 12)
    

    输出格式

    若问题有解,则输出全部摆法(两种摆法之间空一行),否则输出 None。
    要求:试探的顺序逐行从左往右的顺序进行,请参看输出样例2。
    

    输入样例1

    3
    

    输出样例1

    None
    

    输入样例2

    6
    

    输出样例2

    . Q . . . .
    . . . Q . .
    . . . . . Q
    Q . . . . .
    . . Q . . .
    . . . . Q .
    
    . . Q . . .
    . . . . . Q
    . Q . . . .
    . . . . Q .
    Q . . . . .
    . . . Q . .
    
    . . . Q . .
    Q . . . . .
    . . . . Q .
    . Q . . . .
    . . . . . Q
    . . Q . . .
    
    . . . . Q .
    . . Q . . .
    Q . . . . .
    . . . . . Q
    . . . Q . .
    . Q . . . .
    

    本题不会做
    预习作业:
    预习作业:
    ···
    第十二周的教学内容是:第十一章 指针进阶
    请大家查阅资料,思考如下问题:
    请举实例解释以下几个概念:数组指针,指针数组,指针函数,函数指针,二级指针,单向链表。(无实例不给分)
    请用自己的理解回答。如果有引用他人的文字,请一定要标出出处(使用Markdown的链接方式)。

    一、指针数组
    是一个存放指针的数组。
    

    eg:

    int arr[];//[]优先级高,所以arr首先是一个数组,里面存放的是一个个指针int* arr[];//数组中放入二级指针

    二、数组指针
    是一个指向数组的指针。
    

    eg:

    int (arr)[10];//指向int[10]的指针解释:arr先和结合,说明arr是一个指针变量量,然后指针指向的是一个大小为10个整型

    的数组。所以arr是一个指针,指向一个数组,叫数组指针

    那么,数组的地址应该如何存放呢?
    

    int arr[10] = {0};intp1 = &arr;int (p2)[10] = &arr;

    看上面两种存放方式,显然,选择p2比较合适,因为p2是数组指针。
    指针函数
    定义
    指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。
    声明格式为:*类型标识符 函数名(参数表)
    这似乎并不难理解,再进一步描述一下。
    看看下面这个函数声明:
    

    int fun(int x,int y);

    1
    这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值。
    接着看下面这个函数声明:
    

    int *fun(int x,int y);

    这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。
    这样描述应该很容易理解了,所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。
    指针函数的写法
    

    int fun(int x,int y);
    int * fun(int x,int y);
    int
    fun(int x,int y);
    123

    这个写法看个人习惯,其实如果*靠近返回值类型的话可能更容易理解其定义。
    示例
    来看一个非常简单的示例:
    

    typedef struct _Data{
    int a;
    int b;
    }Data;

    //指针函数
    Data* f(int a,int b){
    Data * data = new Data;
    data->a = a;
    data->b = b;
    return data;
    }

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    //调用指针函数
    Data * myData = f(4,5);
    qDebug() << "f(4,5) = " << myData->a << myData->b;

    return a.exec();
    

    }

    1234567891011121314151617181920212223

    输出如下:
    

    f(4,5) = 4 5
    1

    注意:在调用指针函数时,需要一个同类型的指针来接收其函数的返回值。
    不过也可以将其返回值定义为 void*类型,在调用的时候强制转换返回值为自己想要的类型,如下:
    

    //指针函数
    void* f(int a,int b){
    Data * data = new Data;
    data->a = a;
    data->b = b;
    return data;
    }

    
    调用:
    

    Data * myData = static_cast<Data*>(f(4,5));
    12345678910

    其输出结果是一样的,不过不建议这么使用,因为强制转换可能会带来风险。
    函数指针
    定义
    函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。
    声明格式:类型说明符 (*函数名)   (参数)
    如下:
    

    int (*fun)(int x,int y);

    1
    函数指针是需要把一个函数的地址赋值给它,有两种写法:
    

    fun = &Function;
    fun = Function;
    12

    取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
    调用函数指针的方式也有两种:
    

    x = (*fun)();
    x = fun();
    12

    两种方式均可,其中第二种看上去和普通的函数调用没啥区别,如果可以的话,建议使用第一种,因为可以清楚的指明这是通过指针的方式来调用函数。当然,也要看个人习惯,如果理解其定义,随便怎么用都行啦。
    示例
    

    int add(int x,int y){
    return x+y;
    }
    int sub(int x,int y){
    return x-y;
    }
    //函数指针
    int (*fun)(int x,int y);

    int main(int argc, char argv[])
    {
    QApplication a(argc, argv);
    //第一种写法
    fun = add;
    qDebug() << "(
    fun)(1,2) = " << (fun)(1,2) ;
    //第二种写法
    fun = ⊂
    qDebug() << "(
    fun)(5,2) = " << (*fun)(5,3) << fun(5,3);

    return a.exec();
    

    }

    12345678910111213141516171819202122

    输出如下:
    

    (fun)(1,2) = 3
    (
    fun)(5,2) = 2 2
    12

    上面说到的几种赋值和调用方式我都分别使用了,其输出结果是一样的。
    二者区别
    通过以上的介绍,应该都能清楚的理解其二者的定义。那么简单的总结下二者的区别:
    ###定义不同
    指针函数本质是一个函数,其返回值为指针。
    函数指针本质是一个指针,其指向一个函数。
    写法不同
    

    指针函数:int* fun(int x,int y);
    函数指针:int (*fun)(int x,int y);

    可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。
    再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。
    在如下的A指向B、B指向C的指向关系中:
    首先
    C是"一段内容",比如你用malloc或者new分配了一块内存,然后塞进去"一段内容",那就是C了。C的起始地址是0x00000008。
    B是一个指针变量,其中存放着C的地址,但是B也要占空间的啊,所以B也有地址,B的起始地址是0x00000004,但是B内存中存放的是C的地址,所以B里面的内容就是0x00000008。
    那么到此为止都比较好理解:
    B= 0x00000008;  //B的内容 *B = "一段内容";  //B解引用,也就是B指针指向的C的值&B = 0x00000004;  //B取地址,B的地址是0x00000004那么,再来看A:
    
    A是二级指针变量,其中存放着B的地址0x00000004,A也有地址,是0x00000000;
    
    *A = B= 0x00000008;  //A解引用也就是B的内容 **A = *B = "一段内容";  //B解引用,也就是B指针指向的C的值A = &B = 0x00000004;  //A存的是B的地址,B的地址是0x00000004&A = 0x00000000;  //A取地址
    
    
    二、使用
    
    二级指针作为函数参数的作用:在函数外部定义一个指针p,在函数内给指针赋值,函数结束后对指针p生效,那么我们就需要二级指针。
    
    .二级指针操作
    

    include using namespace std;

    int a= 10;int b = 100;int q; void func(int **p) //2
    {
    cout<<"func:&p="<<&p<<",p="<<p<<endl;
    p = &b; //3
    cout<<"func:&p="<<&p<<",p="<<p<<endl;
    }
    int main()
    {
    cout<<"&a="<<&a<<",&b="<<&b<<",&q="<<&q<<endl;
    q = &a;
    cout<<"
    q="<<
    q<<",q="<<q<<",&q="<<&q<<endl;
    func(&q); //1
    cout<<"q="<<q<<",q="<<q<<",&q="<<&q<<endl;
    system("pause");
    return 0;
    }

    --这里只改了三个地方,变成传二级指针。我们再看:
    因为传了指针q的地址(二级指针**p)到函数,所以二级指针拷贝(拷贝的是p,一级指针中拷贝的是q所以才有问题),(拷贝了指针但是指针内容也就是指针所指向的地址是不变的)所以它还是指向一级指针q(*p = q)。在这里无论拷贝多少次,它依然指向q,那么*p = &b;自然的就是
     q = &b;了。
    

    链表是离散存储线性结构
    n个节点离散分配,彼此通过指针相连,每个节点只有一个前驱节点,每个节点只有一个后续节点,首节点没有前驱节点,尾节点没有后续节点。

    链表优点:
    空间没有限制
    插入删除元素很快
    链表缺点:
    存取速度很慢
    链表相关术语介绍,我还是通过上面那个图来说明吧:

    确定一个链表我们只需要头指针,通过头指针就可以把整个链表都能推导出来了~
    链表又分了好几类:
    单向链表
    一个节点指向下一个节点
    双向链表
    一个节点有两个指针域
    循环链表
    能通过任何一个节点找到其他所有的节点,将两种(双向/单向)链表的最后一个结点指向第一个结点从而实现循环
    操作链表要时刻记住的是:
    节点中指针域指向的就是一个节点
    实例:

    #include <stdio.h>
    #include <stdlib.h>
     
    struct grade {
        int score;
        struct grade *next;
    };
    typedef struct grade NODE;  //typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。
    //使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,
    //另一个是简化一些比较复杂的类型声明。
    struct grade *create();   //创建链表
    void insert(NODE *head,NODE *pnew,int i);   //插入链表
    void pdelete(NODE *head,int i);   //删除列表
    void display(NODE *head);   //输出链表
    void Pfree(NODE *head);    //销毁链表
     
    int main(int argc, char *argv[]) {
        struct grade *head,*pnew;
        head=create();
        if (head==NULL)
            return 0;
        printf("输出创建的链表:");
        display(head);
        pnew=(NODE *)malloc(sizeof(NODE));
        if (pnew==NULL) {
            printf("创建失败!");
            return 0;
        }
        pnew->score=88;
        insert(head,pnew, 3);   //将新节点插入节点3的后面
        printf("插入后的链表:");
        display(head);
        pdelete(head,3);   //删除节点3
        printf("删除后的链表:");
        display(head);
        Pfree(head);
        return 0;
    }
     
    struct grade *create() {
        NODE *head,*tail,*pnew;
        int score;
        head=(NODE *)malloc(sizeof(NODE));  //创建头节点。
        if (head==NULL) { //创建失败返回
            printf("创建失败!");
            return NULL;
        }
        head->next=NULL;  //头节点指针域置NULL
        tail=head;  // 开始时尾指针指向头节点
        printf("输入学生成绩:");
        while (1) { //创建链表
            scanf("%d",&score);
            if (score<0) //成绩为负是退出循环
                break;
            pnew=(NODE *)malloc(sizeof(NODE));  //创建新节点
            if (pnew==NULL) { //创建失败返回
                printf("创建失败!");
                return NULL;
            }
            pnew->score=score;  //新节点数据域存放输入的成绩
            pnew->next=NULL;   //新节点指针域置NULL
            tail->next=pnew;  //新节点插入到表尾
            tail=pnew;   //为指针指向当前的尾节点
        }
        return head;  //返回创建链表的头指针
    }
    void insert(NODE *head,NODE *pnew,int i) {
        NODE *p; //当前指针
        int j;
     
        p=head;
        for (j=0; j<i&&p!=NULL; j++) //p指向要插入的第i个节点
            p=p->next;
         
        if (p==NULL) { //节点i不存在
            printf("与插入的节点不存在!");
            return;
        }
     
        pnew->next=p->next;   //插入节点的指针域指向第i个节点的后继节点
        p->next=pnew;    //犟第i个节点的指针域指向插入的新节点
    }
     
    void pdelete(NODE *head,int i) {
        NODE *p,*q;
        int j;
        if (i==0) //删除的是头指针,返回
            return;
        p=head;
        for (j=1; j<i&&p->next!=NULL; j++)
            p=p->next;  //将p指向要删除的第i个节点的前驱节点
        if (p->next==NULL) { //表明链表中的节点不存在
            printf("不存在!");
            return;
        }
        q=p->next;  //q指向待删除的节点
        p->next=q->next;  //删除节点i,也可写成p->next=p->next->next
        free(q);   //释放节点i的内存单元
    }
    void display(NODE *head) {
        NODE *p;
        for (p=head->next; p!=NULL; p=p->next)
            printf("%d ",p->score);
        printf("
    ");
    }
    void pfree(NODE *head) {
        NODE *p,*q;
     
        p=head;
        while (p->next!=NULL) { //每次删除头节点的后继节点
            q=p->next;
            p->next=q->next;
            free(q);
        }
        free(head);   //最后删除头节点
    }
    void Pfree(NODE *head) {
        NODE *p,*q;
        p=head;
        while (p->next!=NULL) {
            q=p->next;
            p->next=q->next;
            free(q);
        }
        free(p);
    }
    

    原文:https://blog.csdn.net/majianfei1023/article/details/46629065
    链接出处:<https://blog.csdn.net/luoyayun361/article/details/80428882 >
    链接出处:<https://blog.csdn.net/weixin_40417029/article/details/78580080 >
    学习总结:
    后面的大题都看不懂,知识感觉太薄弱
    结对编程总结:
    感觉就还好,互相都有进步

    学习计划:

    时间 代码行数 这周花的时间 学到的知识点
    3/2-3/12 50 5天 主要是文件的相关问题
    3/9-3/20 70 5天 一维数组
    3/20-3/30 80 5天 二位数组
    3/22-3/28 100 5天 字符串的使用
    3/28-4/5 80 5天 指针
    4/5-4/12 124 5天 指针的具体操作
    4/14-4/19 113 5天 字符串函数以及使用指针操作字符串的方法和动态内存分配
    4/21-4/26 68 5天 使用结构变量与结构数组进行编程,掌握结构指针的操作,并应用于函数传递
    4/29-5/3 74 5天 怎样花两年时间面试一个人,如何有效地记忆与学习?以及如何提问?
    5/5-5/10 72 5天 合理定义程序的多函数结构;能够使用递归函数进行编程;掌握宏的基本用法;掌握编译预处理的概念
  • 相关阅读:
    【Java】_2_Java程序入门第五课
    【算法和数据结构】_3_线性结构_栈
    Windows程序设计_17_鼠标_1
    网络基础知识1:集线器,网桥,交换机
    [hyddd安全性测试笔记2]浅淡静态代码分析工具
    [Ruby小记]初试~
    Arp攻击实战
    [hyddd安全性测试笔记1]URL Encode and URL Decode
    网络嗅探技术浅析
    Session小记
  • 原文地址:https://www.cnblogs.com/xiaoyao1234/p/10847025.html
Copyright © 2020-2023  润新知