分类目录归档:C++

C++是一种使用非常广泛的电脑程序设计语言。它是一种静态数据类型检查的,支持多范型的通用程序设计语言。C++支持过程化程序设计、数据抽象化、面向对象程序设计、泛型程序设计、基于原则设计等多种程序设计风格。贝尔实验室的比雅尼·斯特劳斯特鲁普博士在20世纪80年代发明并实现了C++

c++ primer 5 exercise 10.9

c++ primer 5 exercise 10.9

实现自己的elimDups程序。测试你的程序,分别在读取输入后、调用unique后以及调用erase后打印vector
程序实现:

// sort and elimDups
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
using std::ends;
using std::endl;
using std::string;
using std::vector;
using std::sort;
using std::unique;

vector<string> strToVec(const string line, const string separators);
void show(vector<string> const &words);
void elimDups(vector<string> words);
int main(void)
{
        const string Separators = " \t:;,\n\r\f\v";
        string str("the quick red fox jumps the slow red turtle");

        // string turn on vector<sting>
        vector<string> vec;
        vec = strToVec(str, Separators);

        // show vector<string>
        cout << "string to vector<sting>..." << endl;
        show(vec);

        // elimDups()
        cout << "\nelimDups()..." << endl;
        elimDups(vec);

        return 0;
}

vector<string> strToVec(const string line, const string separators)
{
        vector<string> vec;
        string word;
        std::string::size_type startPos = 0, endPos = 0;
        std::string::size_type wordLen = 0;

        while ((startPos = line.find_first_not_of(separators,
                endPos)) != std::string::npos) {
                endPos = line.find_first_of(separators, startPos);
                if (endPos == std::string::npos)
                        wordLen = line.size() - startPos;
                else
                        wordLen = endPos - startPos;
                word.assign(line.begin() + startPos,
                        line.begin() + startPos + wordLen);
                vec.push_back(word);
        }

        return vec;
}

void show(vector<string> const &words)
{
        for (const auto s : words)
                cout << s << " ";
        cout << endl;

        return;
}

void elimDups(vector<string> words)
{
        sort(words.begin(), words.end());
        show(words);

        auto end_unique = unique(words.begin(), words.end());
        show(words);

        words.erase(end_unique, words.end());
        show(words);

        return;
}

程序测试结果:

[lhf@localhost 10-9]$ ./elimDups
string to vector<sting>...
the quick red fox jumps the slow red turtle

elimDups()...
fox jumps quick red red slow the the turtle
fox jumps quick red slow the turtle the red
fox jumps quick red slow the turtle

字符串排序函数(单词排序,唯一)

本程序演示:怎样将一个string字符串输入到一个vector中,每个元素对应一个单词。

// sort and unique
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
using std::ends;
using std::endl;
using std::string;
using std::vector;
using std::sort;

void show(vector<string> const &words);
void elimDups(vector<string> &words);
int main(void)
{
        string str("the quick red fox jumps over the slow red turtle");
        //string str("");

        string separators = " \t:;,\v\n\r\f";
        string word;
        vector<string> vec;
        std::string::size_type startPos = 0, endPos = 0;
        std::string::size_type /*count = 0,*/ wordLen = 0;
        while ((startPos = str.find_first_not_of(separators, endPos))
                != std::string::npos) {
//              ++count;
                endPos = str.find_first_of(separators, startPos);
                if (endPos == std::string::npos) {
                        wordLen = str.size() - startPos;
                } else {
                        wordLen = endPos -startPos;
                }
                word.assign(str.begin() + startPos,
                        str.begin() + startPos + wordLen);
                vec.push_back(word);
        }
        // show vec info
        show(vec);

        elimDups(vec);

        return 0;
}

void elimDups(vector<string> &words)
{
        sort(words.begin(), words.end());
        show(words);
        auto end_unique = unique(words.begin(), words.end());
        show(words);
        words.erase(end_unique, words.end());
        show(words);
}

void show(vector<string> const &words)
{
        for (auto s : words)
                cout << s << " ";
        cout << endl;

        return;
}


程序输出:

[lhf@localhost study]$ ./23
the quick red fox jumps over the slow red turtle
fox jumps over quick red red slow the the turtle
fox jumps over quick red slow the turtle the red
fox jumps over quick red slow the turtle

