4-1
在标准C库中,函数puts()能显示字符数组到控制台上(所以能写puts(“hello”))。试写一个C语言程序,这个程序使用puts(),但不包含<stdio.h>,也不声明这个函数。用C编译器编译这个程序。(有些C++编译器并不与它们的C编译器分开;在这种情况下,可能需要使用一个强制C编译的命令行标记。)然后再用C++编译器对它编译,注意它们之间的区别。 CPP文件:
int main() {
puts("hello");
}
我用g++编译,只是出现一个警告:
4-1.c: In function 'main':
4-1.c:2:2: warning: implicit declaration of function 'puts' [-Wimplicit-function-declaration]
2 | puts("hello");
| ^~~~
按道理,应该给出错误提示才对,不知道怎么回事?按照作者的文章里的讲解,这时候应该是编译错误才对,因为使用了未声明的函数。不过这个不重要,我们知道就好了。
4-2
创建一个struct声明,它有单个成员函数,然后为这个成员函数创建定义。创建这个新数据类型的对象,再调用这个成员函数。
#include <iostream>
using namespace std;
struct MyStruct {
void f();
};
void MyStruct::f() {
cout << "void MyStruct::f() 被调用" << endl;
}
int main() {
MyStruct myStruct;
myStruct.f();
}
输出:
void MyStruct::f() 被调用
4-3
改变练习2的答案,使得struct在合适的“防护”头文件中声明,同时,它的定义在一个cpp文件中,main()在另一个文件中。 MyStruct.h
#ifndef MYSTRUCT_H
#define MYSTRUCT_H
struct MyStruct {
void f();
};
#endif
MyStruct.cpp
#include "MyStruct.h"
#include <iostream>
using namespace std;
void MyStruct::f() {
cout << "void MyStruct::f() 被调用" << endl;
}
4-3.cpp
#include "MyStruct.h"
int main() {
MyStruct myStruct;
myStruct.f();
}
输出:
void MyStruct::f() 被调用
4-4
创建一个struct,它有一个int数据成员,再创建两个全局函数,每个函数都接受一个指向该struct的指针。第一个函数有第二个int参数,并设置这个struct的int为它的参数值,第二个函数显示来自这个struct的int。测试这两个函数。
#include <iostream>
using namespace std;
struct S {
int a;
};
void setS(S *ps, int a) {
ps->a = a;
}
void display(S *ps) {
cout << ps->a << endl;
}
int main() {
S s;
setS(&s, 1);
display(&s);
}
4-5
重写练习4,将两个函数改为这个struct的成员函数,再次测试。
#include <iostream>
using namespace std;
struct S {
int a;
void set(int a);
void display();
};
void S::set(int a) {
this->a = a;
}
void S::display() {
cout << a << endl;
}
int main() {
S s;
s.set(1);
s.display();
}
4-6
创建一个类,它使用this关键字(冗余地)执行数据成员选择和成员函数调用。(this表示当前对象的地址)。
#include <iostream>
using namespace std;
struct S {
int a;
void set(int a);
void display();
};
void S::set(int a) {
this->a = a;
cout << "当前a为:";
this->display();
}
void S::display() {
cout << a << endl;
}
int main() {
S s;
s.set(1);
}
输出:
当前a为:1
4-7
让Stash存放double,存入25个double值,然后把它们显示到控制台上。
#include "CppLib.h"
#include <iostream>
using namespace std;
int main() {
Stash doubleStash;
doubleStash.initialize(sizeof(double));
double k = 1.0;
for(int i = 0; i < 10; i++, k+=0.1)
doubleStash.add(&k);
for(int j = 0; j < doubleStash.count(); j++)
cout << "doubleStash.fetch(" << j << ") = "
<< *(double*)doubleStash.fetch(j)
<< endl;
doubleStash.cleanup();
}
输出:
doubleStash.fetch(0) = 1
doubleStash.fetch(1) = 1.1
doubleStash.fetch(2) = 1.2
doubleStash.fetch(3) = 1.3
doubleStash.fetch(4) = 1.4
doubleStash.fetch(5) = 1.5
doubleStash.fetch(6) = 1.6
doubleStash.fetch(7) = 1.7
doubleStash.fetch(8) = 1.8
doubleStash.fetch(9) = 1.9
freeing storage
4-8
用Stack重写练习7。
#include "Stack.h"
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
Stack doubleStack;
doubleStack.initialize();
double d[10];
for (int i = 0; i < 10; i++) {
d[i] = i + 0.1;
doubleStack.push(&d[i]);
}
double *pd;
while((pd = (double*)doubleStack.pop()) != 0) {
cout << *pd << endl;
}
doubleStack.cleanup();
}
输出:
9.1
8.1
7.1
6.1
5.1
4.1
3.1
2.1
1.1
0.1
4-9
创建一个文件,包含以int为参数的函数f(),用<stdio.h>中的printf()函数将参数int的值显示到控制台上,即写printf("%d\n", i),这里i是希望显示的int。创建另外一个单独的文件,它包含main(),在该文件中声明f()接受float参数。从main()中调用f()。尝试用c++编译器编译和连接这个程序,看看会发生什么事情。再用c编译器编译和连接这个程序,观察运行时会发生什么事情。解释这里的行为。 f.cpp
#include <cstdio>
using namespace std;
void f(int i) {
printf("%d\n", i);
}
4-9.cpp
extern void f(float f);
int main() {
f(1.0);
}
C++编译连接出错:
$ make -f gcc.makefile 4-9
g++ -c 4-9.cpp
g++ -c f.cpp
g++ -o4-9 4-9.o f.o
D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: 4-9.o:4-9.cpp:(.text+0x16): undefined reference to `f(float)'
collect2.exe: error: ld returned 1 exit status
make: *** [gcc.makefile:91: 4-9] Error 1
C编译器应该不会出错,因为C编译器只看函数名是否匹配,不管参数。
4-10
发现如何由你的C编译器和C++编译器产生汇编语言。用C写一个函数和用C++写一个带有一个成员函数的struct。由每一个编译器产生汇编语言,找出由你的C函数和C++成员函数产生的函数名,这样,你能看到什么样的名字修饰出现在编译器内部。 4-10.c
void f(int i) {}
使用gcc -S 选项就可以编译成汇编语言:
gcc -S 4-10.c
生成汇编4-10.s:
.file "4-10.c"
.text
.globl f
.def f; .scl 2; .type 32; .endef
.seh_proc f
f:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
.seh_endprologue
movl %ecx, 16(%rbp)
nop
popq %rbp
ret
.seh_endproc
.ident "GCC: (Rev5, Built by MSYS2 project) 10.3.0"
函数名就是f ,如果用C++编译器呢?
.file "4-10.c"
.text
.globl _Z1fi
.def _Z1fi; .scl 2; .type 32; .endef
.seh_proc _Z1fi
_Z1fi:
.LFB0:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
.seh_endprologue
movl %ecx, 16(%rbp)
nop
popq %rbp
ret
.seh_endproc
.ident "GCC: (Rev5, Built by MSYS2 project) 10.3.0"
函数名是_Z1fi ,里面包含了参数信息,所以C++函数是可以重载的,因为它的名字会跟参数有关,而C则没有,我们现在再来看一下struct成员函数的名字: 4-10.cpp
struct S {
void f(int i);
};
void S::f(int i) {}
编译:
g++ -S 4-10.cpp
输出汇编:
.file "4-10.cpp"
.text
.align 2
.globl _ZN1S1fEi
.def _ZN1S1fEi; .scl 2; .type 32; .endef
.seh_proc _ZN1S1fEi
_ZN1S1fEi:
.LFB0:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
.seh_endprologue
movq %rcx, 16(%rbp)
movl %edx, 24(%rbp)
nop
popq %rbp
ret
.seh_endproc
.ident "GCC: (Rev5, Built by MSYS2 project) 10.3.0"
函数名为_ZN1S1fEi ,名字由结构体名字,函数名,以及参数组成。
4-11
写一个main()中有条件编译代码的程序,使得当预处理器的值被定义时打印一条消息,而不被定义时则打印另外一条消息。编译这一代码段在程序中有#define的试验代码,然后找出你的编译器在命令行上定义预处理器的方法,对它进行试验。 4-11.cpp
#include <iostream>
using namespace std;
int main() {
#ifdef MYDEBUG
cout << "定义了MYDEBUG" << endl;
#else
cout << "没有定义MYDEBUG" << endl;
#endif
}
编译:
$ g++ -o 4-11 4-11.cpp && ./4-11
没有定义MYDEBUG
这次在命令行上通过 -D来定义宏:
$ g++ -o 4-11 -DMYDEBUG 4-11.cpp && ./4-11
定义了MYDEBUG
4-12
写一个程序,它带有参数总是为假(零)的assert(),当运行时看发生什么现象。现在用#define NDEBUG编译它,再次运行它,看有什么不同。 4-12.cpp
#include <cassert>
#include <iostream>
using namespace std;
int main() {
assert(0, "值为false");
cout << "assert 没有执行" << endl;
}
执行不带NDEBUG宏定义:
$ g++ -o 4-12 4-12.cpp && ./4-12
Assertion failed: 0, file 4-12.cpp, line 6
执行带NDEBUG宏定义:
$ g++ -o 4-12 -DNDEBUG 4-12.cpp && ./4-12
assert 没有执行
4-13
创建一个抽象数据类型,它表示录像带租赁店中的录像带,试考虑在录像带租赁管理系统中为使录像带(Video)类型运行良好而必须的所有数据与运算。包含一个能显示录像带Video信息的print()成员函数。 VideoTape.h
#ifndef VIDEOTAPE_H
#define VIDEOTAPE_H
#include <string>
struct VideoTape {
int id;
std::string name;
void setName(std::string &name);
void setId(int id);
void print();
};
#endif
VideoTape.cpp
#include "VideoTape.h"
#include <iostream>
using namespace std;
void VideoTape::setId(int id) {
this->id = id;
}
void VideoTape::setName(string &name) {
this->name = name;
}
void VideoTape::print() {
cout << "ID:" << id
<< ",名字:" << name << endl;
}
VideoTapeTest.cpp
#include "VideoTape.h"
#include <string>
using namespace std;
int main() {
VideoTape tape;
tape.setId(1);
string name = "战狼";
tape.setName(name);
tape.print();
}
编译输出:
$ g++ -o VideoTapeTest VideoTapeTest.cpp VideoTape.cpp && ./VideoTapeTest
ID:1,名字:战狼
4-14
创建一个Stack对象,能存放练习13中的Video对象。创建几个Video对象,把它们存放在Stack中,然后用Video::print()显示它们。 4-14.cpp
#include "Stack.h"
#include "VideoTape.h"
using namespace std;
int main(int argc, char* argv[]) {
Stack videoStack;
videoStack.initialize();
string movies[] = {"战狼", "复仇者联盟", "失控玩家", "怒火重案", "峰爆"};
for (int i = 0, len = sizeof(movies)/sizeof(string); i < len; i++) {
VideoTape *pvt = new VideoTape;
pvt->setId(i);
pvt->setName(movies[i]);
videoStack.push(pvt);
}
VideoTape *pvt;
while((pvt = (VideoTape*)videoStack.pop()) != 0) {
pvt->print();
delete pvt;
}
videoStack.cleanup();
}
编译输出:
ID:4,名字:峰爆
ID:3,名字:怒火重案
ID:2,名字:失控玩家
ID:1,名字:复仇者联盟
ID:0,名字:战狼
4-15
写一个程序,使用sizeof打印出你的编译器的所有基本数据类型的长度。 省略
4-16
修改Stash,使用vector<char>作为它的底层数据结果。 CppLib.h
#include <vector>
struct Stash {
int size;
std::vector<unsigned char> storage;
void initialize(int size);
void cleanup();
int add(const void* element);
void* fetch(int index);
int count();
void inflate(int increase);
};
CppLib.cpp
#include "CppLib.h"
#include <iostream>
#include <cassert>
using namespace std;
void Stash::initialize(int sz)
{
size = sz;
}
int Stash::add(const void *element)
{
unsigned char *e = (unsigned char *)element;
for (int i = 0; i < size; i++)
{
storage.push_back(e[i]);
}
return storage.size()/size - 1;
}
void *Stash::fetch(int index)
{
assert(0 <= index);
int maxIndex = count() - 1;
if (index > maxIndex)
return 0;
unsigned char *p = new unsigned char[size];
for (int i = 0; i < size; i++) {
p[i] = storage[i + index * size];
}
return p;
}
int Stash::count()
{
return storage.size()/size;
}
void Stash::inflate(int increase)
{
}
void Stash::cleanup()
{
}
CppLibTest.cpp
#include "CppLib.h"
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
Stash intStash;
intStash.initialize(sizeof(int));
for(int i = 0; i < 100; i++)
intStash.add(&i);
for(int j = 0; j < intStash.count(); j++) {
int *element = (int*)intStash.fetch(j);
cout << "intStash.fetch(" << j << ") = "
<< *element
<< endl;
delete element;
}
Stash stringStash;
const int bufsize = 80;
stringStash.initialize(sizeof(char) * bufsize);
ifstream in("CppLibTest.cpp");
string line;
while(getline(in, line))
stringStash.add(line.c_str());
int k = 0;
char* cp;
while((cp =(char*)stringStash.fetch(k++)) != 0) {
cout << "stringStash.fetch(" << k << ") = "
<< cp << endl;
delete cp;
}
intStash.cleanup();
stringStash.cleanup();
}
编译输出:
$ g++ -o CppLibTest CppLibTest.cpp CppLib.cpp && ./CppLibTest
intStash.fetch(0) = 0
intStash.fetch(1) = 1
intStash.fetch(2) = 2
intStash.fetch(3) = 3
intStash.fetch(4) = 4
intStash.fetch(5) = 5
intStash.fetch(6) = 6
intStash.fetch(7) = 7
intStash.fetch(8) = 8
intStash.fetch(9) = 9
intStash.fetch(10) = 10
intStash.fetch(11) = 11
intStash.fetch(12) = 12
intStash.fetch(13) = 13
intStash.fetch(14) = 14
intStash.fetch(15) = 15
intStash.fetch(16) = 16
intStash.fetch(17) = 17
intStash.fetch(18) = 18
intStash.fetch(19) = 19
intStash.fetch(20) = 20
intStash.fetch(21) = 21
intStash.fetch(22) = 22
intStash.fetch(23) = 23
intStash.fetch(24) = 24
intStash.fetch(25) = 25
intStash.fetch(26) = 26
intStash.fetch(27) = 27
intStash.fetch(28) = 28
intStash.fetch(29) = 29
intStash.fetch(30) = 30
intStash.fetch(31) = 31
intStash.fetch(32) = 32
intStash.fetch(33) = 33
intStash.fetch(34) = 34
intStash.fetch(35) = 35
intStash.fetch(36) = 36
intStash.fetch(37) = 37
intStash.fetch(38) = 38
intStash.fetch(39) = 39
intStash.fetch(40) = 40
intStash.fetch(41) = 41
intStash.fetch(42) = 42
intStash.fetch(43) = 43
intStash.fetch(44) = 44
intStash.fetch(45) = 45
intStash.fetch(46) = 46
intStash.fetch(47) = 47
intStash.fetch(48) = 48
intStash.fetch(49) = 49
intStash.fetch(50) = 50
intStash.fetch(51) = 51
intStash.fetch(52) = 52
intStash.fetch(53) = 53
intStash.fetch(54) = 54
intStash.fetch(55) = 55
intStash.fetch(56) = 56
intStash.fetch(57) = 57
intStash.fetch(58) = 58
intStash.fetch(59) = 59
intStash.fetch(60) = 60
intStash.fetch(61) = 61
intStash.fetch(62) = 62
intStash.fetch(63) = 63
intStash.fetch(64) = 64
intStash.fetch(65) = 65
intStash.fetch(66) = 66
intStash.fetch(67) = 67
intStash.fetch(68) = 68
intStash.fetch(69) = 69
intStash.fetch(70) = 70
intStash.fetch(71) = 71
intStash.fetch(72) = 72
intStash.fetch(73) = 73
intStash.fetch(74) = 74
intStash.fetch(75) = 75
intStash.fetch(76) = 76
intStash.fetch(77) = 77
intStash.fetch(78) = 78
intStash.fetch(79) = 79
intStash.fetch(80) = 80
intStash.fetch(81) = 81
intStash.fetch(82) = 82
intStash.fetch(83) = 83
intStash.fetch(84) = 84
intStash.fetch(85) = 85
intStash.fetch(86) = 86
intStash.fetch(87) = 87
intStash.fetch(88) = 88
intStash.fetch(89) = 89
intStash.fetch(90) = 90
intStash.fetch(91) = 91
intStash.fetch(92) = 92
intStash.fetch(93) = 93
intStash.fetch(94) = 94
intStash.fetch(95) = 95
intStash.fetch(96) = 96
intStash.fetch(97) = 97
intStash.fetch(98) = 98
intStash.fetch(99) = 99
stringStash.fetch(1) = #include "CppLib.h"
stringStash.fetch(2) = #include <fstream>
stringStash.fetch(3) = #include <iostream>
stringStash.fetch(4) = #include <string>
stringStash.fetch(5) = using namespace std;
stringStash.fetch(6) =
stringStash.fetch(7) = int main() {
stringStash.fetch(8) = Stash intStash;
stringStash.fetch(9) = intStash.initialize(sizeof(int));
stringStash.fetch(10) = for(int i = 0; i < 100; i++)
stringStash.fetch(11) = intStash.add(&i);
stringStash.fetch(12) = for(int j = 0; j < intStash.count(); j++) {
stringStash.fetch(13) = int *element = (int*)intStash.fetch(j);
stringStash.fetch(14) = cout << "intStash.fetch(" << j << ") = "
stringStash.fetch(15) = << *element
stringStash.fetch(16) = << endl;
stringStash.fetch(17) = delete element;//需要释放空间,因为我们在fetch里分配了空间
stringStash.fetch(18) = }
stringStash.fetch(19) = // Holds 80-character strings:
stringStash.fetch(20) = Stash stringStash;
stringStash.fetch(21) = const int bufsize = 80;
stringStash.fetch(22) = stringStash.initialize(sizeof(char) * bufsize);
stringStash.fetch(23) = ifstream in("CppLibTest.cpp");
stringStash.fetch(24) = string line;
stringStash.fetch(25) = while(getline(in, line))
stringStash.fetch(26) = stringStash.add(line.c_str());
stringStash.fetch(27) = int k = 0;
stringStash.fetch(28) = char* cp;
stringStash.fetch(29) = while((cp =(char*)stringStash.fetch(k++)) != 0) {
stringStash.fetch(30) = cout << "stringStash.fetch(" << k << ") = "
stringStash.fetch(31) = << cp << endl;
stringStash.fetch(32) = delete cp;
stringStash.fetch(33) = }
stringStash.fetch(34) = intStash.cleanup();
stringStash.fetch(35) = stringStash.cleanup();
stringStash.fetch(36) = }
4-17
使用new动态创建下面类型的存储块:int、long、一个能存放100个char的数组、一个能存放100个float的数组。打印它们的地址,然后用delete释放这些存储。 4-17.cpp
#include <iostream>
using namespace std;
int main() {
int *pi = new int;
long *pl = new long;
char *pstr = new char[100];
float *pfarr = new float[100];
cout << pi << " " << pl <<
" " << (void*)pstr << " " << pfarr << endl;
delete pi;
delete pl;
delete pstr;
delete pfarr;
}
编译输出:
$ g++ -o 4-17 4-17.cpp && ./4-17
0x238893e6400 0x238893e6420 0x238893e6a50 0x238893e6ac0
4-18
写一个带有char*参数的函数。用new动态申请一个char数组,长度与传给这个函数的char数组同。 使用数组下标,从参数中拷贝字符到这个动态申请的数组中(不要忘记null终结符)并且返回拷贝的指针。在main()中,通过传递静态引用字符数组,测试这个函数。然后取这个结果,再传回这个函数。打印这两个字符串和这两个指针,这样我们可以看到它们是不同的存储。使用delete,清除所有的动态存储。 4-18.cpp
#include <iostream>
#include <cstring>
using namespace std;
char *f(const char *p) {
int len = strlen(p);
char *pnew = new char[len+1];
int i = 0;
while (pnew[i] = p[i]) {
i++;
}
return pnew;
}
int main() {
const char *p = "Hi Bixby, 今天天气怎么样呢?";
char *p1 = f(p);
cout << (void*)p1 << ": " << p1 << endl;
char *p2 = f(p1);
cout << (void*)p2 << ": " << p2 << endl;
delete p1;
delete p2;
}
编译输出:
$ g++ -o 4-18 4-18.cpp && ./4-18
0x17205ea6400: Hi Bixby, 今天天气怎么样呢?
0x17205ea6a50: Hi Bixby, 今天天气怎么样呢?
4-19
显示在一个结构中声明另一个结构的例子(嵌套结构),声明这两个struct的数据成员,声明和定义这两个struct的成员函数。写一个main(),测试这两个新类型。 4-19.cpp
#include <iostream>
using namespace std;
struct OuterStruct {
void f();
struct NestedStruct {
void f();
};
};
void OuterStruct::f() {
cout << "OuterStruct::f()被调用" << endl;
}
void OuterStruct::NestedStruct::f() {
cout << "OuterStruct::NestedStruct::f()被调用" << endl;
}
int main() {
OuterStruct outS;
OuterStruct::NestedStruct nestedS;
outS.f();
nestedS.f();
}
编译输出:
$ g++ -o 4-19 4-19.cpp && ./4-19
OuterStruct::f()被调用
OuterStruct::NestedStruct::f()被调用
4-20
结构有多大?写一段代码,打印几个结构的长度。创建几个只有数据成员的结构和几个既有数据成员又有函数成员的结构,然后创建一个完全没有成员的结构。打印出所有这些结构的长度。解释产生完全没有成员的结构的长度结果的原因。 4-20.cpp
#include <iostream>
using namespace std;
struct S1 {
int a;
};
struct S2 {
};
struct S3 {
int a;
void f(){}
};
int main() {
S1 s1; S2 s2; S3 s3;
cout << &s1 << ": " << sizeof(S1) << endl;
cout << &s2 << ": " << sizeof(S2) << endl;
cout << &s3 << ": " << sizeof(S3) << endl;
}
编译输出:
$ g++ -o 4-20 4-20.cpp && ./4-20
0x97a01ffd1c: 4
0x97a01ffd1b: 1
0x97a01ffd14: 4
没有数据成员的结构大小为1, 因为任何结构其实都是一个自定义类型,一个类型必须有大小,否则如何创建这个类型的变量呢?所以就给了一个默认的最小值1。
4-21
C++自动创建struct的typedef的等价物,正如在本章中看到的。对于枚举和联合类型也是如此。写一个小程序来证明这一点。 4-21.cpp
enum Color {
RED, GREEN, BLUE
};
union Data {
int i;
long j;
};
int main() {
Color color = GREEN;
Data data;
data.j = 2;
}
编译没有错误,就说明了自动创建typedef等价物:
$ g++ -o 4-21 4-21.cpp && ./4-21
4-22
创建一个存放Stash的Stack,每个Stash存放来自输入文件的5行。使用new创建Stash,读文件进入Stack,然后从这个Stack中提取并按原来的形式打印出来。 4-22.cpp
#include "Stack.h"
#include "CppLib.h"
#include <fstream>
#include <string>
#include <iostream>
using namespace std;
void displayStash(Stash* pStash) {
int k = 0;
char* cp;
while((cp =(char*)pStash->fetch(k++)) != 0)
cout << "stringStash.fetch(" << k << ") = "
<< cp << endl;
}
int main() {
Stack stashStack;
stashStack.initialize();
ifstream in("4-22.cpp");
string line;
int lineNo = 0;
while (getline(in, line)) {
Stash *pStash = 0;
if (lineNo == 0) {
pStash = new Stash();
pStash->initialize(sizeof(char) * 80);
stashStack.push(pStash);
} else {
pStash = (Stash*)stashStack.peek();
}
if (++lineNo == 5) {
lineNo = 0;
}
pStash->add(line.c_str());
}
Stash *pStash;
while((pStash = (Stash*)stashStack.pop()) != 0) {
displayStash(pStash);
pStash->cleanup();
}
stashStack.cleanup();
}
编译输出:
$ g++ -o 4-22 4-22.cpp CppLib.cpp Stack.cpp && ./4-22
stringStash.fetch(1) = }
stringStash.fetch(2) = stashStack.cleanup();
stringStash.fetch(3) = }
freeing storage
stringStash.fetch(1) =
stringStash.fetch(2) = Stash *pStash;
stringStash.fetch(3) = while((pStash = (Stash*)stashStack.pop()) != 0) {
stringStash.fetch(4) = displayStash(pStash);
stringStash.fetch(5) = pStash->cleanup();
freeing storage
stringStash.fetch(1) = if (++lineNo == 5) {
stringStash.fetch(2) = lineNo = 0;
stringStash.fetch(3) = }
stringStash.fetch(4) = pStash->add(line.c_str());
stringStash.fetch(5) = }
freeing storage
stringStash.fetch(1) = pStash->initialize(sizeof(char) * 80);
stringStash.fetch(2) = stashStack.push(pStash);
stringStash.fetch(3) = } else {
stringStash.fetch(4) = pStash = (Stash*)stashStack.peek();
stringStash.fetch(5) = }
freeing storage
stringStash.fetch(1) = int lineNo = 0;
stringStash.fetch(2) = while (getline(in, line)) {
stringStash.fetch(3) = Stash *pStash = 0;
stringStash.fetch(4) = if (lineNo == 0) {
stringStash.fetch(5) = pStash = new Stash();
freeing storage
stringStash.fetch(1) = int main() {
stringStash.fetch(2) = Stack stashStack;
stringStash.fetch(3) = stashStack.initialize();
stringStash.fetch(4) = ifstream in("4-22.cpp");
stringStash.fetch(5) = string line;
freeing storage
stringStash.fetch(1) = while((cp =(char*)pStash->fetch(k++)) != 0)
stringStash.fetch(2) = cout << "stringStash.fetch(" << k << ") = "
stringStash.fetch(3) = << cp << endl;
stringStash.fetch(4) = }
stringStash.fetch(5) =
freeing storage
stringStash.fetch(1) = using namespace std;
stringStash.fetch(2) =
stringStash.fetch(3) = void displayStash(Stash* pStash) {
stringStash.fetch(4) = int k = 0;
stringStash.fetch(5) = char* cp;
freeing storage
stringStash.fetch(1) = #include "Stack.h"
stringStash.fetch(2) = #include "CppLib.h"
stringStash.fetch(3) = #include <fstream>
stringStash.fetch(4) = #include <string>
stringStash.fetch(5) = #include <iostream>
freeing storage
4-23
修改练习22,使得创建一个struct,它封装几个Stash的Stack。用户只能通过成员函数添加和得到一行,在这个覆盖下,struct使用Stash的Stack。 省略
4-24
创建一个struct,它存放一个int和一个指向相同struct的另一个实例的指针。写一个函数,它能取这些struct的地址,并且能取一个表示被创建的表的长度的int。这个函数产生这些struct的一个完整链(链表),链表的头指针是这个函数的参数,struct中的指针指向下一个struct。用new产生一些新struct,将计数(对象数目)放在这个int中,对这个链表的最后一个struct的指针位置零值,表示链表结束。写第二个函数,它取这个链表的头指针,并且向后移动到最后,打印出每个struct的指针值和int值。 4-24.cpp
#include <iostream>
using namespace std;
struct Node {
int value;
Node *next;
};
void makeLinkedList(Node **ppNode) {
Node *pHead = NULL;
int count = 0;
for (int i = 0; i < 5; i++) {
Node *p = new Node();
p->value = ++count;
p->next = pHead;
pHead = p;
}
*ppNode = pHead;
}
void displayLinkedList(Node *pHead) {
Node *pNext = pHead;
while (pNext) {
cout << "value: " << pNext->value << endl;
pNext = pNext->next;
}
}
int main() {
Node *pHead = NULL;
makeLinkedList(&pHead);
displayLinkedList(pHead);
}
编译输出:
$ g++ -o 4-24 4-24.cpp && ./4-24
value: 5
value: 4
value: 3
value: 2
value: 1
4-25
重复练习24, 但是将这些函数放在一个struct内部,而不是用“原始”的struct和函数。 4-25.cpp
#include <iostream>
using namespace std;
struct Node {
int value;
Node *next;
};
struct LinkedList {
Node *pHead;
void makeLinkedList();
void displayLinkedList();
};
void LinkedList::makeLinkedList() {
pHead = NULL;
int count = 0;
for (int i = 0; i < 5; i++) {
Node *p = new Node();
p->value = ++count;
p->next = pHead;
pHead = p;
}
}
void LinkedList::displayLinkedList() {
Node *pNext = pHead;
while (pNext) {
cout << "value: " << pNext->value << endl;
pNext = pNext->next;
}
}
int main() {
LinkedList lst;
lst.makeLinkedList();
lst.displayLinkedList();
}
编译输出:
$ g++ -o 4-25 4-25.cpp && ./4-25
value: 5
value: 4
value: 3
value: 2
value: 1
|