C高级第三次作业

PTA第一部分

6-1 输出月份英文名(15 分)

本题要求实现函数,可以返回一个给定月份的英文名称。

函数接口定义:

char *getmonth( int n );

函数getmonth应返回存储了n对应的月份英文名称的字符串头指针。如果传入的参数n不是一个代表月份的数字,则返回空指针NULL。

裁判测试程序样例:

#include <stdio.h>

char *getmonth( int n );

int main()
{
    int n;
    char *s;

    scanf("%d", &n);
    s = getmonth(n);
    if ( s==NULL ) printf("wrong input!\n");
    else printf("%s\n", s);

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例1:

5

输出样例1:

May

输入样例2:

15

输出样例2:

wrong input!

1.设计思路:

(1).题目算法描述
第一步:定义*month[]并初始化为各个月份
第二步:定义*s
第三步:当n是月份时将对应的月份赋值给s,否则将wrong input!赋值给s
第四步:return s

(2).流程图
暂略

2.实验代码

char *getmonth( int n )
{
    char *month[13] = {"January","February","March","April","May","June","July","August","September","October","November","December","wrong input!"};
    char *s;
    if(n>=1 && n<=12)
    {
        s = month[n-1];
    }else
    {
        s = month[12];
    }
    return s;
}

2.错误调试

答案正确

答案正确

6-2 查找星期(15 分)

本题要求实现函数,可以根据下表查找到星期,返回对应的序号。

序号 星期
0 Sunday
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday

函数接口定义:

int getindex( char *s );

函数getindex应返回字符串s序号。如果传入的参数s不是一个代表星期的字符串,则返回-1。

裁判测试程序样例:

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

#define MAXS 80

int getindex( char *s );

int main()
{
    int n;
    char s[MAXS];

    scanf("%s", s);
    n = getindex(s);
    if ( n==-1 ) printf("wrong input!\n");
    else printf("%d\n", n);

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例1:

Tuesday

输出样例1:

2

输入样例2:

today

输出样例2:

wrong input!

1.设计思路:

(1).题目算法描述
第一步:定义*week[]并初始化为各个星期
第二步:遍历week判断是否与s相同
第三步:相同返回对应下标,不相同是返回-1

(2).流程图
暂略

2.实验代码

int getindex( char *s )
{
    int i=0;
    char *week[8] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
    for(i=0;i<7;i++)
    {
        if(strcmp(s,week[i])==0)
        {
            break;
        }
    }
    if(i<7){
        return i;
    }else{
        return -1;
    }
}


2.错误调试

答案正确

答案正确

6-3 计算最长的字符串长度(15 分)

本题要求实现一个函数,用于计算有n个元素的指针数组s中最长的字符串的长度。

函数接口定义:

int max_len( char *s[], int n );

其中n个字符串存储在s[]中,函数max_len应返回其中最长字符串的长度。

裁判测试程序样例:

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

#define MAXN 10
#define MAXS 20

int max_len( char *s[], int n );

int main()
{
    int i, n;
    char *string[MAXN] = {NULL};

    scanf("%d", &n);
    for(i = 0; i < n; i++) {
        string[i] = (char *)malloc(sizeof(char)*MAXS);
        scanf("%s", string[i]);
    }
    printf("%d\n", max_len(string, n));

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

4
blue
yellow
red
green

输出样例:

6

1.设计思路:

(1).题目算法描述
第一步:定义i,max
第二步:for循环遍历s判断每个字符串长度与max的关系将最大长度赋值给max
第三步:返回max

(2).流程图
流程图

2.实验代码

int max_len( char *s[], int n )
{
    int i=0,max=0;
    for(i=0;i<n;i++)
    {
        if(strlen(s[i])>max){
            max = strlen(s[i]);
        }
    }
    return max;

}

2.错误调试

答案正确

答案正确

6-4 指定位置输出字符串(20 分)

本题要求实现一个函数,对给定的一个字符串和两个字符,打印出给定字符串中从与第一个字符匹配的位置开始到与第二个字符匹配的位置之间的所有字符。

函数接口定义:

char *match( char *s, char ch1, char ch2 );

函数match应打印s中从ch1ch2之间的所有字符,并且返回ch1的地址。

裁判测试程序样例:

#include <stdio.h>

#define MAXS 10

char *match( char *s, char ch1, char ch2 );

int main()
{
    char str[MAXS], ch_start, ch_end, *p;

    scanf("%s\n", str);
    scanf("%c %c", &ch_start, &ch_end);
    p = match(str, ch_start, ch_end);
    printf("%s\n", p);

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例1:

program
r g

输出样例1:

rog
rogram

输入样例2:

program
z o

输出样例2:

(空行)
(空行)

输入样例3:

program
g z

输出样例3:

gram
gram

1.设计思路:

(1).题目算法描述
第一步:定义整型变量i,j,len
第二步:定义指针变量并初始化为NULL
第三步:统计len的长度并将值赋给len
第四步:遍历s当找到与找到第一个与ch1相同的字符是让p指向它
第五步:从第一个与ch1相同字符串之后继续向下遍历,如果其后的字符串与ch2不相同则输出此字符串继续向下遍历,如果相同输出此字符串并换行返回p
第六步:当遍历全部完成后则换行返回p

(2).流程图
暂略

2.实验代码

char *match( char *s, char ch1, char ch2 )
{
    int i = 0, j = 0,len = 0;
    char *p=NULL;
    len = strlen(s);//统计字符串长度
    for(i = 0;i < len;i++)//遍历s
    {
        if(*(s+i)==ch1){
            p = &s[i];//让p指向第一个与ch1相同的字符
            for(j = i;j < len;j++)//从第一个相同的字符开始继续向下遍历
            {
                if(s[j]!=ch2){
                    printf("%c",*(s+j));//第一个字符之后的字符如果与最后一个字符串不相同则输出此字符
                }
                if(s[j] == ch2){
                    printf("%c\n",*(s+j));//当与第二个字符相同时则输出此字符并换行后返回p
                    return p;
                }
            }
            printf("\n");
            return p;
        }
    }
    printf("\n");
    return p;
}


2.错误调试

错误提示1:段错误
改正方法:将指针p初始化为NULL
改正后的代码在Cold::Blocks上每个示例均能运行出正确答案,但是在PTA上仍是部分正确
错误提示

求大佬指教!!!

编程题

有一个axb的数组,该数组里面顺序存放了从1到a*b的数字。其中a是你大学号的前三位数字,b是你大学号的后四位数字,比如你的学号是2017023936,那么数组大小是201 x 3936,数组中顺序存放了1到791136(201和3936的积)的整数. 要求用筛选法,把该数组里的质数找出并打印出来,打印格式为5个质数一行,数字间用空格隔开。

筛选法具体做法是:先把N个自然数按次序排列起来。1不是质数,也不是合数,要划去。第二个数2是质数留下来,而把2后面所有能被2整除的数都划去。2后面第一个没划去的数是3,把3留下,再把3后面所有能被3整除的数都划去。3后面第一个没划去的数是5,把5留下,再把5后面所有能被5整除的数都划去。这样一直做下去,就会把不超过N的全部合数都筛掉,留下的就是不超过N的全部质数。

1.设计思路:

参考教程:https://baike.baidu.com/item/筛选法/9393288?fr=aladdin#2_2(来源百度百科)
(1).题目算法描述
第一步:计算学号前三位和后四位的乘积并赋值给n
第二步:定义大小为n的数组axb
第三步:遍历数组输入1到n的值
第四步:从2开始遍历数组将所有合数和能被此合数整除的数全都赋值为一
第五步:输出值不是1的数

(2).流程图
流程图

2.实验代码

#include <stdio.h>
#include <math.h>
int main ()
{
    long int n=0,i=0,j=0,x=0;
    n = 201*3990;
    int axb[n];

    for(i=1;i<n;i++)
    {
        axb[i-1] = i;
    }
    for(i=1;i<=n;i++)
    {
        for(j=2;j<=sqrt(i);j++)
        {
            if(i%j==0){
                axb[i-1]=1;
            }
        }
    }
    for(i=0,x=0;i<n;i++)
    {
        if(axb[i]!=1){
            printf("%d ",axb[i]);
            x++;
            if(x%5 == 0){
            printf("\n");
            }
        }
    }
    return 0;
}

2.错误调试

修改

经过课堂讲解后发现自己的错误,没有将存储学号的数组写成二维数组。
修改后的代码如下


#include <stdio.h>
#define N 201
#define M 3990

int a[N][M];//全局变量
void del(int a[N][M],int x){
     int i=0,j=0;
     for(i=0;i<N;i++){
        for(j=1;j<M;j++){
             if(i==0 && j==0){
                    continue;
             }
             if(a[i][j]>x &&(a[i][j] % x== 0)){
                    a[i][j]=0;
             }
        }
    }
}

int main ()
{
    int i=0,j=0,num=1,count=0;
    for(i=0;i<N;i++){
        for(j=0;j<M;j++){
             a[i][j] = num++;
        }
    }
    a[0][0]=0;//去掉a[0][0]从第一个数开始
    for(i=0;i<N;i++){
        for(j=0;j<M;j++){
             if(a[i][j] != 0){
                del(a,a[i][j]);
             }
        }
    }
    for(i=0;i<N;i++){
        for(j=0;j<M;j++){
             if(a[i][j] != 0){
                printf("%d ",a[i][j]);
                count++;
                if(count%5 == 0){
                    printf("\n");
                }
             }
        }
    }
    return 0;
}


答案正确

输出结果截图

PTA第二部分

6-1 奇数值结点链表(20 分)

本题要求实现两个函数,分别将读入的数据存储为单链表、将链表中奇数值的结点重新组成一个新的链表。链表结点定义如下:

struct ListNode {
    int data;
    ListNode *next;
};

函数接口定义:

struct ListNode *readlist();
struct ListNode *getodd( struct ListNode **L );

函数readlist从标准输入读入一系列正整数,按照读入顺序建立单链表。当读到−1时表示输入结束,函数应返回指向单链表头结点的指针。

函数getodd将单链表L中奇数值的结点分离出来,重新组成一个新的链表。返回指向新链表头结点的指针,同时将L中存储的地址改为删除了奇数值结点后的链表的头结点地址(所以要传入L的指针)。

裁判测试程序样例:

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

struct ListNode {
    int data;
    struct ListNode *next;
};

struct ListNode *readlist();
struct ListNode *getodd( struct ListNode **L );
void printlist( struct ListNode *L )
{
     struct ListNode *p = L;
     while (p) {
           printf("%d ", p->data);
           p = p->next;
     }
     printf("\n");
}

int main()
{
    struct ListNode *L, *Odd;
    L = readlist();
    Odd = getodd(&L);
    printlist(Odd);
    printlist(L);

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

1 2 2 3 4 5 6 7 -1

输出样例:

1 3 5 7 
2 2 4 6

1.设计思路:

(1).题目算法描述
第一个部分:
第一步:定义num并初始化为0
第二步:定义结构指针head p tail并初始化
第三步:用动态内存分配为p申请空间;读入num,当num不是-1时将其赋给p->data;如果head是空head=p否则tail->next=p
第四步:重复以上过程知道读入的数据为-1
第五步:释放p
第六步:return head
第二部分:
第一步:定义n并初始化为0
第二步:定义结构指针head,tail,q,p,p1,p2,ptr
第三步:当p->data为奇数时,用动态内存分配为q申请空间q->data = p->data;q->next = NULL;如果head为空则head=q否则tail->next=q然后将q的值赋给tail将p的值赋给ptr,p指向下一个节点,并释放申请的空间
第四步:当p->data不是奇数时,如果p1为空p1=p否则p2->next =p; p2=p; p= p->next; n=1
第五步:判断当n=1时p2->next为空
第六步:*L = p1
第七步:return head
(2).流程图
暂略

2.实验代码

struct ListNode *readlist(){
    int num=0;
    struct ListNode *head=NULL, *p=NULL, *tail=NULL;
    p = (struct ListNode*)malloc(sizeof(struct ListNode));
    scanf("%d", &num);
    while(num != -1){
        p->data = num;
        p->next=NULL;
        if(head == NULL){
            head=p;
        }
        else{
            tail->next=p;
        }
        tail=p;
        p=(struct ListNode*)malloc(sizeof(struct ListNode));
        scanf("%d", &num);
    }
    free(p);
    return head;
}
  struct ListNode *getodd(struct ListNode **L){
      int n = 0;
      struct ListNode *head=NULL, *tail=NULL, *q=NULL, *p=*L, *p1=NULL, *p2=NULL, *ptr=NULL;

      while (p!=NULL)
      {
          if (p->data % 2 != 0)
          {
              q = (struct ListNode *) malloc(sizeof(struct ListNode));
              q->data = p->data;
              q->next = NULL;
              if (head == NULL)
                  head = q;
              else
                  tail->next = q;
              tail = q;
              ptr = p;
              p = p->next;
              free(ptr);
          }
          else
          {
              if (p1 == NULL){
                p1 = p;
              }
              else{
                p2->next = p;
              }
              p2 = p;
              p = p->next;
              n = 1;
          }
      }
      if (n==1){
        p2->next = NULL;
      }
      *L = p1;
      return head;
  }


2.错误调试

错误提示:全是奇数全是偶数第一个是奇数的测试点答案错误
错误改正:第一次上完课后对相关链表的操作只是知道大概的操作思路,并不清楚相关的代码应该怎么写,对于相关插入、删除的写法更是一头雾水,在网上简单的看来相关的资料但并不是十分理解。上了第二次课后理解的相对好了一些,重新写了所有代码,以上贴的是修改后的代码

6-2 学生成绩链表处理(20 分)

本题要求实现两个函数,一个将输入的学生成绩组织成单向链表;另一个将成绩低于某分数线的学生结点从链表中删除。

函数接口定义:

struct stud_node *createlist();
struct stud_node *deletelist( struct stud_node *head, int min_score );

函数createlist利用scanf从输入中获取学生的信息,将其组织成单向链表,并返回链表头指针。链表节点结构定义如下:

struct stud_node {
    int              num;      /*学号*/
    char             name[20]; /*姓名*/
    int              score;    /*成绩*/
    struct stud_node *next;    /*指向下个结点的指针*/
};

输入为若干个学生的信息(学号、姓名、成绩),当输入学号为0时结束。

函数deletelist从以head为头指针的链表中删除成绩低于min_score的学生,并返回结果链表的头指针。

裁判测试程序样例:

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

struct stud_node {
     int    num;
     char   name[20];
     int    score;
     struct stud_node *next;
};

struct stud_node *createlist();
struct stud_node *deletelist( struct stud_node *head, int min_score );

int main()
{
    int min_score;
    struct stud_node *p, *head = NULL;

    head = createlist();
    scanf("%d", &min_score);
    head = deletelist(head, min_score);
    for ( p = head; p != NULL; p = p->next )
        printf("%d %s %d\n", p->num, p->name, p->score);

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

1 zhang 78
2 wang 80
3 li 75
4 zhao 85
0
80

输出样例:

2 wang 80
4 zhao 85

1.设计思路:

(1).题目算法描述
第一部分:
第一步:定义结构指针head,tail,q并初始化
第二步:定义num并读入num
第三步:当num不等于0时,动态内存分配为q申请空间;读入q->name和q->score;当head为空的时候head=q否则tail->next=q
第四步:tail=q;继续读入num
第五步:当num等于0时停止读入并return head
第二部分:
第一步:定义结构指针ptr1和ptr2
第二步:当head不为空并且head->score小于min->score时ptr2=head;head=head->next;并释放ptr2的空间
第三步:当head为空时return NULL;
第四步:ptr1=head;ptr2=head->next
第五步:当ptr2不为空时 判断如果ptr2->score小于min_score则ptr1->next = ptr2->next;并释放ptr2的空间否则ptr1=ptr2然后ptr2=ptr1->next
第六步:return head;
(2).流程图
流程图
流程图

2.实验代码

struct stud_node *createlist()
{
    struct stud_node *head, *tail, *q;
    head = NULL;
    tail = NULL;
    int num;
    scanf ("%d", &num);
    while (num != 0)
    {
        q = (struct stud_node *)malloc (sizeof (struct stud_node));
        scanf ("%s %d", q->name, &q->score);
        q->num = num;
        q->next = NULL;
        if (head == NULL){
            head = q;
        }
        else{
            tail->next = q;
        }
        tail = q;
        scanf ("%d", &num);
    }
    return head;
}

struct stud_node *deletelist( struct stud_node *head, int min_score )
{
    struct stud_node *ptr1, *ptr2;
    while (head != NULL && head->score < min_score)
    {
        ptr2 = head;
        head = head->next;
        free(ptr2);
    }
    if (head == NULL){
        return NULL;
    }
    ptr1 = head;
    ptr2 = head->next;
    while (ptr2 != NULL)
    {
        if (ptr2->score < min_score) {
            ptr1->next = ptr2->next;
            free(ptr2);
        }
        else{
             ptr1 = ptr2;
        }
        ptr2 = ptr1->next;
    }
    return head;
}

2.错误调试

6-3 链表拼接(20 分)

本题要求实现一个合并两个有序链表的简单函数。链表结点定义如下:

struct ListNode {
    int data;
    struct ListNode *next;
};

函数接口定义:

struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2);

其中list1list2是用户传入的两个按data升序链接的链表的头指针;函数mergelists将两个链表合并成一个按data升序链接的链表,并返回结果链表的头指针。

裁判测试程序样例:

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

struct ListNode {
    int data;
    struct ListNode *next;
};

struct ListNode *createlist(); /*裁判实现,细节不表*/
struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2);
void printlist( struct ListNode *head )
{
     struct ListNode *p = head;
     while (p) {
           printf("%d ", p->data);
           p = p->next;
     }
     printf("\n");
}

int main()
{
    struct ListNode  *list1, *list2;

    list1 = createlist();
    list2 = createlist();
    list1 = mergelists(list1, list2);
    printlist(list1);
	
    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

1 3 5 7 -1
2 4 6 -1

输出样例:

1 2 3 4 5 6 7

1.设计思路:

(1).题目算法描述
第一步:定义结构指针p,head,tail并初始化
第二步:定义整型数组list[100]和整型变量i,j,swap,count并初始化为0
第三步:当list1不为空时list[i]=list1->data;list1=list1->next;i++;count++;
第四步:当list2不为空时list[i]=list2->data;list2=list2->next;i++;count++;
第五步:对list进行排序
第六步:遍历list用动态内存分配为p申请空间p->data=list[i];p->next=NULL;判断当head=NULL时head=p否则tail->next=p;然后tail=p;
第七步:return head
(2).流程图
流程图

2.实验代码

struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2){
    struct ListNode *p=NULL,*head=NULL,*tail=NULL;
    int list[100],i=0,j=0,swap=0,count=0;
    while(list1!=NULL){
        list[i]=list1->data;
        list1=list1->next;
        i++;
        count++;
    }
    while(list2!=NULL){
        list[i]=list2->data;
        list2=list2->next;
        i++;
        count++;
    }
    for(i=0;i<count;i++){
        for(j=i+1;j<count;j++){
                if(list[i]>list[j]){
                    swap=list[i];list[i]=list[j];list[j]=swap;
                }
        }
    }
    for(i=0;i<count;i++){
        p=(struct ListNode*)malloc(sizeof(struct ListNode));
        p->data=list[i];
        p->next=NULL;
        if(head==NULL){
            head=p;
        }
        else{
            tail->next=p;
        }
        tail=p;
    }
    return head;
}


2.错误调试


题目提交列表:

1.学习进度总结

(1).指针数组:学习了用指针数组对字符串进行相关的处理
(2).筛选法:学习了筛选法的相关思路和具体的程序实现方法
(3).链表:学习并了解了链表的相关知识,明确了链表的优点,掌握了链表的相关思路但是链表具体的代码实现方法还有待加强练习
(4).结构:为了更好的学习链表在mooc复习了相关结构的内容
(5)二级指针:还是感觉用起来很混乱,不清晰

2.问题回答

(1)如何理解指针数组,它与指针、数组有何关系?为何可以用二级指针对指针数组进行操作?

指针数组:元素全都是指针的数组
数组的名称可以代表数组首元素的地址,有了首元素的地址就可以用二级指针对数组的元素进行操作

(2)将C高级第三次PTA作业(1)任何一个题目改为使用二级指针对指针数组进行操作。

修改C高级第三次PTA作业(1)中的第一题
修改后的代码:

char *getmonth( int n )
{
    char *month[13] = {"January","February","March","April","May","June","July","August","September","October","November","December","wrong input!"};
    char **s;
    if(n>=1 && n<=12)
    {
        s = &month[n-1];
    }
    else
    {
        s = &month[12];
    }
    return *s;
}

(3)用指针数组处理多个字符串有何优势?可以直接输入多个字符串给未初始化的指针数组吗?为什么?

优势:处理起来更加便捷
不可以,指针没有初始化的话就不知道指向哪里,有可能指的是不允许用户更改的区域,这时候就会出现段错误

2.代码托管

我的GitHub地址:https://github.com/XINJY/The-homework-of-C
上传成功截图:

3.作业点评

李伍壹:http://www.cnblogs.com/chenxidream/p/8778302.html
李新华:http://www.cnblogs.com/Lixinhua18/p/8810369.html
马钰娟:http://www.cnblogs.com/dfgfds/p/8906883.html

4.表格和折线图(由于博客字数太多,所以单独做了折线图)



posted @ 2018-04-09 22:38  瑶啊摇✨  阅读(2385)  评论(10编辑  收藏  举报