c++primer 9.51习题

设计一个类,它有三个unsigned成员,分别表示年月日。为其编写构造函数,接受一个表示日期的string参数。你的构造函数能够处理不同的数据格式,如January 1, 1900 1/1/1900 Jan 1 1900等

// January 1, 1900      1/1/1900        Jan 1 1900
#include <iostream>
#include <vector>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::ends;
using std::vector;
using std::string;
using std::stoi;

class Date {
public:
        vector<string> full_month{
                "January", "February", "March", "April", "May", "June", "July",
                "August", "September", "October", "November", "December"
        };
        vector<string> abb_month{
                "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept",
                "Sep", "Oct", "Nov", "Dec"
        };
public:
        Date(const string& info);
        ~Date(void) {}
        void print_info(void)
        {
                cout << "_" << month << "." << day << "."<< year << "_\n";
                return;
        }
private:
        void init(void)
        {
                year = 1900;
                month = 1;
                day = 1;

                return;
        }
private:
        unsigned year;
        unsigned month;
        unsigned day;
};

int main(void)
{

        cout << "2343" << endl;
        Date error("2343");
        error.print_info();
        cout << string(20, '*') << endl;

        cout << "October 21, 2002" << endl;
        Date date1("October 21, 2002");
        date1.print_info();
        cout << string(20, '*') << endl;

        cout << "2/8/1995" << endl;
        Date date2("2/8/1995");
        date2.print_info();
        cout << string(20, '*') << endl;

        cout << "May 12 2011" << endl;
        Date date3("May 12 2011");
        date3.print_info();

        return 0;
}

Date::Date(const string& info)
{
        std::string::size_type pos;
        pos = info.find_first_of(", /");

        // error info
        if (pos == std::string::npos) {
                init();
                cout << "error date format: init" << endl;
                return;
        }

        // 1/1/1900
        std::string::size_type pos1 = info.find_first_of('/'),
                pos11 = pos1;
        if (pos1 != std::string::npos) {
                day = stoi(info.substr(0, pos1));
                pos11 = info.find_first_of('/', pos1 + 1);
                month = stoi(info.substr(pos1 + 1, pos11));
                year = stoi(info.substr(pos11 + 1, info.size() - 1));
                return;
        }

        // January 1, 1990 and Jan 1 1900
        std::string::size_type pos2 = info.find_first_of(' '),
                pos3 = pos2, pos33 = pos3, pos22 = info.find_first_of(',');
        if (pos22 != std::string::npos) {
                // January 1, 1990
                string str_month = info.substr(0, pos2);
                vector<string>::size_type n = 0;
                for (; n != full_month.size(); ++n) {
                        if (!full_month[n].compare(str_month))
                                break;
                }
                if (n == full_month.size()) {
                        init();
                        cout << "format(January 1, 1990) error: init" << endl;
                        return;
                } else {
                        month = n + 1;
                }
                day = stoi(info.substr(pos2 + 1, pos22));
                year = stoi(info.substr(pos22 + 1, info.size() -1));

                return;
        } else if (info.find_first_of(' ', pos3 + 1) != std::string::npos) {
                // Jan 1 1990
                vector<string>::size_type n = 0;
                string str_month = info.substr(0, pos3);
                for (; n != abb_month.size(); ++n) {
                        if (!abb_month[n].compare(str_month))
                                break;
                }
                if (n == abb_month.size()) {
                        init();
                        cout << "format(Jan 1 1990) error: init" << endl;
                        return;
                } else if (n < 9) {
                        month = n + 1;
                } else if (n == 9) {
                        month = n;
                } else {
                        month = n - 1;
                }
                pos33 = info.find_first_of(' ', pos3 + 1);
                day = stoi(info.substr(pos3 + 1, pos33));
                year = stoi(info.substr(pos33 + 1, info.size() - 1));
        } else {
                init();
                cout << "other error format: init" << endl;

                return;
        }

        return;
}

测试运行结果:

$ ./my_date
2343
error date format: init
_1.1.1900_
********************
October 21, 2002
_10.21.2002_
********************
2/8/1995
_8.2.1995_
********************
May 12 2011
_5.12.2011_

在windows平台上使用开源软件nodepad++和MinGW自己打造IDE

在win平台上的使用的IDE简介

