C++ primer plus习题集及解析第九章(内存模型和名字空间)

题目:9.1

下面是一个头文件:

const int Len = 40;
struct golf {
    char fullname[Len];
    int handicap;
};
void handicap(golf & g, int hc);
void showgolf(const golf & g);
int setgolf(golf & g);

 注意到 setgolf() 被重载,可以这样使用其第一个版本:(有参构造)

golf ann;
setgolf(ann, "Ann Birdfree", 24);

上述函数调用提供了存储在ann结构中的信息。可以这样使用其第二个版本:(拷贝构造)

golf andy;
setgolf(andy);

上述函数将提示用户输入姓名和等级,并将它们存储在andy结构 中。这个函数可以(但是不一定必须)在内部使用第一个版本。 根据这个头文件,创建一个多文件程序。其中的一个文件名为 golf.cpp,它提供了与头文件中的原型匹配的函数定义;另一个文件应 包含main( ),并演示原型化函数的所有特性。例如,包含一个让用户输 入的循环,并使用输入的数据来填充一个由golf结构组成的数组,数组 被填满或用户将高尔夫选手的姓名设置为空字符串时,循环将结束。 main( )函数只使用头文件中原型化的函数来访问golf结构。 

代码: 

//golf.h
#include<iostream>
#include<string>
const int Len = 40;
struct golf {
    char fullname[Len];
    int handicap;
};
//设置等级
void handicap(golf& g, int hc);

//展示信息
void showgolf(const golf& g);

//设置信息,方式1,拷贝构造
int setgolf(golf& g);

//设置信息 方式2,有参构造
void setgolf(golf &object,const char* name, int hc);
//golf.cpp
#include "golf.h"

//设置等级
void handicap(golf& g, int hc)
{
	g.handicap = hc;
}

//展示信息
void showgolf(const golf& g)
{
	std::cout <<"名字:"<< g.fullname << std::endl;
	std::cout << "等级:" << g.handicap << std::endl;
}

//设置信息,方式1,拷贝构造
int setgolf(golf& g)
{
	//手动输入
	std::string name;
	
	std::cout << "请输入选手的姓名:";
	std::cin >> name;
	std::cout << std::endl;
	int hc;
	std::cout << "请输入选手的等级:";
	std::cin >> hc;
	int len = name.length();
	strcpy_s(g.fullname, len + 1, name.c_str());
	g.handicap = hc;

	return 1;
}

//设置信息 方式2,有参构造
void setgolf(golf& object, const char* name, int hc)
{
	int len = sizeof(name) / sizeof(name[0]);
	strcpy_s(object.fullname, len + 1, name);
	object.handicap = hc;
}

 问题1:void showgolf(const golf& g)为什么使用const golf&g

 使用const golf&g是为了确保在showgolf函数中不会意外修改golf对象的内容。const关键字表示g是一个常量引用,即在函数中无法修改g的值,只能读取它的内容。这有助于提高代码的可读性和安全性,同时避免意外的数据修改。

使用引用可以避免在函数调用时进行对象的复制,提高程序的效率。如果不使用引用,而是直接传递golf对象作为参数,则会触发对象的拷贝构造函数,将整个对象复制一份传递给函数。而使用引用只是传递对象的地址,不会触发拷贝构造函数,避免了不必要的开销。因此,使用引用可以在保证数据不被修改的前提下提高程序的性能。

题目:9.2 

 修改程序清单9.9:用string对象代替字符数组。这样,该程序将 不再需要检查输入的字符串是否过长,同时可以将输入字符串同字符 串“”进行比较,以判断是否为空行。

9.9清单如下:(本质就是统计字符)

#include<iostream>
using namespace std;

const int ArSize = 10;

void strcount(const char* str);


int main()
{
	char input[ArSize];
	char next;
	cout << "输入一行:\n";
	cin.get(input, ArSize);

	while (cin)
	{
		cin.get(next);
		while (next != '\n')
		{
			cin.get(next);
		}

		strcount(input);
		cout << "输入下一行(输入空行退出):\n";
		cin.get(input, ArSize);
	}

	cout << "Bye\n";
	
	system("pause");
	return 0;
}

void strcount(const char* str)
{
	static int total = 0;//一直持续性的增加,程序不关闭就不释放
	int count = 0;

	cout << "\"" << str << "\" 包含字符数为";
	while (*str++)
	{
		count++;
	}
	total += count;
	cout << count << endl;
	cout << "总共的字符数为:" << total << endl;
}

代码: 

