C++学习之路(七),C++primer plus 第八章 函数探幽 - 编程练习

 

 8.8 编程练习

  1. 编写通常接受一个参数(字符串的地址),并打印该字符串的函数。然而,如果提供了第二个参数(int类型),且该参数不为 0,则该函数打印字符串的次数将为该函数被调用的次数(注意,字符串的打印次数不等于第二个参数的值,而等于函数被调用的次数)。是的,这是一个非常可笑的函数,但它让你能够使用本章的一些技术。在一个简单的程序中使用该函数,以演示该函数是如何工作的。

#include <iostream>
using namespace std;

char ch[ 20 ] = "oH~mY gOd!";

void display(char * ch, int n = 0);

int main()
{
    display(ch);
    display(ch, 5);
    display(ch);
    display(ch, 9);
    display(ch, 14);

    return 0;
}

void display(char * ch, int n)
{
    static int times =0;
    times ++;
    cout << times << endl;

    if (n == 0)
        cout << ch << endl;
    esle
    {
         for (int i = 0; i < times; i ++)
               cout << ch << end;   
    }
    cout << endl;
}
    

程序运行如下:,基本上完成了题目要求,但是这句话还是没有好好的理解清楚

 2. CandyBar 结构包含 3 个成员。第一个成员存储 candy bar 的品牌名称;第二个成员存储 candy bar 的重量(可能有小数);第三个成员存储(candy bar的热量(整数)。请编写一个程序,它使用一个这样的函数,即将 CandyBar 的引用、char指针、double 和 int 作为参数,并用最后 3 个值设置相应的成员。最后 3 个参数的默认值分别为“Millennium Munch”、2.85 和 350。另外,该程序还包含一个以 CandyBar 的引用参数,并显示结构内容的函数。请尽可能使用 const。

 

#include <iostream>
using namespace std;

struct CandyBar
{
    char name[ 20 ];
    double height;
    int cal;

};

void set_candybar(CandyBar & cb, char * name = "Millennium Munch", double h = 2.85, int c = 350);
void show_candybar(const CandyBar & cb);  // 这里和对应的下面加不加 const 运行结果是一样的,不知道区别在哪里

int main()
{
    CandyBar cb;
    set_candybar(cb);
    show_candybar(cb);


    return 0;
}

void set_candybar(CandyBar & cb, char * name, double h, int c)
{
    for (int i = 0; i < 20; i ++)
    {
    cb.name[ i ] = name[ i ];
    }
    cb.height = h;
    cb.cal = c;
}

void show_candybar(const CandyBar & cb)
{
    cout << "Name: " << cb.name << endl;
    cout << "Height: " << cb.height << endl;
    cout << "Calorie: " << cb.cal << endl;
}

代码运行结果:

 

 

 3.  编写一个函数,它接受一个指向 String 对象的引用作为参数,并将该 string 对象的内容转换为大写,此可使用表 6.4 描述的函数 toupper()。然后编写一个程序,它通过使用一个循环让你能够用不同的输入来测试这个函数,该程序运行情况如下:

Enter a string (q to quit): go away
GO AWAY
Next string (q to quit): good grief!
GOOD GRIEF!
Next string (q to quit): q
Bye.

先编写一个内联函数来实际此功能:

#include <iostream>
#include <string>
using namespace std;

string name;

int main()
{
  cout << "Enter a string (q to quit): ";
  getline(cin, name);
  while(name != "q" && name != "Q")
  {
  for(int i = 0; i < name.size(); i ++)
    name[ i ] = toupper(name[ i ]);
    cout << name << endl;
  cout << "Next string (q to quit)" ;
  getline(cin, name);
  }
  cout << "Bye. " << endl;

return 0;
}

上述代码运行为:

 

 另一个版本:

#include <iostream>
#include <cstring>
#include <string>
using namespace std;

char name[ 20 ];

int main()
{
    cout << "Enter a string (q to quit): ";
    cin >> name;
    while(strcmp(name, "q") && strcmp(name, "Q"))
    {
        for (int i = 0; i < 20; i ++)
            name[ i ] = toupper(name[ i ]);
            cout << name << endl;
        
        cout << "Next string (q to quit): ";
        cin >> name;
    }
    cout << "Bye. " << endl;

    return 0;
}

代码运行情况:

 

 现在来开始实现题目的要求,string 版本:

#include <iostream>
#include <string>
using namespace std;

string name;

void toup(string & str);

int main()
{
  cout << "Enter a string (q to quit): ";
  getline(cin, name);
  while(str != "q" && str != "Q")
  {
    toup(name);

    cout << "Next string (q to quit): ";
    getline(cin, str);
  }
  cout << "Bye." << endl;
return 0; } void toup(string & str) {   for (int i = 0; str[ i ]; i ++)
    str[ i ] = toupper(str[ i ])
}

上述代码运行如下:

 

 

 char 版本:

#include <iostream>

using namespace std;

char name[ 20 ];

void toup(char * name);

int main()
{
  cout << "Enter a string (q to quit);
  cin.getline(name, 20);  // cin >> name; 这里用这个不能读取一整行
  while(strcmp(name, "q") && strcmp(name, "Q"))
  {
    toup(name);
    cout << "Next string (q to quit): ";
    cin.getline(name, 20);  // 这里还行加一句
    cin >> name;
  }
  cout << "Bye. " << endl;
return 0; } void toup(char *name) {   for (int i = 0; name[ i ]; i ++)
    name[ i ] = toupper(name[ i ];
  cout << name;
}

代码运行如下:

 

 

 4. 下面是一个程序框架:

 

#include <iostream>
#include <cstring>    // for strlen(), strcpy()
using namespace std;
struct stringy {
    char * str;            // points to a string
    int ct;                   // length of string (not counting '\0')
};

//  prototypes for set(), show(), and show() go here
int main()
{  
    stringy beany:
    char testing[ ] = "Reality isn't what it used to be.";

    set(beany, testing);    // first argument is a reference,
                            // allocates space to hole copy of testing, 
                            // new block, copies testing to new block,
                            // and sets ct member of beany
    show(beany);          // prints member string once
    show(beany, 2);       // prints member string twice
    testing[ 0 ] = 'D';
    testing[ 1 ] = 'u';
    show(testing);        // prints testing string once
    show(testing, 3);    // prints testing string thrice
    show("Done!");
    
    return 0;
}

  请提供其中描述的函数和原型,从而完成该程序。注意,应有两个 show()函数,每个都使用默认参数。请尽可能使用 const 参数。set()使用 new 分配足够的空间来存储指定的字符串,这里使用的技术与设计和实现类时使用的相似。(可能还必须修改头文件的名称,删除 using 编译指令,这取决于所用的编译器。)

#include <iostream>
#include <cstring>     // for strlen(), strcpy()
using namespace std;

struct stringy
{
    char * str;        // points to string
    char ct;            // length of string (not counting '\0')
};

// prototypes for set(), show(), and show() go here

void set(stringy &, char *);
void show(stringy &, int c = 1);
void show(char *, int c = 1);

int main()
{
    stringy beany;
    char testing[ ] = "Reality isn't what it used to be.";

    set(beany, testing);    // first argument is a reference,
                            // allocates space to hole copy of testing,
                            // sets str member of beany to point to thd
                            // new block, copies testing to new block,
                            // and sets ct member of beany
    show(beany);            // prints member string once
    show(beany, 2);            // prints member string twice
    testing[ 0 ] = 'D';
    testing[ 1 ] = 'u';
    show(testing);            // prints testing string once
    show(testing, 3);        // prints testing string thrice
    show("Done!"); 

    return 0;
}

void set(stringy & s, char * ch)
{
  s.ct = strlen(ch) + 1;
  s.str = new char[s.ct + 1];
  
  strcpy(s.str, ch);
}

void show(stringy & s, int c = 1)
{
  for (int i = 0; i < c; i ++)
    cout << "str = " << s.str << " ct = " << s.ct << endl;
}

void show(char * s, int c)
{
  fot int i = 0; i < c; i ++)
    cout << "str = " << s.str << endl;
}

 5. 编写模板函数 max5(),它将一个包含 5 个 T 类型元素的数组作为参数,并返回数组中最大的元素(由于长度固定,因此可以循环中使用硬编码,而不必通过参数来传递)。在一个程序中使用该函数,将 T 替换为一个包含 5 个 int 值的数组和一个包含 5 个 double 值的数组,以测试该函数。

// 1.先编写一个返回最大值的代码:
#include <iostream>
#include <time.h>
#include <stdlib.h>            // 有的编译器需要加这个
using namespace std;

int main()
{
    int s[ 5 ], temp;
    srand(time(0));
//    cout << "Enter five number: ";
    for (int i = 0; i < 5; i ++)
    {
//        cin >> s[ i ];
        s[ i ] = rand() % 100;    // 随机1 - 99 数
        cout << s[ i ] << " ";
    }
    cout << endl;
    temp = s[ 0 ];
    
    for (int j = 1; j < 5; j ++)
    {
        if (temp > s[ j ])
            continue;
        else
            temp = s[ j ];
    }
    cout << "其中最大的数为: " << temp << endl;

    return 0;
}

上述是使用随机数中找出最大值的代码,运行结果

 

 

// 2.再使用函数模板返回 5 个数中最大值
#include <iostream>
#include <time.h>
#include <stdlib.h>            // 有的编译器需要加这个
using namespace std;

template <typename T>
void max5(T * s);


int main()
{    
    int ari[ 5 ];
    double ard[ 5 ];
    cout << "输入5个整数: ";
    for (int i = 0; i < 5; i ++)
    {
        cin >> ari[ i ];
        cout << ari[ i ] << "\t" ;
    }
    cout << endl;
    max5(ari);

    cout << "输入5个小数: ";
    for (int j = 0; j < 5; j ++)
    {
        cin >> ard[ j ];
        cout << ard[ j ] << "\t" ;
    }
    cout << endl;
    max5(ard);    

    return 0;
}


template <typename T>
void max5(T s[])
{
    T temp;

    temp = s[ 0 ];
    
    for (int j = 1; j < 5; j ++)
    {
        if (temp > s[ j ])
            continue;
        else
            temp = s[ j ];
    }
    cout << "其中最大的数为: " << temp << endl;
}

这是使用模板来找出最大值,代码运行如下

  

  6.编写模板函数 maxn(),它将由一个 T 类型元素组成的数组和一个表示数组元素数目的整数作为参数,并返回数组中最大的元素。在程序对它进行测试,该程序使用一个包含 6 个 int 元素的数组和一个包含 4 个 doulbe 元素的数组来调用该函数。程序还包含一个具体化,它将 char 指针数组和数组中的指针数量作为参数,并返回最长的字符串的地址。如果有多个这样的字符串,则返回其中第一个字符串的地址。使用由 5 个字符串指针组成的数组来测试该具体化。

  先编写一段代码,手动输入元素数目和元素数,然后输出最大值,不过印象中,数组的元素数目必须是一个常量来着,普通的输入一个元素数目应该不能编译,不管了,先试下:

#include <iostream>
using namespace std;

void maxn(int *s, int);

int main()
{
    int n;
    cout << "输入数组元素数目: ";
    cin >> n;
    int ari[ n ];    // 错误提示:expected constant expression(应为常量表达式)
    cout << "输入 " << n << "数组元素数: ";
    for (int i = 0; i < n; i ++)
        cout << ari[ i ] << "\t";  // ① 这里缺了 cin >> ari[ i ];


    return 0;
}

void maxn(int * s, int n)
{
    int tmp = ari[ 0 ];      // ② 这里不能用 ari 这个数组名,这个数组名只存在于上面 main 函数中,而这里只能用参数名 s, 
    for (int i = 1; i < n; i ++)
    {
        if tmp > ari[ i ];    // ③ 这里是个灰常低级的错误
            continue;
        else
            tmp = ari[ i ];  
    }
    cout << "最大的数是: " << tmp;
}

  果不基然;以上代码不能编译成功,这里 int ari[ n ];  提示expected constant expression(应为常量表达式),后来在 网上查了下,一定要有和int * ari = new int[ n ];来代码前面那段代码;另外,上述代码还犯了几处错误:

  ① 这里缺了 cin >> ari[ i ];

  ② 这里不能用 ari 这个数组名,这个数组名只存在于上面 main 函数中,而这里只能用参数名 s, 

  ③ 这里是个灰常低级的错误,

  全部错误改正后代码运行结果如下:

 

 

  在网上看到输入5个数中最大的代码有一段是这样的

for (int i = 1; i < 5 ;i ++)
    if (a[ i ] > temp)temp = a[ i ];
return temp;

 

  我就纳闷了, (a[ i ] > temp)temp = a[ i ]; 这句话是个会什么操作?数学中有这样操作(2 + 3) X 5, 可以把中间的乘号去掉,简写成(2 + 3)5,我还想往上面的, (a[ i ] > temp)temp = a[ i ] 按数学上写法,a[ i ] * temp > temp * temp = a[ i ]; 这是几个意思,这么一写就更不懂了,于是在网上查 (a[ i ] > temp)temp 是什么意思,查不出来......,就在我想来想去不知道什么意思的时候,我在百度查 “5个数中最大值 C++”,的时候看到一段代码是这样写的,

for(int i=0;i<5;i++){
    int temp;
    if(max<a[i])
        max=a[i];
        if(min>a[i])
        min=a[i];
} 
        

  看到这里我终于明白了,网上多次写到 if (a[ i ] > temp)temp = a[ i ]; 的代码完全是有误导的嫌疑,不知道是输写习惯还是格式问题,好几个代码都好像是抄一个人写的,不说这个了。

 

 

   最基本的第一步是完成了,然后是完成第二步题目要求的

#include<iostream>
#include<cstring>
using namespace std;

template<typename T>
T maxn(T ar[], int n);

template<> const char * maxn(const char * ar[], int n);

int main()
{
  int ari[ 6 ] = {1, 2, 6, 9, 8, 3};
  double ard[ 5 ] = {1.1, 2.2, 6.6, 9.9, 8.8};
  const char * arr[ 4 ] = {"a Aa aAa", "BBBBBbb bBBbbbb bbbbbbbb.", "Ccccc cCc ccccc..", "dd...DD"};

  cout << "The max integer of array is:" << maxn(ari, 6) <<endl;
  cout << "The max double of array is:" << maxn(ard, 5) <<endl;
  cout << "The max string of array is:" << maxn(arr, 4) <<endl;

  return 0;
}

template<typename T>
T maxn(T ar[], int n)
{
  T max = ar[ 0 ];
  for (int i = 0; i < n; i ++)
    if (max < ar[ i ])
    max = ar[ i ];

  return max;
}

template<> const char * maxn(const char * ar[], int n)
{
  const char * max = ar[ 0 ];
  for (int i = 0; i < n; i ++)
    if (strlen(max) < strlen(ar[ i ]))
    max = ar[ i ];

  return max;

}

代码运行情况如下

 

 

7. 修改程序清单 8.14,使其使用两个名为 SumArray() 的模板函数来返回数组元素的总和,而不是显示数组的内容。程序应显示 thing 的总和以及所有 debt 的总和。

程序清单 8.14 有两个用来显示数组内容的模板定义。第一个定义(模板A)假设作为参数传递的数组中包含了要显示的数据;第二个定义(模板B)假设数组元素为指针,指向要显示的数据。

程序清单 8.14 temptempover.cpp

//tempover.cpp -- template overloading
  #include <iostream>
  using namespace std;

  template <typename T>            // template A
  void SHowArray(T arr[], int n);

  template<typename T>            // template B
  void ShowArray(T * arr[], int n);

  struct debts
  {
        char name[ 50 ];
        double amount;
  };

  int main()
  {
        int things[ 6 ] = {13, 31, 103, 301, 310, 130};
        struct debts mr_E[ 3 ] = {
            {"Ima Wolfe", 2400.0},
            {"Ura Foxe", 1300.0},
            {"Iby Stout", 1800.0}
        };
        double * pd[ 3 ];

  // set pointers to the amount members of the structures in mr_E
        for (int i = 0; i < 3; i ++)
            pd[ i ] = &mr_E[ i ].amount;


        cout << "Listing Mr. E's counts of things: \n";
  // things is an array of int
        ShowArray(things, 6);    // usestemplate A
        cout << "Listing Mr. E's debts: \n";
  // pd is an array of pointers to double
        ShowArray(pd, 3);        // uses templalte B(more specialized)

        return 0;
  }

  template<typename T>
  void ShowArray(T arr[], int n)
  {
        cout << "template A\n";
        for (int i = 0; i < n; i ++)
            cout << arr[ i ] << ' ';
        cout << endl;
  }

  template <typename T>
  void ShowArray(T *arr[], int n)
  {
        cout << "template B\n"
        for (int i = 0; i < n; i ++)
            cout << *arr[ i ] << ' ';
        cout << endl;
  }

修改为显示数组元素的和的代码:

#include <iostream>
using namespace std;

template <typename T>        // template A
void SumArray(T arr[], int n);

template<typename T>            // template B
void SumArray(T * arr[], int n);

struct debts
{
    char name[ 50 ];
    double amount;
};

int main()
{
    int things[ 6 ] = {13, 31, 103, 301, 310, 130};
    struct debts mr_E[ 3 ] = {
        {"Ima Wolfe", 2400.0},
        {"Ura Foxe", 1300.0},
        {"Iby Stout", 1800.0}
    };
    double * pd[ 3 ];

// set pointers to the amount members of the structures in mr_E
    for (int i = 0; i < 3; i ++)
        pd[ i ] = &mr_E[ i ].amount;


    cout << "Listing Mr. E's counts of things: \n";
// things is an array of int
    SumArray(things, 6);    // uses template A
    cout << "Listing Mr. E's debts:\n";
// pd is an array of pointers to double
    SumArray<double>(pd, 3);        // uses templalte B(more specialized)

    return 0;
}

template<typename T>
void SumArray(T arr[], int n)
{
    int sumt = 0;
    cout << "template A\n";
    for (int i = 0; i < n; i ++)
        sumt += arr[ i ];
        cout << sumt << ' ';
    cout << endl;
}

template <typename T>
void SumArray(T *arr[], int n)
{
    double sumd = 0.0;
    cout << "template B\n";
    for (int i = 0; i < n; i ++)
        sumd += * arr[ i ];
        cout << sumd << ' ';
    cout << endl;
}

代码运行如下:

 

 我还在想应该不会这么简单吧,网上去查下,一查还真是这样,唯一的一个难点应该是 sumd += * arr[ i ]; 这个代码中,当我首次用 sumd += arr[ i ],错误提示为

 

 第一次将定义  double sumd = 0 ;改为 double * sum = 0;错误更多,于是就改了  sumd += * arr[ i ]; 这个了;

 

 好了,反观这一章,从19年到10月份,正文到复习到练习,跨越一年,之间经历了历史上一次重大的世界新冠病毒,虽然到目前为止还没有攻克,但这一章经历的时间太长了,主要原因还是在于自身,自制能力差,有点不愿意动脑子,不过还好,也算是勉勉强强的学习完了这一章,好多的东西也不大懂,希望自己能够坚持学习这一本书,看看900+页,看了300+而,1/3了,真是有些不简单,坚持坚持再坚持,准备下一章……

posted @ 2020-08-09 11:10  人五人六  阅读(315)  评论(0)    收藏  举报