C/C++的的win平台IDE非常多,对于初学者建议使用轻量级的Dev-c++就非常不错, 当然也可以选择其他的编译器,但建议初学者从简单入手。
dev-c++ 有两个版本,老版本已经不更新了,新版本点这里下载:
dev-C++ 新版调试的时候有可能出现“没有调试信息”调试,解决办法:打开主菜单的“工具”选项,选择“编译”选项,继续选择“代码生成/优化”选项,选择“连接器”选项,在“产生调试信息”选项框内选择“YES”,最后保存退出。
vc6是过期产品,另外有太多与标准不兼容细节,建议抛弃,至于vs2010和vs2013,程序庞大,配置繁琐,下载请自行google。

本文介绍怎样使用nodepad++和MinGW自己打造IDE

why: nodepad++是win平台的非常优秀编辑器,平常查看网上的代码非常方便。并且支持自定义运行程序,网上教程有非常多。

第一步下载程序

Nodepad++ 下载:http://notepad-plus-plus.org/
MinGW网盘下载:mingw-GCC4.6.2,建议下载
dev-C++使用的MinGW: dev-C++使用的MinGW
官方下载:官方下载, 安装需要联网,比较繁琐。
minGW安装:建议安装到C:\根目录下。

MinGW的环境配置

以下配置以MinGW安装到C:\下,压缩文件请解压到该目录。例如:C:\MinGw\ 注意下面是bin目录
桌面上右击“我的电脑”,选择“高级选项配置”,打开”环境变量”,在“系统变量”里双击“Path”变量,在弹出的窗口内末尾后面添加如下代码
如果末尾文本有“;”,则下面代码去除“;”后添加

;c:\MinGW\bin

继续阅读

hangman猜字游戏

C++ primer plus 16.3例题

实际上,书中的例题是有bug的。下面贴出正确的代码

// hangman.cpp -- some string methods
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <cctype>
using std::string;

const int NUM = 26;
const string wordlist[NUM] = {
	"apiary", "beetle", "cereal", "danger", "ensign", "florid", "garage",
	"health", "insult", "jackal", "keeper", "loaner", "manage", "nonce",
	"onset", "plaid", "quilt", "remote", "stolid", "train", "useful",
	"valid", "whence", "xenon", "yearn", "zippy"
};

int main(void)
{
	using std::cout;
	using std::cin;
	using std::tolower;
	using std::endl;

	std::srand(std::time(0));
	char play;
	cout << "Will you play a word game? <y/n> ";
	cin >> play;
	play = tolower(play);
	while (play == 'y') {
		string target = wordlist[std::rand() % NUM];
		int length = target.length();
		string attempt(length, '-');
		string badchars;
		int guesses = 6;
		cout << "Guess may secret word. It has " << length
 			<< " letters, and you guess\n"
			<< "one letter at a time. You get " << guesses
			<< " wrong guesses.\n";
		cout << "Your word: " << attempt << endl;

		while (guesses > 0 && attempt != target) {
			char letter;
			cout << "Guess a letter: ";
			cin >> letter;
			if (badchars.find(letter) != string::npos
				|| attempt.find(letter) != string::npos) {
				cout << "You already guessed that. \
					Try again.\n";
				continue;
			}
			unsigned long loc = target.find(letter);// 这里一定要用unsigned long来声明变量
			if (loc == string::npos) {
				cout << "Oh, bad guess!\n";
				--guesses;
				badchars += letter;	// add to string
			} else {
				cout << "Good guess!\n";
				attempt[loc] = letter;
				// check if letter appears again
				loc = target.find(letter, loc + 1);
				while (loc != string::npos) {
					attempt[loc] = letter;
					loc = target.find(letter, loc + 1);
				}
			}
			cout << "Your word: " << attempt << endl;
			if (attempt != target) {
				if (badchars.length() > 0)
					cout << "Bad choices: " << badchars 
						<< endl;
				cout << guesses << " bad guesses left\n";
			}
		}
		if (guesses > 0)
			cout << "That's right!\n";
		else
			cout << "Sorry, the word is " << target << ".\n";

		cout << "Will you play another? <y/n> ";
		cin >> play;
		play = tolower(play);
	}

	cout << "Bye\n";

	return 0;
}

抽象基类(ABC)的应用