void strcount(const string str)
{
    static int total = 0;
    int count = 0;

    cout << "\"" << str.c_str() << "\" contains ";
    while (str[count])
    {
        count++;
    }
    total += count;
    cout << count << " characters\n";
    cout << total << " characters total\n";
}
void main()
{
    string input;

    cout << "输入一行:\n";
    getline(cin, input);
    while (cin)
    {
        strcount(input);
        cout << "输入下一行(输入空行退出):\n";
        getline(cin, input);
        if (input == "")
        {
            break;
        }
    }

    cout << "Bye\n";
    return;
}

问题1:while(cin)如何理解?

 在C++中,while(cin)是一种常见的用法,它利用了输入流对象cin的隐式转换为布尔值的特性。在C++中,输入流对象cin会在发生错误或到达文件末尾时返回false,否则返回true。因此,while(cin)的含义是在输入流对象cin有效时(即没有发生错误且没有到达文件末尾),就会一直执行循环。

这种用法通常用于循环读取用户的输入,直到用户输入特定的结束标志(例如空行)。在这种情况下,while(cin)可以作为一个方便的循环条件,让程序持续接收用户输入。

问题2:getline()用法 

 getline 是 C++ 中用于从输入流中读取一行数据的函数。它的用法如下: 

#include <iostream>
#include <string>

int main() {
    std::string line;
    
    // 从标准输入流中读取一行数据
    std::getline(std::cin, line);
    
    // 打印读取的数据
    std::cout << "You entered: " << line << std::endl;
    
    return 0;
}

题目:9.3

下面是一个结构声明:

struct chaff {
    char dross[20];
    int slag;
};

编写一个程序,使用定位new运算符将一个包含两个这种结构的数 组放在一个缓冲区中。然后,给结构的成员赋值(对于char数组,使用函数 strcpy( )),并使用一个循环来显示内容。一种方法是像程序清单 9.10那样将一个静态数组用作缓冲区;另一种方法是使用常规new运算 符来分配缓冲区。 

 代码:

struct chaff {
    char dross[20];
    int slag;
};
char buffer[1024];
void Func()
{
    chaff* pcha = new (buffer) chaff[2];
    char* pc = new char[1024];
    chaff* pcha2 = new (pc) chaff[2];
    char dross[20] = { 0 };
    int slag = 0;

    for (int i = 0; i < 2; i++)
    {
        cout << "Enter dross of " << i << " chaff: " << endl;
        cin.getline(dross, 20);
        cout << "Enter slag of " << i << " chaff: " << endl;
        cin >> slag;
        cin.get();

        strcpy(pcha[i].dross, dross);
        strcpy(pcha2[i].dross, dross);
        pcha[i].slag = pcha2[i].slag = slag;
    }

    for (int i = 0; i < 2; i++)
    {
        cout << "staff :" << (i + 1) << ":" << endl;
        cout << "pcha.dross: " << pcha[i].dross << ". pcha.slag: " << pcha[i].slag << endl;
        cout << "pcha2.dross: " << pcha2[i].dross << ". pcha2.slag: " << pcha2[i].slag << endl;
    }

    cout << "address of buffer: " << (void*)buffer << endl;
    cout << "address of pcha: " << pcha << ". address of pcha[0]: " << &pcha[0] << ". address of pcha[1]: " << &pcha[1] << endl;
    cout << "address of pc: " << (void*)pc << endl;
    cout << "address of pcha2:" << pcha2 << ". address of pcha2[0]: " << &pcha2[0] << ". address of pcha2[1]: " << &pcha2[1] << endl;;

    delete[] pc;
}

问题1:chaff* pcha = new (buffer) chaff[2]; char* pc = new char[1024]; chaff* pcha2 = new (pc) chaff[2];用法分析

 这几种用法涉及动态内存分配和放置new操作符。

  1.chaff* pcha = new (buffer) chaff[2];

在这行代码中,使用了放置new操作符,指定将新分配的内存存储在buffer指向的位置。这意味着buffer指针指向的内存将被用于存储两个chaff对象的数组。这种技术称为放置new,并允许程序员控制对象的内存分配。在这种情况下,pcha指针将指向buffer指针指向的内存,而不是堆上的内存。这种方法通常用于需要精确控制对象位置或需要避免堆内存碎片化的情况。

  2.char* pc = new char[1024];

这行代码是标准的动态内存分配,使用new操作符在堆上分配了一个包含1024个char元素的数组。返回的指针pc指向这个分配的内存空间。这种情况下,动态内存由操作系统管理,程序员不需要担心具体的内存地址或管理。

  3.chaff* pcha2 = new (pc) chaff[2];

这行代码与第一个用法类似,不同之处在于这次是在之前通过new char[1024]分配的pc指向的内存中创建两个chaff对象。这再次展示了放置new操作符的用法,允许将对象存储在指定的内存位置。在这种情况下,pcha2指针将指向pc指针指向的内存,这个内存现在包含了两个chaff对象。

