PA0:关于剩余练习1

练习16: 结构体里,如果用的是指针,那引用对应结构体的成员时要用->箭头,如果用实际变量名,那使用成员时用.点号即可。

  例子里面是用malloc来手动在堆里申请了一块内存来创建结构体,但没这个必要,结构体定义好以后,可以作为一个类型来使用,这样创建出来的结构体就在栈里面。

typedef struct test {
    int age;
    char sex;
} Test;
   
//这里用了typedef关键字,Test就是给test起的别名,之后可以用Test t1={40,‘m’}这样的格式来创建结构体实例

//或者,不用typedef,直接在结构体声明后实例
struct test {
    int age;
    char sex;
} t1, t2;

原题里用的是malloc:

struct Person *Person_create(char *name, int age, int height, int weight)

{

    struct Person *who = malloc(sizeof(struct Person));

    assert(who != NULL);

    who->name = strdup(name);

    who->age = age;

    who->height = height;

    who->weight = weight;

    return who;

}  附加题要求不用malloc,那连这个函数其实都可以不需要。就按照上面的,直接实例化,用大括号赋值即可。

 

----------------练习17------------

关于C语言里结构体的内存分配:    基本原则是这个变量当前的地址要能被自己这个类型的大小整除

 

errno是一个全局变量,可以保存程序在运行中的错误代码和对应错误信息。程序运行时,errno会被设置为0,出现错误时会被设为其他值。perror是一个函数,大致相当于打印错误信息,它的参数就是message。

rewind函数:文件操作相关,作用是让文件指针回到文件开头,以便重新读取,或写入。

fflush函数:文件操作相关,刷新stream的缓冲区,确保缓冲区内容都写入了文件或显示在屏幕。

 

附加题要的find操作:这个find的功能是找出所有同时满足名字和Email的数据库表项。

void Database_find(struct Connection *conn,const char *name,const char *email)
{
     int i=0;
     struct Database *db=conn->db;
     for(i=0;i<MAX_ROWS;i++)
     {
         if(db->rows[i]->set)
         {
             if( !strcmp(name,db->rows[i)->name) &&
                     !strcmp(name,db->rows[i)->name)) 
             {
                    struct Address *cur = &db->rows[i];
                    Address_print(cur);
             }
         }
         else
         {
             die("Cannot find target name&email");
         }
     }
    
}  //按照输入的名字或邮箱进行搜索,
//只有名字和邮箱二者都匹配才会提示存在,否则即报错 
//这里是基于原版数据库写的 
//strcmp(const char*s1,const chat *s2)  返回0才表示二者相等 

用脚本做自动化测试:

#!/bin/bash

echo "Compiling ex17.c..."
make ex17

echo "Creating database file db.dat..."
./ex17 db.dat c

echo "Storing users in db.dat..."
./ex17 db.dat s 1 zed zed@zedshaw.com
./ex17 db.dat s 2 frank frank@zedshaw.com
./ex17 db.dat s 3 joe joe@zedshaw.com

echo "Listing users in db.dat..."
./ex17 db.dat l

echo "Deleting user 3 in db.dat..."
./ex17 db.dat d 3

echo "Listing users in db.dat again..."
./ex17 db.dat l

echo "Getting user 2 in db.dat..."
./ex17 db.dat g 2

 

--------------------练习18-------------

函数指针的基本格式:

int (*POINTER_NAME)(int a, int b)

int (*p) (int, int); // 定义一个函数指针变量    

这样定义出来的p就是一个指针变量,可以指向一个同样有 两个int参数,返回值为int的函数。

让p=compare,这样以来p(10,20)和compare(10,20)效果就一样了。

 

typedef这个关键字的功能不只是起别名,它还可以定义新的类型名。

typedef int (*compare_cb) (int, int)   这样就定义了一个新类型名,叫compare_cb,就和int 、char一样。注意,typedef后面的int不是修饰typedef的,它是完整的函数指针定义的一部分,表示返回值是int。

这样定义新类型以后,用法就和别的类型一样:

compare_cb p2=compare  声明了一个函数指针变量p2,指向了compare函数。

 

练习18 的例子就是一个函数调用其他函数。为什么不直接在函数里写明要调用哪个函数?因为用函数指针可以放入任何输入输出匹配的函数。

从某些用法上来说,函数指针是不是也是间接实现多态的一种方法?

 

练习18的例子,在test_sorted里调用冒泡排序,冒泡排序又分别调用了三种sort。前两种分别对应升序和降序,根据sort的结果来冒泡。

 

附加题:

如果把NULL加进去,被当作0来进行排序了,程序没有崩溃。用valgrind,并没有发现报错,程序正常地执行了。

我尝试加入了一个有三个int参数的假排序函数fake,编译器会提示expected 'compare_cb'{aka 'int(*)(int,int)'} but argument is of type 'int (*)(int,int,int)  

posted @ 2024-01-17 17:46  namezhyp  阅读(11)  评论(0编辑  收藏  举报