该带码依照 C++ primer plus 第5版 13.6.1应用。

头文件

抽象基类,Brass公有派生类和BrassPlus公有派生类

抽象基类简述

类AcctABC为抽象基类,所谓抽象基类不能生成实例,即不能生成对象。
该类有三个私有成员:分别是名字,银行账户,存款金额。
保护成员方法:显示名字,显示账户,以及显示格式重置函数
公有成员方法:构造函数,存款函数,纯虚取款函数,获取存款金额,纯虚账户信息显示函数,虚拟析构函数(必须设置为虚函数,试指针可以准确定析构对于的对象)

Brass派生类

公有成员方法:构造函数,虚拟取款函数(必须,基类定义为纯虚函数),虚拟账户显示函数(必须,基类定义为纯虚函数),虚拟析构函数

BrassPlus派生类

私用成员:最大贷款金额,贷款利率,还贷金额
公有成员方法: 构造函数,虚拟取款函数(必须,基类定义为纯虚函数),虚拟账户显示函数(必须,基类定义为纯虚函数),虚拟析构函数,以及设置最大贷款金额函数,设置贷款利率函数,设置还贷金额函数。

三个类的头文件

// acctabc.h -- bank account classes
#ifndef ACCTABC_H_
#define ACCTABC_H_

// Abstract Base Class
class AcctABC {
private:
	enum {MAX = 32};
	char fullName[MAX];
	long acctNum;
	double balance;
protected:
	const char * FullName(void) const {return fullName;}
	long AcctNum(void) const {return acctNum;}
	std::ios_base::fmtflags SetFormat(void) const;
public:
	AcctABC(const char * s = "Nullbody", long an = -1, double bal = 0.0);
	void Deposit(double amt);
	virtual void Withdraw(double amt) = 0; 	// pure virtual function
	double Balance(void) const {return balance;}
	virtual void ViewAcct(void) const = 0;	// pure virtual function
	virtual ~AcctABC(void) {}
};

// Brass Account Class
class Brass: public AcctABC {
public:
	Brass(const char * s = "NullBody", long an = -1, 
		double bal = 0.0): AcctABC(s, an, bal) {}
	virtual void Withdraw(double amt);
	virtual void ViewAcct(void) const;
	virtual ~Brass(void) {}
};

// Brass Plus Account Class
class BrassPlus: public AcctABC {
private:
	double maxLoan;
	double rate;
	double owesBank;
public:
	BrassPlus(const char * s = "Nullbody", long an = -1, 
		double bal = 0.0, double ml = 500, 
		double r = 0.1);
	BrassPlus(const AcctABC & ba, double ml = 500, double r = 0.1);
	virtual void ViewAcct(void) const;
	virtual void Withdraw(double amt);
	void ResetMax(double m) {maxLoan = m;}
	void ResetRate(double r) {rate = r;}
	void ResetOwes(void) {owesBank = 0;}
};

#endif//ACCTABC_H_

继续阅读

函数声明,原型与定义

函数声明

函数原型能告诉编译程序一个函数将接受什么样的参数,将返回什么样的返回值,这样编译程序就能检查对函数的调用是否正确,是否存在错误的类型转换。函数声明加上分号就是函数原型。函数原型通常放在主函数之前。

函数定义

即函数实现代码,参数传值(变量的值或变量的地址)

函数调用

主程序函数调用,编译器检查函数调用原型,与原型符合,则进入函数定义中执行代码。执行完毕后返回。

函数原型演示:

下面是等同的函数原型。

int sum(int a[], int n);
int sum(int *a, int n);
int sum(int [], int);
int sum(int *, int);

压栈和出栈的类方法演示

什么是堆栈

堆栈(英语:stack),也可直接称栈。台湾作堆叠,在计算机科学中,是一种特殊的串行形式的数据结构,它的特殊之处在于只能允许在链结串行或阵列的一端(称为堆叠顶端指标,英语:top)进行加入资料(英语:push)和输出资料(英语:pop)的运算。另外堆叠也可以用一维阵列或连结串行的形式来完成。堆叠的另外一个相对的操作方式称为伫列。

由于堆叠数据结构只允许在一端进行操作,因而按照后进先出(LIFO, Last In First Out)的原理运作。

堆叠数据结构使用两种基本操作:推入(push)和弹出(pop):

