C++:简单计算器与排序

两个小程序

包含两个小程序,一个对数字进行计算的(也可以对其他可用类型),第二个是排序的.

C++.
image-2210

计算的小程序


// Example program
#include
#include
#include
using namespace std;

//加减乘除运算.

int main()
{
/*
template struct plus {
T operator() (const T& x, const T& y) const {return x+y;}
typedef T first_argument_type;
typedef T second_argument_type;
typedef T result_type;
};

例如:上面是plus的原型,可以看出其中重载了加法运算.(其他的类似)
更多可以参考:http://www.cplusplus.com/reference/functional/plus/ [应查看c++ 11的示例]
*/
plus age;
minus gre;
multiplies nums;
divides ds;
negate ne;
modulus modu;
///////////////////////////////
cout << "add:" << age(10,20) << endl; cout << "minus:" << gre(100,50) << endl; cout << "mulitplies:" << nums(50,100) << endl; cout << "divides:" << ds(100,2) << endl; cout << "negate:" << ne(100) << endl; cout << "modulus:" << modu(100,10) << endl; return 0; }

逆序排序

下面的程序其实使用了上面程序中的匿名negate对象(negate会倒置传入的值).

negate原型如下:


template struct negate {
T operator() (const T& x) const {return -x;}
typedef T argument_type;
typedef T result_type;
};
//更多可参考:http://www.cplusplus.com/reference/functional/negate/

程序如下:

// Example program
#include
#include
#include
#include
using namespace std;

//逆序排列vector中的元素

int main()
{
vector vec={5,20,70,6,100,658,50,3,1558,1,85217,0};
sort(vec.begin(),vec.end(),greater());
for_each(vec.begin(),vec.end(),[](const int &is){cout << is << " " ;}); cout << endl; return 0; }

C++:可调用对象与function

一点东西

题目也可以是函数表(用于存储指向可调用对象的”指针”).


//普通函数
int add(int i,int j){ return i+j; }
//lambda,其产生一个未命名的函数对象类.
auto mod = [](const int &i,const int &j){ return i+j; }
//函数对象类.
struct divide{
int operator()(int denominator,int divisor)
{
return denominator / divisor;
}
};

上面这些可调用对象,虽然类型不同,但是共享同一种调用形式:

int(int,int)

可以定义一个函数表,用于存储指向这些可调用对象的”指针”.当程序需要执行某个特定的操作时,
从表中查找该调用的函数.

在C++中,函数表很容易通过map来实现.

简单意思就是将与int(int,int)一样的类型,放入一个map中,将其的操作作为map的主键.

形如:

map["+"]=add;//add是一个函数指针.
map["-"]=minus;//同add的含义一样.
map["*"]=..
以此类推..

C++.
image-2208

代码实现

下面的代码可以运行,推荐一个在线运行的网址:CPP.SH


// Example program
#include
#include
#include

#include
using namespace std;

/*
//普通函数
int add(int i,int j){ return i+j; }
//lambda,其产生一个未命名的函数对象类.
auto mod = [](const int &i,const int &j){ return i+j; }
//函数对象类.
struct divide{
int operator()(int denominator,int divisor)
{
return denominator / divisor;
}
};

上面这些可调用对象,虽然类型不同,但是共享同一种调用形式:
int(int,int)

可以定义一个函数表,用于存储指向这些可调用对象的"指针".当程序需要执行某个特定的操作时,
从表中查找该调用的函数.

在C++中,函数表很容易通过map来实现.

*/
int add(int i,int j){
return i+j;
}

struct divide{
int operator()(int denominator,int divisor)
{
return denominator / divisor;
}
};

int main()
{
auto mod = [](const int &i,const int &j){ return i+j; };
map binops;
binops.insert({"+",add});
//但是我们不能将mod或者divide存入binops.因为mod不是一个函数指针.
//问题在于mod是个lambda表达式,而每个lambda有它自己的类类型,该类型与存储在binops中的值得类型不匹配.

//解决办法如下:
//使用一个名为function的新的标准库类型解决上述问题.

/*function f1 = add;//函数指针
function f2 = divide();//函数对象类的对象.
function f3 = [](int i,int j){ return i * j ; }; //lambda

cout << f1(4,2) << endl; cout << f2(4,2) << endl; cout << f3(4,2) << endl;*/ //使用function类型我们可以重新定义map. map> binops2={
{"+",add}, //函数指针.
{"-",std::minus()}, //标准库函数对象
{"/",divide()}, //用户定义的函数对象.
{"*",[](int i,int j){ return i * j ;}}, //未命名的lambda
{"%",mod} //命名了的lambda对象
};

