题目: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);
}