《C++編程思想》第二章 數 據 抽 象(原書代碼+習題+答案)

來源:互聯網
上載者:User

標籤:ack   ash   範圍   extern   指標   編譯器   指標   lib   對象   

相關代碼例如以下:

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 spaceint quantity;          //Number of storage spacesint next;              //Next empty spaceunsigned 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 80int 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 spaceint quantity;             //Number of storage spacesint next;                 //Next empty spaceunsigned 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 80int 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 spaceint quantity;          //Number of storage spacesint next;              //Next empty spaceunsigned 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.hstruct stash{int size;                 //Size of each spaceint quantity;             //Number of storage spacesint next;                 //Next empty spaceunsigned 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 是神秘的,由於它是沒有資料成員的 structprintf("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 100int 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 是神秘的,由於它是沒有資料成員的 structreturn 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++編程思想》第二章 數 據 抽 象(原書代碼+習題+答案)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.