cout << "10+5=" << binops2["+"](10,5) << endl;//调用add(10,5) cout << "10-5=" << binops2["-"](10,5) << endl;//调用minus
cout << "10/5=" << binops2["/"](10,5) << endl;//调用divide cout << "10*5=" << binops2["*"](10,5) << endl;//调用lambda cout << "10%5=" << binops2["%"](10,5) << endl;//调用lambda /* 我们不能(直接)将重载函数的名字存入function类型的对象中: int add(int i,int j){return i+j;} Sales_data add(const Sales_data&,const Sales_data&); map> binops3;
binops3.insert({"+",add}); //错误:哪个add?

解决上述二义性的问题是存储函数指针而非函数的名字:

int (*fp)(int,int) =add; //指针所指的add是接受两个int的版本.
binops3.insert({"+",fp}); //正确:fp指向一个正确的add版本

同样,也可以用lambda来消除二义性:

//正确:使用lambda来指定我们希望使用的add版本
binops3.insert({"+",[](int a,int b){return add(a,b);}});

*/

return 0;
}

C++:解析迅雷下载地址

一个简单的说明

其实看完这个文章你会发现实现这些真的很简单,假如你问我为什么前缀要用C++(已用多语言实现),我只能说:当你用C++去解析这些的时候,你会体验到“前所未有”的“快感(痛楚)”。

大多数语言都已经实现了的功能,在C++上却要自己动手去实现。不得不说,这或许是它到目前为止还受欢迎的原因之一吧。

原理

迅雷的下载地址是用base64实现加密的,所以,你尽可以去搜索:语言+base64(当然了,C/C++的实现会让你头晕)。

C++.
image-2157

C++实现

说明一下,时间仓促,这段代码来自网络。待日后研究透彻了,在来说原理吧。


#include
using namespace std;

/**

迅雷下载地址解码--因环境因素,未实际运行.

*/

static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static inline bool is_base64(unsigned char c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
}

std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++) char_array_4[i] = base64_chars.find(char_array_4[i]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (i = 0; (i < 3); i++) ret += char_array_3[i]; i = 0; } } if (i) { for (j = i; j <4; j++) char_array_4[j] = 0; for (j = 0; j <4; j++) char_array_4[j] = base64_chars.find(char_array_4[j]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; } return ret; } int main() { //未完善:请输入去掉[thunder://]之后的部分 string thunders; cin >> thunders;
string base64url = base64_decode(thunders).replace(0,2,"");
cout << base64url << endl; return 0; }

python Logo
image-2158

python实现


#!/usr/bin/env python
# coding=utf-8

#-*-coding:utf-8-*-

'''

python-version:2.7.5

解析迅雷下载地址.

输入一个迅雷下载的地址,可以打印到控制台,也可以输出到文件.

1.现在默认打印到控制台.
2.输出到文件请取消 #1,#2,#3的注释,对齐代码并为#5添加注释.

'''

import os
import base64

__author__='puruidong'
__date__='2014.8.14'

print u"输入一个迅雷下载的地址:\n"
th=raw_input()
if(th.find("thunder://")!=-1):
#1 fs=open("D:\/py\/test.txt","wb")
th=th.replace("thunder://","")
decodeurl=base64.b64decode(th)
urls=decodeurl[2:len(decodeurl)]
print u"\n\n转换结果:\n"+urls #5
#2 fs.write(urls)
#3 fs.close()
else:
print u"\n\n错误提示:不是标准的迅雷下载地址!!"

java标志
image-2159

Java实现


import sun.misc.BASE64Decoder;
import java.util.Scanner;