这些用法展示了动态内存分配和放置new操作符的不同方式,每种用法适合不同的情况和需求。通过仔细控制内存分配,程序员可以提高内存使用效率并避免一些常见的问题。

题目:9.4 

请基于下面这个名称空间编写一个由3个文件组成的程序:

namespace SAIGES {
    const int QUARTERS = 4;
    struct Sales {
        double sales[QUARTERS];
        double average;
        double max;
        double min;
    };
    void setSales(Sales &s, const double ar[], int n);
    void setSales(Sales &s);
    void showSales(const Sales &s);
}

 第一个文件是一个头文件,其中包含名称空间; 第二个文件是一个 源代码文件,它对这个名称空间进行扩展,以提供这三个函数的定义; 第三个文件声明两个Sales对象,并使用 setSales() 的交互式版本为一个 结构提供值,然后使用 setSales() 的非交互式版本为另一个结构提供值。 另外它还使用 showSales() 来显示这两个结构的内容。

代码: 

#pragma once
#include<iostream>
namespace SAIGES {
    const int QUARTERS = 4;
    struct Sales {
        double sales[QUARTERS];
        double average;
        double max;
        double min;
    };
    void setSales(Sales& s, const double ar[], int n);
    void setSales(Sales& s);
    void showSales(const Sales& s);
}
#include "myself.h"

void SAIGES::setSales(Sales& s, const double ar[], int n)
{
	double min = ar[0];
	double max = ar[0];
	double average = 0;
	for (int i = 0; i < n; i++)
	{
		s.sales[i] = ar[i];
		if (min > ar[i])
		{
			min = ar[i];
		}
		if (max < ar[i])
		{
			max = ar[i];
		}
		average += ar[i];

	}
	average = average / n;

	s.max = max;
	s.min = min;
	s.average = average;



}

void SAIGES::setSales(Sales& s)
{
	//手动输入
	double total = 0.0;
	double max = 0.0;
	double min = 0.0;
	double input = 0.0;

	std::cout << "Enter 4 double number; " << std::endl;
	for (size_t i = 0; i < QUARTERS; i++)
	{
		std::cin >> input;
		if (i == 0)
		{
			max = input;
			min = input;
		}
		if (min > input)
		{
			min = input;
		}
		if (max < input)
		{
			max = input;
		}
		total += input;
		s.sales[i] = input;
	}
	s.average = total / QUARTERS;
	s.max = max;
	s.min = min;


}

void SAIGES::showSales(const Sales& s)
{
	for (int i = 0; i < QUARTERS; i++)
	{
		std::cout << s.sales[i] << " ";
	}
	std::cout << std::endl;

	std::cout << "s.max=" << s.max << std::endl;
	std::cout << "s.min=" << s.min << std::endl;
	std::cout << "s.average=" << s.average << std::endl;

}
void Func()
{
	SAIGES::Sales a;
	const double ar[] = { 5.00,6.00,7.00,8.00 };
	SAIGES::setSales(a,ar, 4);
	SAIGES::showSales(a);
}

 

  • 22
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++ Primer习题集(第五版) , 带目录完整版。 --------------------------------------------------------------------------- 目录 第1章............................................................ 1 练习1.1 练 习1.25 第2 章变量和基本类型................................................. 12 练习2.1 练 习2.42 第3 章字符串、向量和数组..............................................37 练习3.1 练 习3.45 第4 章表达式......................................................... 80 练习4.1 练 习4.38 第5 章语句........................................................... 99 练习5.1 练 习5.25 第6 章函数.......................................................... 120 练习6.1 练 习6.56 m m m ...................................................................... 152 练习7.1 练 习7.58 第8 章1 0库..........................................................183 练习8.1 练 习8.14 第9 章顺序容器...................................................... 193 练习9.1 练 习9.52 第10章泛型算法..................................................... 234 练习10.1 练 习10.42 目录 ◄ v 第11章关联容器..................................................... 273 练习11.1 练 习11.38 第12章动态内存..................................................... 297 练习12.1 练 习12.33 第13章拷贝控制..................................................... 331 练习13.1 练 习13.58 第14章重载运算与类型转换............................................368 练习14.1 练 习14.53 第15章面向对象程序设计..............................................399 练习15.1 练 习15.42 第16章模板与泛型编程............................................... 424 练习16.1 练 习16.67 第17章标准库特殊设施............................................... 458 练习17.1 练 习17.39 第18章用于大型程序的工具............................................483 练习18.1 练 习18.30 第19章特殊工具与技术............................................... 502 练习19.1 练 习19.26

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值