推入:将数据放入堆叠的顶端(阵列形式或串行形式),堆叠顶端top指标加一。
弹出:将顶端数据资料输出(回传),堆叠顶端资料减一。

类方法演示

程序分三个部分:头文件定义类(包括类数据和类方法原型);类实现部分(类方法定义);程序演示部分(演示压栈和出栈行为)

头文件stack.h

// stack.h -- class definition for the stack ADT
#ifndef STACK_H_
#define STACK_H_

typedef unsigned long Item;

class Stack {
private:
        enum {MAX = 10};        // constant specific to class
        Item items[MAX];        // holds stack items
        int top;                // index for top stack item
public:
        Stack(void);
        bool isempty(void) const;
        bool isfull(void) const;
        // push() returns false if stack already is full, true otherwise
        bool push(const Item & item);   // add item to stack
        // pop() returns false if stack already is empty, true otherwise
        bool pop(Item & item);          // pop top into item
};

#endif//STACK_H_

类方法定义

// stack.cpp -- Stack member functions
#include "stack.h"

Stack::Stack(void)      // create an empty stack
{
        top = 0;

        return;
}

bool Stack::isempty(void) const
{
        return top == 0;
}

bool Stack::isfull(void) const
{
        return top == MAX;
}

bool Stack::push(const Item & item)
{
        if (top < MAX) {
                items[top++] = item;
                return true;
        } else {
                return false;
        }
}

bool Stack::pop(Item & item)
{
        if (top > 0) {
                item = items[--top];
                return true;
        } else {
                return false;
        }
}

继续阅读

C++ primer plus 第7章 7.16程序修复版本

7.16程序修复版本

第五版原书的代码是无法显示如下图的所示的。

|                                                               |
|                                                               |
|                               |                               |
|               |               |               |               |
|       |       |       |       |       |       |       |       |
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

代码使用了递归。
经过测试,修复代码如下:

#include <iostream>
const int Len = 66;
const int Divs = 6;

void subdivide(char arr[], int low, int high, int level);

int main(void)
{
	char ruler[Len];

	int i;
	for (i = 1; i < Len - 2; i++)
		ruler[i] = ' ';
	ruler[Len - 1] = '\n';
	ruler[Len] = '\0';
	
	int max = Len - 2;
	int min = 0;

	ruler[min] = ruler[max] = '|';
	std::cout << ruler;

	for (i = 0; i <= Divs; i++) {
		subdivide(ruler, min, max, i);
		std::cout << ruler;
		for (int j = 1; j < Len - 2; j++)
			ruler[j] = ' ';			// reset to blank ruler
	}

	return 0;
}

void subdivide(char arr[], int low, int high, int level)
{
	if (level == 0)
		return;
	int mid = (high + low) / 2;
	arr[mid] = '|';

	subdivide(arr, low, mid, level - 1);
	subdivide(arr, mid, high, level - 1);

	return;
}

自己编写的string类

基本上是照着视频写的, 但是使用了自己的算法

功能如下:
/****************************************************************************
*
* 1. 可对字符串初始化
* mystring s1 = “hello world”;
* 2. 可计算字符串的长度
* cout < < s1.get_len() << endl; * 3. 可对字符串进行赋值运算 * mystring s2; * s2 = s1; * 4. 可以重载运算符"<<"输出字符串, 并且可以级联输出 * cout << s1 << s2 <>”输入字符串, 并且可以级联输入
* cin >> s1 >> s2;
* 6. 可将char形字符串直接赋值给mystring形字符串
* char ch[] = “not at all”;
* s1 = ch;
* 7. 可以像构造对象定义字符串
* mystring s3; //定义一个空字符串
* mystring s4(“mother”); //定义一个非空字符串
* 8. 可以通过下标运算符操作字符串
* cout < < s3[999] << endl; //越界安全保护 * 9. 可以比较两个mystring类字符串, 如:s1 == s2, s1 < s2, s1 > s2
* cout < < s3 < s4 ? s3 : s4 << endl; * 10.可以将两个字符串相加 * s3 = s1 + s2; * cout << s3 << endl; * 11.可执行+=操作 * s1+=s2; * cout << s1 << endl; * 12.可以根据字符串的大小自动保存字符串数组的大小 * *******************************************************************************/

继续阅读