《C++编程思想》第二章 数 据 抽 象(原书代码+习题+答案)
相关代码例如以下:
1.
<span style="font-size:18px;">/*声明与定义的差别*/ #include <iostream>
using namespace std; extern int i;//声明
extern float f(float);//声明 float b;//定义+声明
float f(float a)//定义
{ return a + 1.0;
} int i;//定义
int h(int x)//定义+声明
{
return x + 1;
} int main()
{
b = 1.0;
i = 2;
cout<<f(b)<<endl;
cout<<h(i)<<endl; return 0;
}</span>
2.
<span style="font-size:18px;">/*test.h*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* 一个袖珍C库 C */
typedef struct STASHtag
{
int size; //Size of each space
int quantity; //Number of storage spaces
int next; //Next empty space
unsigned char* storage;//storage指针是一个unsigned char*。 这是 C 编译器支持的最小的存储片。虽然在某些机器
//上它可能与最大的一般大,这依赖于详细实现。 storage指向的内存从堆中分配
}Stash; void initialize(Stash* S, int Size);//initialize()完毕对 struct stash 的必要的设置。即设置内部变量为适当的值。 最初,设置
//storage指针为零。设置size 指示器也为零,表示初始存储未被分配。 void cleanup(Stash* S); //清除
int add(Stash* S, void* element); //add()函数在stash的下一个可用位子上插入一个元素。首先,它检查是否有可用空间,如
//果没有,它就用后面介绍的 inflate() 函数扩展存储空间。
void* fetch(Stash* S, int index); //fetch()首先看索引是否越界,假设没有越界,返回所希望的变量地址,地址的计算採用与
//add()中同样的方法
int count(Stash* S); //返回所存储空间大小
void inflate(Stash* S, int increase);
/*inflate()函数使用realloc()为stash得到更大的空间块。 realloc()把已经分配而又希望重分配
的存储单元首地址作为它的第一个參数(假设这个參数为零,比如 initialize()刚刚被调用时。
realloc()分配一个新块)。第二个參数是这个块新的长度,假设这个长度比原来的小。这个块
将不须要作拷贝。简单地告诉堆管理器剩下的空间是空暇的。 假设这个长度比原来的大。在堆
中没有足够的相临空间,所以要分配新块,而且要拷贝内存。 assert()检查以确信这个操作成
功。(假设这个堆用光了。 malloc()、 calloc()和realloc()都返回零。 )*/</span>
<span style="font-size:18px;">/*test.c*/ /*如果有一个程序设计工具,当创建时它的表现像一个数组。但它的长度能在执行时建
立。我称它为stash*/ #include "test.h" void initialize(Stash* S, int Size)
{
S->size = Size;
S->quantity = 0;
S->storage = 0;
S->next = 0;
} void cleanup(Stash* S)
{
if(S->storage)
{
puts("freeing storage");
free(S->storage);
}
} int add(Stash* S, void* element)
{
if(S->next >= S->quantity)
{
inflate(S,100);
}
memcpy(&(S->storage[S->next * S->size]),element,S->size );
/*我们必须用标准 C 库函数memcpy( )一个字节一个字节地拷贝这个变量,第一个參数是 memcpy()
開始拷贝字节的目的地址,由以下表达式产生:
&(S->storage[S->next * S->size])
它指示从存储块開始的第 next个可用单元结束。这个数实际上就是已经用过的单元号加一
的计数,它必须乘上每一个单元拥有的字节数,产生按字节计算的偏移量。 这不产生地址。而是
产生处于这个地址的字节。为了产生地址,必须使用地址操作符 &。
memcpy()的第二和第三个參数各自是被拷贝变量的開始地址和要拷贝的字节数。 n e x t计数
器加一。并返回被存值的索引。 这样。程序猿能够在后面调用 fetch( )时用它来取得这个元素。 */
S->next ++;
return (S->next - 1);
} void* fetch(Stash* S, int index)
{
if(index >= S->next || index < 0)
{
return 0;
}
return &(S->storage[index * S->size]);
} int count(Stash* S)
{
return S->next;
} void inflate(Stash* S, int increase)
{
void* v = realloc(S->storage,(S->quantity + increase)*S->size );
assert(v);
S->storage = v;//在 C 库中的 inflate()中,能够将void *赋给其它不论什么指针。比如S->storage = v;并且编译器能够通过。
S->quantity += increase;
}</span>
<span style="font-size:18px;">/*main.c*/ #include "test.h" #define BUFSIZE 80 int main()
{
Stash intStash,stringStash;
int i;
FILE* file;
char buf[BUFSIZE];
char* cp; initialize(&intStash,sizeof(int));
for(i = 0;i < 100;++i)
{
add(&intStash,&i);
} initialize(&stringStash,sizeof(char)*BUFSIZE);
file = fopen("main.c","r");
assert(file);
while(fgets(buf, BUFSIZE, file))
{
add(&stringStash, buf);
}
fclose(file); for(i = 0;i < count(&intStash);++i)
{
printf("fetch(&intStash, %d) = %d\n",i ,
*(int*)fetch(&intStash,i));
}
i = 0;
while((cp = fetch(&stringStash,i++)) != 0)
{
printf("fetch(&stringStash, %d) = %s",
i-1,cp);
}
putchar('\n');
cleanup(&intStash);
cleanup(&stringStash); return 0;
}</span>
3.
<span style="font-size:18px;">#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//C++
struct stash
{
int size; //Size of each space
int quantity; //Number of storage spaces
int next; //Next empty space
unsigned char* storage; //storage指针是一个unsigned char*。这是 C 编译器支持的最小的存储片,虽然在某些机器
//上它可能与最大的一般大,这依赖于详细实现。 storage指向的内存从堆中分配
void initialize(int Size);//initialize()完毕对 struct stash 的必要的设置,即设置内部变量为适当的值。最初,设置
//storage指针为零。设置size 指示器也为零,表示初始存储未被分配。
void cleanup(); //清除
int add(void* element); //add()函数在stash的下一个可用位子上插入一个元素。首先,它检查是否有可用空间,如
//果没有,它就用后面介绍的 inflate() 函数扩展存储空间。 void* fetch(int index); //fetch()首先看索引是否越界,假设没有越界,返回所希望的变量地址,地址的计算採用与
//add()中同样的方法
int count(); //返回所存储空间大小
void inflate(int increase);
/*inflate()函数使用realloc()为stash得到更大的空间块。 realloc()把已经分配而又希望重分配
的存储单元首地址作为它的第一个參数(假设这个參数为零,比如 initialize()刚刚被调用时。
realloc()分配一个新块)。第二个參数是这个块新的长度,假设这个长度比原来的小。这个块
将不须要作拷贝,简单地告诉堆管理器剩下的空间是空暇的。假设这个长度比原来的大,在堆
中没有足够的相临空间。所以要分配新块,而且要拷贝内存。 assert()检查以确信这个操作成
功。 (假设这个堆用光了。 malloc()、 calloc()和realloc()都返回零。 )*/
};
</span>
<span style="font-size:18px;">/*test.cpp*/ /*如果有一个程序设计工具。当创建时它的表现像一个数组,但它的长度能在执行时建
立。我称它为stash*/ #include "test.h" void stash::initialize(int Size)
{
size = Size;
quantity = 0;
storage = 0;
next = 0;
} void stash::cleanup()
{
if(storage)
{
puts("freeing storage");
free(storage);
}
} int stash::add(void* element)
{
if(next >= quantity)
{
inflate(100);
}
memcpy(&(storage[next * size]),element,size );
/*我们必须用标准 C 库函数memcpy( )一个字节一个字节地拷贝这个变量,第一个參数是 memcpy()
開始拷贝字节的目的地址,由以下表达式产生:
&(S->storage[S->next * S->size])
它指示从存储块開始的第 next个可用单元结束。这个数实际上就是已经用过的单元号加一
的计数,它必须乘上每一个单元拥有的字节数,产生按字节计算的偏移量。这不产生地址,而是
产生处于这个地址的字节,为了产生地址。必须使用地址操作符 &。
memcpy()的第二和第三个參数各自是被拷贝变量的開始地址和要拷贝的字节数。 n e x t计数
器加一,并返回被存值的索引。这样,程序猿能够在后面调用 fetch( )时用它来取得这个元素。*/
next ++;
return (next - 1);
} void* stash::fetch(int index)
{
if(index >= next || index < 0)
{
return 0;
}
return &(storage[index * size]);
} int stash::count()
{
return next;
} void stash::inflate( int increase)
{
void* v = realloc(storage,(quantity + increase)*size );
assert(v);
storage = (unsigned char*)v;
quantity += increase;
}</span>
<span style="font-size:18px;">#include "test.h"
#define BUFSIZE 80 int main()
{
stash intStash,stringStash;
int i;
FILE* file;
char buf[BUFSIZE];
char* cp; intStash.initialize(sizeof(int));
for(i = 0;i < 100;++i)
{
intStash.add(&i);
} stringStash.initialize(sizeof(char)*BUFSIZE);
file = fopen("main.cpp","r");
assert(file);
while(fgets(buf, BUFSIZE, file))
{
stringStash.add(buf);
}
fclose(file); for(i = 0;i < intStash.count();++i)
{
printf("intStash.fetch(%d) = %d\n",i,
*(int*)intStash.fetch(i));
}
i = 0;
while((cp = (char*)stringStash.fetch(i++)) != 0)
{
printf("stringStash.fetch(%d) = %s",
i-1,cp);
}
putchar('\n');
intStash.cleanup();
stringStash.cleanup();
return 0;
}</span>
4.
<span style="font-size:18px;">/*1.h C */
typedef struct STASHtag
{
int size; //Size of each space
int quantity; //Number of storage spaces
int next; //Next empty space
unsigned char* storage;//storage指针是一个unsigned char*。这是 C 编译器支持的最小的存储片,虽然在某些机器
//上它可能与最大的一般大,这依赖于详细实现。 storage指向的内存从堆中分配
}Stash; void initialize(Stash* S, int Size);//initialize()完毕对 struct stash 的必要的设置,即设置内部变量为适当的值。最初,设置
//storage指针为零,设置size 指示器也为零,表示初始存储未被分配。 void cleanup(Stash* S); //清除
int add(Stash* S, void* element); //add()函数在stash的下一个可用位子上插入一个元素。首先,它检查是否有可用空间。如
//果没有,它就用后面介绍的 inflate() 函数扩展存储空间。 void* fetch(Stash* S, int index); //fetch()首先看索引是否越界,假设没有越界,返回所希望的变量地址,地址的计算採用与
//add()中同样的方法
int count(Stash* S); //返回所存储空间大小
void inflate(Stash* S, int increase);
/*inflate()函数使用realloc()为stash得到更大的空间块。 realloc()把已经分配而又希望重分配
的存储单元首地址作为它的第一个參数(假设这个參数为零。比如 initialize()刚刚被调用时,
realloc()分配一个新块)。第二个參数是这个块新的长度。假设这个长度比原来的小,这个块
将不须要作拷贝,简单地告诉堆管理器剩下的空间是空暇的。假设这个长度比原来的大,在堆
中没有足够的相临空间。所以要分配新块,而且要拷贝内存。 assert()检查以确信这个操作成
功。(假设这个堆用光了。 malloc()、 calloc()和realloc()都返回零。 )*/</span>
<span style="font-size:18px;">//C++2.h
struct stash
{
int size; //Size of each space
int quantity; //Number of storage spaces
int next; //Next empty space
unsigned char* storage; //storage指针是一个unsigned char*。这是 C 编译器支持的最小的存储片,虽然在某些机器
//上它可能与最大的一般大。这依赖于详细实现。 storage指向的内存从堆中分配
void initialize(int Size);//initialize()完毕对 struct stash 的必要的设置,即设置内部变量为适当的值。 最初,设置
//storage指针为零,设置size 指示器也为零。表示初始存储未被分配。
void cleanup(); //清除
int add(void* element); //add()函数在stash的下一个可用位子上插入一个元素。 首先,它检查是否有可用空间,如
//果没有,它就用后面介绍的 inflate() 函数扩展存储空间。
void* fetch(int index); //fetch()首先看索引是否越界。假设没有越界。返回所希望的变量地址,地址的计算採用与
//add()中同样的方法
int count(); //返回所存储空间大小
void inflate(int increase);
/*inflate()函数使用realloc()为stash得到更大的空间块。 realloc()把已经分配而又希望重分配
的存储单元首地址作为它的第一个參数(假设这个參数为零,比如 initialize()刚刚被调用时,
realloc()分配一个新块)。第二个參数是这个块新的长度,假设这个长度比原来的小。这个块
将不须要作拷贝。简单地告诉堆管理器剩下的空间是空暇的。假设这个长度比原来的大,在堆
中没有足够的相临空间,所以要分配新块,而且要拷贝内存。 assert()检查以确信这个操作成
功。(假设这个堆用光了, malloc()、 calloc()和realloc()都返回零。)*/
};
</span>
<span style="font-size:18px;">#include "1.h"
#include "2.h"
#include <stdio.h> struct A
{
int I[100];
}; struct B
{
void f();
}; void B::f()
{} int main()
{
printf("sizeof struct A = %d bytes\n",
sizeof(A));//每一个 int 占二个字节
printf("sizeof struct B = %d bytes\n",
sizeof(B));//struct B 是神秘的,由于它是没有数据成员的 struct
printf("sizeof Stash in C = %d bytes\n",
sizeof(Stash));
printf("sizeof stash in C++ = %d bytes\n",
sizeof(stash));
/*最后两个 sizeof 语句表明在 C++ 中的结构长度与 C 中等价版本号的长度同样。 C++ 尽力不
添加不论什么花费*/ return 0;
}</span>
5.
<span style="font-size:18px;">#ifndef NESTED_H_
#define NESTED_H_ struct stack//这个嵌套 struct 称为 link。它包含指向这个表中的下一个 link 的指针和指向存放在 link 中的数据的指针。假设 next 指针是零。意味着表尾。
{
struct link
{
void* data;
link* next;
void initialize(void* Data, link* Next);
}*head;
void initialize();
void push(void* Data);
void* peek();
void* pop();
void cleanup();//cleanup 去除每一个栈元素,并释放data 指针
};
#endif</span>
<span style="font-size:18px;">#include "nested.h"
#include <stdlib.h>
#include <assert.h> void stack::link::initialize(void* Data, link* Next)
//简单地两次使用范围分解运算符,以指明这个嵌套 struct 的名字。 stack::link::initialize( ) 函数取參数并把參数赋给它的成员们
{
data = Data;
next = Next;
} void stack::initialize()
//stack::initialize( ) 函数置 head 为零。使得这个对象知道它有一个空表
{
head = 0;
} void stack::push(void* Data)
//stack::push( ) 取參数,也就是一个指向希望用这个 stack 保存的一块数据的指针。而且把
//这个指针放在栈顶
{
link* newlink = (link*)malloc(sizeof(link));
assert(newlink);
newlink->initialize(Data, head);
head = newlink;
} void* stack::peek()
//返回head的值
{
return head->data;
} void* stack::pop()
//stack::pop( )取出当前在该栈顶部的 data 指针,然后向下移 head 指针,删除该栈老的栈顶元素
{
if(head == 0)
{
return 0;
}
void* result = head->data;
link* oldHead = head;
head = head->next;
free(oldHead);
return result;
} void stack::cleanup()
//stack::cleanup()创建cursor 在整个栈上移动。用free()释放每一个link的data和link 本身
{
link* cursor = head;
while(head)
{
cursor = cursor->next;
free(head->data);
free(head);
head = cursor;
}
}</span>
<span style="font-size:18px;">#include "nested.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h> #define BUFSIZE 100 int main(int argc, char** argv)
{
stack textlines;
FILE* file;
char* s;
char buf[BUFSIZE];
assert(argc == 2);
textlines.initialize();
file = fopen(argv[1],"r");
assert(file);
while(fgets(buf, BUFSIZE, file))
{
char* string = (char*)malloc(strlen(buf)+1);
assert(string);
strcpy(string, buf);
textlines.push(string);
} while((s = (char*)textlines.pop()) != 0 )
{
printf("%s",s);
free(s);
}
textlines.cleanup(); return 0;
}</span>
6.
<span style="font-size:18px;">#include <iostream>
using namespace std;
//假设在 S::f() 中没有范围分解。
//编译器会缺省地选择 f() 和 A 的成员版本号
int A;
void f()
{} struct S
{
int A;
void f();
}; void S::f()
{
::f();
::A++;
A--;
}
int main()
{
return 0;
}</span>
1) 创建一个 struct 声明,它有单个成员函数。然后对这个成员函数创建定义。创建这个新数据类型的对象,再调用这个成员函数。
#include <iostream>
using namespace std; struct Student
{
void play();
}; void Student::play()
{
cout<<"Funny!"<<endl;
} int main()
{
Student s;
s.play();
return 0;
}
2) 编写而且编译一段代码,这段代码完毕数据成员选择和函数调用。
#include <iostream>
#include <string>
using namespace std; struct Student
{
string address;
void play(string address);
}; void Student::play(string address)
{
cout<<address<<" "<<"is Funny!"<<endl;
} int main()
{
Student s;
s.play("Xi'an");
return 0;
}
3) 写一个在还有一个结构中的被声明结构的样例(嵌套结构)。并说明怎样定义这个结构的成员。
#include <iostream>
#include <string>
using namespace std; #ifndef TEST_H_
#define TSET_H_ struct family
{
struct school
{
string address;
void schools(string address);
}*addr;
int number;
void families(int number);
}; #endif
#include "test.h" void family::school::schools(string address)//取參数并输出
{
cout<<"The school's address: "<<address<<endl;
}
void family::families(int number)//取參数并输出
{
cout<<"The family's people number: "<<number<<endl;
}
#include "test.h" int main()
{
family f;
f.families(5); return 0;
}
4) 结构有多大?写一段能打印各个结构的长度的代码。创建一些结构。它们仅仅有数据成员。还有一些有数据成员和函数成员。然后创建一个结构,它根本没有成员。打印出全部这些结构的长度。
对于根本没有成员的结构的结果作出解释。
#include <stdio.h> struct A
{
char a;
int b;
}; struct B
{
void f();
double d;
}; struct C
{ }; void B::f()
{} int main()
{
printf("sizeof struct A = %d bytes\n",
sizeof(A));//每一个 int 占四个字节,char占一个字节,可是要是四的倍数即为八
printf("sizeof struct B = %d bytes\n",
sizeof(B));//每一个double占八个字节,函数字节数为八
printf("sizeof struct C = %d bytes\n",
sizeof(C));//struct C 是神秘的,由于它是没有数据成员的 struct return 0;
}
5) C++对于枚举、联合和 struct 自己主动创建 typedef 的等价物,正如在本章中看到的。
写一个能说明这一点的小程序。
#include <iostream>
#include <string>
using namespace std; typedef struct
{
int age;
string address;
}student; typedef union
{
int a;
double d;
}number; typedef enum
{
white,black,blue,green
}colour; int main()
{
student s;
s.address = "Xi'an";
s.age = 18;
cout<<"student's address: "<<s.address<<endl;
cout<<"student's age: "<<s.age<<endl; number n;
n.a = 5;
cout<<"people number:"<<n.a<<endl; colour c = white;
cout<<"number of enum: "<<c<<endl; return 0;
}
《C++编程思想》第二章 数 据 抽 象(原书代码+习题+答案)的更多相关文章
- 《C++编程思想》第四章 初始化与清除(原书代码+习题+解答)
相关代码: 1. #include <stdio.h> class tree { int height; public: tree(int initialHeight); ~tree(); ...
- [Java编程思想] 第二章 一切都是对象
第二章 一切都是对象 2.1 用引用操纵对象 创建一个String引用: String s; 这里所创建的只是引用,并不是对象. 创建一个引用的同时便初始化: String s = &qu ...
- JAVA编程思想第二章答案
欢迎访问我的CSDN博客查看https://mp.csdn.net/mdeditor/94797839# 有其他问题欢迎发送邮箱至hpzhangjunjiell@163.com 感谢
- [书籍翻译] 《JavaScript并发编程》 第二章 JavaScript运行模型
本文是我翻译<JavaScript Concurrency>书籍的第二章 JavaScript运行模型,该书主要以Promises.Generator.Web workers等技术来讲解J ...
- 3-8《Ruby元编程》第二章对象模型
<Ruby元编程> 第二章 对象模型 类定义揭秘inside class definitions: class关键字更像一个作用域操作符,核心作用是可以在里面随时定义方法. [].meth ...
- 第二章:排序算法 及其他 Java代码实现
目录 第二章:排序算法 及其他 Java代码实现 插入排序 归并排序 选择排序算法 冒泡排序 查找算法 习题 2.3.7 第二章:排序算法 及其他 Java代码实现 --算法导论(Introducti ...
- c++学习书籍推荐《C++编程思想第二卷》下载
百度云及其他网盘下载地址:点我 编辑推荐 <C++编程思想>(第2卷)是惟一一本如此清晰地阐述如何重新思考以面向对象方法构造程序的书籍.<C++编程思想>(第2卷)介绍实用的编 ...
- [Java编程思想] 第一章 对象导论
第一章 对象导论 "我们之所以将自然界分解,组织成各种概念,并按其含义分类,主要是因为我们是整个口语交流社会共同遵守的协定的参与者,这个协定以语言的形式固定下来--除非赞成这个协定中规定的有 ...
- java多线程编程核心技术——第二章
第一节synchronized同步方法目录 1.1方法内的变量为线程安全的 1.2实例变量非线程安全 1.3多个对象多个锁 1.4synchronized方法与锁对象 1.5脏读 1.6synchro ...
随机推荐
- 使用 CommandScene 类在 XNA 中创建命令场景(十二)
平方已经开发了一些 Windows Phone 上的一些游戏,算不上什么技术大牛.在这里分享一下经验,仅为了和各位朋友交流经验.平方会逐步将自己编写的类上传到托管项目中,没有什么好名字,就叫 WPXN ...
- PAT1026
要获得一个C语言程序的运行时间,常用的方法是调用头文件time.h,其中提供了clock()函数,可以捕捉从程序开始运行到clock()被调用时所耗费的时间.这个时间单位是clock tick,即“时 ...
- nyoj 题目20 吝啬的国度
吝啬的国度 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 在一个吝啬的国度里有N个城市,这N个城市间只有N-1条路把这个N个城市连接起来.现在,Tom在第S号城市, ...
- RUBY 模拟rtsp消息
require 'rtsp/client' require 'log_switch' require 'socket' RTSP::Client.log? # => false RTSP::Cl ...
- 查看oracle日志路径
adrci ADRCI: Release 12.2.0.1.0 - Production on Tue Oct 9 16:14:35 2018 Copyright (c) 1982, 2017, Or ...
- JVM(8):JVM知识点总览-高级Java工程师面试必备
http://www.importnew.com/23792.html jvm 总体梳理 jvm体系总体分四大块: 类的加载机制 jvm内存结构 GC算法 垃圾回收 GC分析 命令调优 当然这些知识点 ...
- BZOJ-1043 [HAOI2008]下落的圆盘
几何题... 先把所有圆储存起来,然后对于每个圆我们求得之后放下的圆挡住了的部分,求个并集,并把没被挡到的周长加进答案. #include <cstdlib> #include <c ...
- 请大家注意这个网站www.haogongju.net
乱转发我的文章,求职之路(拿到百度.美团.趋势科技.华为offer),不注明出处,我把原来的博客删除了,被转载的文章还在,www.haogongju.net,你侵犯版权!!!请你自动撤销!!!
- jupyter的使用
shift+enter 运行程序 Tab 代码补全 shift+Tab 查看函数说明 shift+Tab+Tab 查看函数详细说明 https://www.dataquest.io/blog/jupy ...
- 【16】vuex2.0 之 getter
有的组件中获取到 store 中的state, 需要对进行加工才能使用,computed 属性中就需要写操作函数,如果有多个组件中都需要进行这个操作,那么在各个组件中都写相同的函数,那就非常麻烦,这 ...