/**
* 迅雷下载地址转换.
*
*
* Created by puruidong on 2014/8/13.
*/
public class Test {
public static void main(String[] args)throws Exception {
System.out.println("输入一个迅雷下载地址:");
Scanner sc = new Scanner(System.in);
String thunder = sc.next();
if(thunder.indexOf("thunder://")!=-1) {
thunder = thunder.replaceAll("thunder://", "");
BASE64Decoder base = new BASE64Decoder();
String urls = new String(base.decodeBuffer(thunder));
urls = urls.substring(2, urls.length());
System.out.println("转换结果:"+urls);
}else
{
System.err.println("错误提示:不是标准的迅雷下载地址!");
}
}
}

其余未完善的部分,后面在研究吧。

C++:动态内存管理

很久没写

之前有个笑话,是说:几个程序员去餐厅吃饭,那个会把盘子放回原地的一定是C/C++程序员,因为他们要自己清理内存.

好了,来上题目.

编写函数,返回一个动态分配的int的vector.将此vector传递给另一个函数,这个函数读取标准输入,将读入的值保存在vector元素中.再将vector传递给另一个函数.打印读入的值.记得在恰当的时候delete vector.

小心:动态内存管理容易出错

使用new和delete管理动态内存存在三个问题:

  1. 忘记delete内存,会导致内存泄漏,而且不容易发现.
  2. 使用已经释放掉的对象.有时可以检测出这种错误.
  3. 同一块内存释放两次.

相对于发现“罪证”,制造“罪证”显然容易多了。

C++.
image-2150

源代码


/*************************************************************************
> File Name: test.12.6.cpp
> Author: puruidong
> Mail: 1@w1520.com
> Created Time: 2014年07月25日
************************************************************************/

#include
#include
#include
using namespace std;

/************************************

编写函数,返回一个动态分配的int的vector.将此vector传递给另一个函数,这个函数读取标准输入,将读入的值保存在vector元素中.再将vector传递给另一个函数.打印读入的值.记得在恰当的时候delete vector.

*********************************************/

//输出vector中的内容,并释放内存
void outputvector(vector* vec)
{
cout << "\noutputvector\n" << endl; for(const auto &n:*vec) { cout << n << endl; } delete vec;//一定要释放内存. /* 下面这一行代码是为了避免"空悬指针"的出现而 添加的. 执行下面这一行代码之后,vec将不能再次使用. */ vec=nullptr; //报错.cout << vec->size() << endl; } //获取动态vector. vector* getve()
{
vector *vec=new vector;
return vec;
}

//接收标准输入.
void inputvector()
{
vector *vec=getve();
int pa ;
cout << "动态内存分配,请输入数字:" << endl; while(cin >> pa)
{
vec->push_back(pa);
}
outputvector(vec);
}

int main()
{
inputvector();
return 0;
}

C++:单词计数

问题

单词计数程序,有序和无序版本.

C++.
image-2147

有序源码


/*************************************************************************
> File Name: test.11.39.cpp
> Author: puruidong
> Mail: 1@w1520.com
> Created Time: 2014年07月15日
************************************************************************/

#include
#include

using namespace std;

/*********************************

单词计数程序,字典序.

*****************************************/

int main()
{
cout << "单词计数程序,字典序:" << endl; map map;
string pa;
while(cin >> pa)
{
++map[pa];
}
cout << "输出计算结果:" << endl; for(const auto &s : map) { cout << s.first << " ------ " << s.second << endl; } return 0; }

无序源码


/*************************************************************************
> File Name: test.11.38.cpp
> Author: puruidong
> Mail: 1@w1520.com
> Created Time: 2014年07月15日
************************************************************************/

#include
#include
#include
using namespace std;

/*****************************************

用unordered_map重写单词计数程序

**************************************************/

int main()
{
unordered_map map;
string pa;
while(cin >> pa)
{
++map[pa];//自增.
}
cout << "***********************\n统计结果:\n******************************" << endl; for(const auto &s : map) { cout << s.first << "\t************************\t" << s.second << endl; } cout << "输出桶的数目:" << map.bucket_count() << endl; cout << "最大能容纳的最多的桶的数量:" << map.max_bucket_count() << endl; cout << "第1个桶中有多少个元素:" << map.bucket_size(1) << endl; cout << "关键字a在哪个桶中:" << map.bucket("a") << endl; cout << "每个桶的平均元素数量:" << map.load_factor() << endl; cout << "容器试图维护的平均桶大小:" << map.max_load_factor() << endl; return 0; }