2.9字符专题
2.9.1类型同义词
也就是typedef声明,这个东西就是相当于起绰号,为了方便记忆和简化而生。相信在学习其他语言的时候一定有所了解,在此不再赘述。
再次示例一个之前写过的用typedef改写的程序:
/*************************************************************************
> File Name: char_count.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年05月24日 星期六 21时15分10秒
************************************************************************/
#include <iomanip>
#include <ios>
#include<iostream>
#include<string>
#include <map>
using namespace std;
//Counting Words, Restricting Words to Letters and Letter-like Characters
int main()
{
typedef map<string, int> count_map;
typedef count_map::iterator count_iter;
typedef string::size_type str_size;
count_map counts;
string word;
// Read words from the standard input and count the number of times
// each word occurs.
string okay("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789-_");
while (cin >> word)
{
// Make a copy of word, keeping only the characters that appear in okay.
string copy;
for (string::iterator w(word.begin()); w != word.end(); ++w)
if (okay.find(*w) != string::npos)
copy.push_back(*w);
// The "word" might be all punctuation, so the copy would be empty.
// Don't count empty strings.
if (not copy.empty())
++counts[copy];
}
// Determine the longest word.
str_size longest(0);
for (count_iter iter(counts.begin()); iter != counts.end(); ++iter)
if (iter->first.size() > longest)
longest = iter->first.size();
// For each word/count pair...
const int count_size(10); // Number of places for printing the count
for (count_iter iter(counts.begin()); iter != counts.end(); ++iter)
// Print the word, count, newline. Keep the columns neatly aligned.
cout << setw(longest) << left << iter->first <<
setw(count_size) << right << iter->second << '\n';
return 0;
}
2.9.2字符
字符I/O
get函数一次读取一个字符,且不会对空白字符做特殊处理。也可以使用标准输入操作符实现同样的效果,但是必须同时使用std::skipws操作子。恢复默认行为的时候使用std::skipws操作子。
程序示例:
/*************************************************************************
> File Name: char_io.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年05月24日 星期六 16时29分46秒
************************************************************************/
#include<ios>
#include<iostream>
#include<string>
using namespace std;
// 下面代码中的get函数和noskipws操作子具体作用请自行查阅资料吧。
// 其实就是为了处理空白字符。
int main()
{
// cin >> noskipws;
char ch;
while(cin.get(ch))
cout << ch;
return 0;
}
结果如下:
现在进行一个小练习,假设程序需要读入一系列的点。分别用x,y坐标定义,并以逗号隔开。在每个数字前面、后面以及逗号周围允许有空白。将点分别读入保存x值的向量和保存y的向量,如果点后面没有正确的逗号则结束输入循环。打印向量的内容,每行一个点。
示例代码:
/*************************************************************************
> File Name: char_exc.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年05月24日 星期六 16时41分56秒
************************************************************************/
#include <algorithm>
#include<iostream>
#include<string>
#include <limits>
#include <vector>
using namespace std;
int main()
{
typedef vector<int> intvec;
typedef intvec::iterator iterator;
intvec xs, ys; // store the xs and ys
{
// local block to keep I/O variables local
int x(0), y(0); // variables for I/O
char sep(' ');
// Loop while the input stream has an integer (x), a character (sep),
// and another integer (y); then test that the separator is a comma.
// 当读入的分隔符不是逗号的时候,结束输入,开始输出
while (cin >> x >> sep and sep == ',' and cin >> y)
{
xs.push_back(x);
ys.push_back(y);
}
}
cout << "The data you input are: " << endl;
for (iterator x(xs.begin()), y(ys.begin()); x != xs.end(); ++x, ++y)
std::cout << *x << ',' << *y << '\n';
return 0;
}
结果如下:
转义字符
再次仅仅贴一下几个常用的转义字符,具体转义字符用法什么的,请自行查阅资料吧,这个真真的是最基础的编程语言知识。
字符本地化
说到字符我们必然想到不同的国家的字符不同,英语有26个字母,但是德国法国等国家还有其他的一些字符,比如下面图的那些字符,我们要如何处理呢,好在C++提供了一个函数,可以告知我们那些字符是一个字母,:
下面示例一个程序,使用isalnum来替代调用find函数:
/*************************************************************************
> File Name: char_isalnum.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年05月26日 星期日 10时13分27秒
************************************************************************/
/** Testing a Character by Calling isalnum */
#include <iostream>
#include <istream>
#include <locale>
#include <map>
#include <ostream>
#include <string>
int main()
{
using namespace std;
typedef map<string, int> count_map;
typedef count_map::iterator count_iter;
count_map counts;
string word;
// Read words from the standard input and count the number of times
// each word occurs.
while (cin >> word)
{
// Make a copy of word, keeping only alphabetic characters.
string copy;
for (string::iterator w(word.begin()); w != word.end(); ++w)
if (isalnum(*w, locale("")))
copy.push_back(*w);
// The "word" might be all punctuation, so the copy would be empty.
// Don't count empty strings.
if (not copy.empty())
++counts[copy];
}
// For each word/count pair, print the word & count on one line.
for (count_iter iter(counts.begin()); iter != counts.end(); ++iter)
cout << iter->first << '\t' << iter->second << '\n';
return 0;
}
注意上面的isalnum函数里面的第二个参数locale():isalnum使用该参数指定的区域设置确定测试字符使用的字符集。字符集根据字符的数值确定它的标识。当程序运行时候,用户可以改变字符集,因此程序必须跟踪用户实际的字符集,而不能依赖编译程序运行时的有效字符集。
在C++中,区域设置(locale)是关于文化、地域、和语言信息的集合。区域设置包含的信息如下:
- l 格式化数字、货币、日期、时间
- l 分类字符
- l 字符大小写转换
- l 文本排序
- l 消息目录(用于翻译程序所使用的字符串)
每个C++程序都以最小的、标准区域设置开始,成为经典(classic)区域设置或者C语言设置。函数std::locale::classic()返回经典区域设置。未命名的区域设置(std::locale(“”)注意分号)是C++从操作系统获得的用户首选项。使用空字符串参数的区域设置成为本地区域设置。
经典区域设置的优点是他的行为已知并且是确定的,如果你的程序必须以固定格式读取数据,那么你就不想受用户首选项的影响。相反,本地区域设置格式的优点是由于某种原因设置首选项,并且想让程序以首选项的格式输出。习惯指定日期格式的某地的用户不想被指定为另外地区的格式。
因此,经典格式经常用于读写数据文件,本地格式用于翻译用户输入,并且将输出直接呈献给用户。
每个I/O流都有自己的locale对象,要改变流的locale,可以调用他的imbue函数,将locale对象作为唯一的参数传入。
换言之,在C++启动的时候,他会用经典区域设置初始化每个流,如:
std::cin.imbue(std::locale::classic());
std::cout.imbue(std::locale::classic());
加入要改变输出流使其采用用户的本地区域设置,可以在程序的开始使用下面的语句:
std::cout.imbue(std::locale(""));
当使用本地区域设置时,推荐定义一个类型为std::locale的变量,用于存储本地区域设置。可以将该变量传给isalnum、imbue或者其他的函数。通过创建此变量并分发他的副本,程序只需要向操作系统查询一次用户首选项,而非每次都需要查询。
改写的程序如下:
/** Creating and sharing a single locale object. */
#include <iostream>
#include <istream>
#include <locale>
#include <map>
#include <ostream>
#include <string>
int main()
{
using namespace std;
typedef map<string, int> count_map;
typedef count_map::iterator count_iter;
locale native(""); // get the native locale
cin.imbue(native); // interpret the input and output according to
cout.imbue(native); // the native locale
count_map counts;
string word;
// Read words from the standard input and count the number of times
// each word occurs.
while (cin >> word)
{
// Make a copy of word, keeping only alphabetic characters.
string copy;
for (string::iterator w(word.begin()); w != word.end(); ++w)
if (isalnum(*w, native))
copy.push_back(*w);
// The "word" might be all punctuation, so the copy would be empty.
// Don't count empty strings.
if (not copy.empty())
++counts[copy];
}
// For each word/count pair, print the word & count on one line.
for (count_iter iter(counts.begin()); iter != counts.end(); ++iter)
cout << iter->first << '\t' << iter->second << '\n';
return 0;
}
大小写转换
简单的大小写转换
任务:改写单词计数程序,将大写转换为小写并计算所有单词出现的次数。
示例代码如下:
/** Folding Uppercase to Lowercase Prior to Counting Words */
#include <iostream>
#include <istream>
#include <locale>
#include <map>
#include <ostream>
#include <string>
int main()
{
using namespace std;
typedef map<string, int> count_map;
typedef count_map::iterator count_iter;
locale native(""); // get the native locale
cin.imbue(native); // interpret the input and output according to
cout.imbue(native); // the native locale
count_map counts;
string word;
// Read words from the standard input and count the number of times
// each word occurs.
while (cin >> word)
{
// Make a copy of word, keeping only alphabetic characters.
string copy;
for (string::iterator w(word.begin()); w != word.end(); ++w)
if (isalnum(*w, native))
copy.push_back(tolower(*w, native));
// The "word" might be all punctuation, so the copy would be empty.
// Don't count empty strings.
if (not copy.empty())
++counts[copy];
}
// For each word/count pair, print the word & count on one line.
for (count_iter iter(counts.begin()); iter != counts.end(); ++iter)
cout << iter->first << '\t' << iter->second << '\n';
return 0;
}
稍微复杂的大小写转换
一提到复杂就会想到涉及到了地域字符集的转换,这一部分先不说吧,确实有点复杂。
3.0函数专题
1、关于函数
关于什么是函数,函数的定义和声明什么的和C语言的差不多,再次不再细细的说了。
2、再练单词计数
使用函数改写的程序如下:
/*************************************************************************
> File Name: char_count_founction.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年05月25日 星期日 20时13分27秒
************************************************************************/
#include<iomanip>
#include<ios>
#include<iostream>
#include<locale>
#include<map>
#include<string>
using namespace std;
// Using Functions to Clarify the Word-Counting Program
typedef map<std::string, int> count_map; ///< Map words to counts
typedef count_map::iterator count_iter; ///< Iterate over a @c count_map
typedef string::size_type str_size; ///< String size type
/** Initialize the I/O streams by imbuing them with
* the given locale. Use this function to imbue the streams
* with the native locale. C++ initially imbues streams with
* the classic locale.
* @param locale the native locale
*/
void initialize_streams(std::locale locale)
{
cin.imbue(locale);
cout.imbue(locale);
}
/** Find the longest key in a map.
* @param map the map to search
* @returns the size of the longest key in @p map
*/
str_size get_longest_key(count_map map)
{
str_size result(0);
for (count_iter iter(map.begin()); iter != map.end(); ++iter)
if (iter->first.size() > result)
result = iter->first.size();
return result;
}
/** Print the word, count, newline. Keep the columns neatly aligned.
* Rather than the tedious operation of measuring the magnitude of all
* the counts and then determining the necessary number of columns, just
* use a sufficiently large value for the counts column.
* @param iter an iterator that points to the word/count pair
* @param longest the size of the longest key; pad all keys to this size
*/
void print_pair(count_iter iter, str_size longest)
{
const int count_size(10); // Number of places for printing the count
cout << setw(longest) << left << iter->first <<
setw(count_size) << right << iter->second << '\n';
}
/** Print the results in neat columns.
* @param counts the map of all the counts
*/
void print_counts(count_map counts)
{
str_size longest(get_longest_key(counts));
// For each word/count pair...
for (count_iter iter(counts.begin()); iter != counts.end(); ++iter)
print_pair(iter, longest);
}
/** Sanitize a string by keeping only alphabetic characters.
* @param str the original string
* @param loc the locale used to test the characters
* @return a santized copy of the string
*/
string sanitize(string str, locale loc)
{
string result;
for (string::iterator s(str.begin()); s != str.end(); ++s)
if (isalnum(*s, loc))
result.push_back(tolower(*s, loc));
return result;
}
/** Main program to count unique words in the standard input. */
int main()
{
locale native(""); // get the native locale
initialize_streams(native);
count_map counts;
string word;
// Read words from the standard input and count the number of times
// each word occurs.
while (std::cin >> word)
{
string copy(sanitize(word, native));
// The "word" might be all punctuation, so the copy would be empty.
// Don't count empty strings.
if (not copy.empty())
++counts[copy];
}
print_counts(counts);
return 0;
}
注释文档使用的格式是Doxygen.
3.函数参数
函数实参
有三种传递方式:按值传递,按引用传递、实参传递,
关于这三种传递的特性,不再赘述。
首先实参传递的示例:
/*************************************************************************
> File Name: list2001_argument_parameter.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年05月27日 星期二 10时25分48秒
************************************************************************/
#include<algorithm>
#include<iostream>
#include<iterator>
#include<string>
#include<vector>
using namespace std;
// function
void modify(int x)
{
x =10;
}
int triple(int x)
{
return 3*x;
}
void print_vector(vector<int> v)
{
cout << "{" ;
copy (v.begin(), v.end(), ostream_iterator<int>(cout," "));
cout << "}\n";
}
void add(vector<int> v, int a)
{
for(vector<int>::iterator iter(v.begin()); iter!=v.end(); ++iter)
{
*iter = *iter *a ;
}
}
int main()
{
int a(42);
modify(a);
cout << "a" << a << endl;
vector<int> data;
data.push_back(10);
data.push_back(20);
data.push_back(30);
data.push_back(40);
print_vector(data);
add(data, 30);
print_vector(data);
return 0;
}
结果如下:
按引用传递
/*************************************************************************
> File Name: list2002_reference.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年05月27日 星期二 10时46分28秒
************************************************************************/
#include<algorithm>
#include<iostream>
#include<iterator>
#include<string>
#include<vector>
using namespace std;
// function
void modify(int& x)
{
x =10;
}
/**当triple的参数为引用时候,不可以直接调用triple(14).
*一言以蔽之,不能给数字赋值,只能给变量赋值.
*在C++术语中,粗略的讲,变量出现在赋值的左侧时称为左值.仅能出现在赋值的右侧的称为右值.
*整数字面量是一个很好的右值的例子.
*/
int triple(int x)
{
return 3*x;
}
/**按引用传递值,并且阻止函数改变参数.
*@const& v 声明参数v为不可变类型
*参数从右往左读,首先是参数v,然后他是一个引用,引用的是一个const对象
*/
void print_vector(vector<int> const& v)
{
cout << "{" ;
// copy (v.begin(), v.end(), ostream_iterator<int>(cout," "));
string separator("");
// 取代上面的ostream_iterator, 使用const_iterator,可以防止向量的内容被改变,
// 同时有可以实现迭代.
for(vector<int>const_iterator i(v.begin()); i!=v.end(); i++ )
{
cout << *i << separator ;
separator = ", ";
}
cout << "}\n";
}
void add(vector<int>& v, int a)
{
for(vector<int>::iterator iter(v.begin()); iter!=v.end(); ++iter)
{
*iter = *iter *a ;
}
}
int main()
{
int a(42);
modify(a);
cout << "a" << a << endl;
vector<int> data;
data.push_back(10);
data.push_back(20);
data.push_back(30);
data.push_back(40);
print_vector(data);
add(data, 30);
print_vector(data);
return 0;
}
结果如下:
3.1.函数重载
在讲解重载之前,需要讲一下有关简单的C++其他标准算法。
现在我们使用算法重写单词计数程序,使用transform将字符转换为小写,使用remove_if算法除去字符串中的非字母字符,remove_if算法对于序列中的每个元素调用一个函数,如果函数返回trueremove_if从序列中删除该元素(其实比没有删除)。不过C++中迭代器的的工作原理的有一个副作用,就是这个函数并没有真正的删除该元素,而是重新组织了这个序列,返回了超出需要保存的元素的末端的下一个位置。
原理如下图:
具体部分代码如下:
/** Sanitizing a String by Transforming It */
/** Test for non-letter.
* @param ch the character to test
* @return true if @p ch is not a character that makes up a word
*/
bool non_letter(char ch)
{
return not isalnum(ch, std::locale());
}
/** Convert to lowercase.
* Use a canonical form by converting to uppercase first,
* and then to lowercase.
* @param ch the character to test
* @return the character converted to lowercase
*/
char lowercase(char ch)
{
return std::tolower(ch, std::locale());
}
/** Sanitize a string by keeping only alphabetic characters.
* @param str the original string
* @return a santized copy of the string
*/
std::string sanitize(std::string str)
{
// Remove all non-letters from the string, and then erase them.
str.erase(std::remove_if(str.begin(), str.end(), non_letter),
str.end());
// Convert the remnants of the string to lowercase.
std::transform(str.begin(), str.end(), str.begin(), lowercase);
return str;
}
关于谓词:
首先上面的那个的bool non_letter(char ch)函数是一个谓词的例子,谓词是一个返回bool结果的函数。具体的请参阅相关资料,不再深入探讨。
其他的算法:
回文测试我们应该很熟悉,下面用C++实现。
代码如下:
/*************************************************************************
> File Name: word_pal.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年05月30日 星期五 20时26分41秒
************************************************************************/
#include<algorithm>
#include<iostream>
#include<iterator>
#include<locale>
#include<string>
using namespace std;
/** 测试非字母
* @param ch 带测试的字符
* @return 如果@p ch 不是字母返回true
*/
bool non_letter(char ch)
{
return not isalpha(ch, locale());
}
/** 转换为小写
* 使用规范形式,先转换为大写,后转换为小写.
* @param ch 待测试的字符
* @return 转换后的字符
*/
char lowercase(char ch)
{
return tolower(ch, locale());
}
/** 比较两个字符,不考虑大小写 */
bool same_char(char a, char b)
{
return lowercase(a) == lowercase(b);
}
/** 确定@p str 是否包含回文
* 只测试字母,不包括空格和标点
* 空字符串不是回文
* @param str 带测试的回文
* @return 当@p str 顺读和倒读都一样的时候返回true
*/
bool is_palindrome(string str)
{
string::iterator end(remove_if(str.begin(), str.end(), non_letter));
string rev(str.begin(), end);
reverse(rev.begin(), rev.end());
return not rev.empty() and equal(str.begin(), end, rev.begin(), same_char);
}
int main()
{
locale::global(locale(""));
cin.imbue(locale());
cout.imbue(locale());
string line ;
while(getline(cin, line))
{
if(is_palindrome(line))
{
cout << "这是一个回文: " << line << endl;
}
}
return 0;
}
重载
关于函数的重载和其他的高级语言一样样的。所以,我们会在以后的程序中再讲。。。。哈哈哈哈。
3.2回到数字
3.2.1长整型&短整型
使用number_limits获取整数的位数。
代码如下:
/*************************************************************************
> File Name: list2301_int.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年06月03日 星期二 15时38分25秒
************************************************************************/
/** Discovering the Number of Bits in an Integer */
#include<iostream>
#include <limits>
#include<string>
using namespace std;
// numeric_limits获得整数的位数,并有一个返回值is_signed,即当数字有符号时返回true
int main()
{
cout << "bits per int = ";
if (numeric_limits<int>::is_signed) // 如果有符号,加一,加上符号位
cout << numeric_limits<int>::digits + 1 << '\n';
else // 否则直接输出
cout << numeric_limits<int>::digits << '\n';
cout << "bits per bool = ";
if (numeric_limits<bool>::is_signed)
cout << numeric_limits<bool>::digits + 1 << '\n';
else
cout << numeric_limits<bool>::digits << '\n';
return 0;
}
下面的代码可以显示短整型和长整型的所占的位数:
/*************************************************************************
> File Name: list2302_long.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年06月03日 星期二 15时44分42秒
************************************************************************/
/** Revealing the Number of Bits in Short and Long Integers */
#include<iostream>
#include <limits>
#include<string>
using namespace std;
int main()
{
cout << "bits per int = ";
if (numeric_limits<int>::is_signed)
cout << numeric_limits<int>::digits + 1 << '\n';
else
cout << numeric_limits<int>::digits << '\n';
cout << "bits per bool = ";
if (numeric_limits<bool>::is_signed)
cout << numeric_limits<bool>::digits + 1 << '\n';
else
cout << numeric_limits<bool>::digits << '\n';
cout << "bits per short int = ";
if (numeric_limits<short>::is_signed)
cout << numeric_limits<short>::digits + 1 << '\n';
else
cout << numeric_limits<short>::digits << '\n';
cout << "bits per long int = ";
if (numeric_limits<long>::is_signed)
cout << numeric_limits<long>::digits + 1 << '\n';
else
cout << numeric_limits<long>::digits << '\n';
cout << "bits per long long int = ";
if (numeric_limits<long long>::is_signed)
cout << numeric_limits<long long>::digits + 1 << '\n';
else
cout << numeric_limits<long long>::digits << '\n';
return 0;
}
下面我们就可以演示一下重载了,顺便说明一下类型转换。
代码如下:
/*************************************************************************
> File Name: list2303_print_overide.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年06月03日 星期二 16时08分45秒
************************************************************************/
/** Using Type Casts */
// 重载print函数,输出不同的数值类型
#include<iostream>
#include <locale>
#include<string>
using namespace std;
typedef signed char byte;
void print(byte b)
{
// 操作符<<将signed char 当作变异的char,并尝试打印一个字符
// 为了将该值打印为一个整数,必须将其转换为整数类型
// static_cast() 表达式称为类型转换
cout << "byte=" << static_cast<int>(b) << '\n';
}
void print(short s)
{
cout << "short=" << s << '\n';
}
void print(int i)
{
cout << "int=" << i << '\n';
}
void print(long l)
{
cout << "long=" << l << '\n';
}
int main()
{
cout.imbue(locale(""));
print(0);
print(0L);
print(static_cast<short>(0));
print(static_cast<byte>(0));
print(static_cast<byte>(255)); // -1
print(static_cast<short>(65535)); // -1
print(32768);
print(32768L);
print(-32768);
print(2147483647);
print(-2147483647);
// The following lines might work on your system.
// If you are feeling adventuresome, uncomment the next 3 lines:
print(2147483648); // long类型
print(9223372036854775807);
print(-9223372036854775807);
return 0;
}
下面一个程序再次演示重载函数,同时演示类型转换和类型提升的区别。
代码如下:
/*************************************************************************
> File Name: list2303_typePromotion.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年06月03日 星期二 16时17分39秒
************************************************************************/
/** Overloading Prefers Type Promotion over Type Conversion */
/** 类型转换
* 类型转换分为两步.
* 当使用signed char和short类型时,编译器总是将他们转换为int,然后执行运算.这被称为类型提升.
* 但是,对于一组重载函数且编译器需要知道调用哪个时,编译器首先做的事情是找一个精确的匹配,
* 如果找不到,就会考虑类型提升之后的匹配,仅当这种匹配也失败的时候,才会搜索类型转换后能够匹配上的.
* 因此,编译器优先考虑基于类型提升的匹配.
*/
// 具体如下面的程序.
#include<iostream>
#include<string>
using namespace std;
// print is overloaded for signed char, short, int and long
void print(signed char b)
{
cout << "print(signed char = " << static_cast<int>(b) << ")\n";
}
void print(short s)
{
cout << "print(short = " << s << ")\n";
}
void print(int i)
{
cout << "print(int = " << i << ")\n";
}
void print(long l)
{
cout << "print(long = " << l << ")\n";
}
// guess is overloaded for bool, int, and long
void guess(bool b)
{
cout << "guess(bool = " << b << ")\n";
}
void guess(int i)
{
cout << "guess(int = " << i << ")\n";
}
void guess(long l)
{
cout << "guess(long = " << l << ")\n";
}
// error is overloaded for bool and long
void error(bool b)
{
cout << "error(bool = " << b << ")\n";
}
void error(long l)
{
cout << "error(long = " << l << ")\n";
}
int main()
{
signed char byte(10);
short shrt(20);
int i(30);
long lng(40);
// 精确匹配各个类型
cout << "第一次匹配的结果" << endl;
print(byte);
print(shrt);
print(i);
print(lng);
// 前三个都自动提升为int类型
// 因为guess函数没有相应的类型参数,所以无法精确匹配,需要提升类型
cout << "第二次匹配的结果" << endl;
guess(byte);
guess(shrt);
guess(i);
guess(lng);
// 由于error参数没有相应的类型,所以需要类型提升,先将signed char和short
// 提升为int类型,但是guess没有int类型的参数,需要进行类型转换,此时guess函数中
// 参数有long和bool两种,而类型转换,编译器认为所有转换的优先级相同,所以,此时编译器不知道
// 该转换为long还是bool,即是不知道该调用那一个guess函数,因此会出现错误.
// 要避免错误,只需要添加一个guess函数,参数为int即可.
cout << "第三次匹配失败的结果" << endl;
// error(byte); // expected error
// error(shrt); // expected error
// error(i); // expected error
error(lng);
return 0;
}
结果如下:
3.2.1浮点数&定点数
首先用下面的代码演示浮点数的一些特性:
/*************************************************************************
> File Name: list2401_float.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年06月03日 星期二 17时14分59秒
************************************************************************/
/** Floating-Point Numbers Do Not Always Behave as You Expect */
#include<iostream>
#include<string>
#include <cassert>
using namespace std;
// 浮点数的比较!显示出浮点数在精度上的注意事项.
int main()
{
float a(0.03f);
float b(10.0f);
float c(0.3f);
cout << "a*b = " << a*b << endl;
cout << "c = " << c << endl;
assert(1 == 1);
return 0;
}
结果如下:
下面演示三种浮点数格式的输出:
/*************************************************************************
> File Name: list2401_float_print.cpp
> Author: suool
> Mail: 1020935219@qq.com
> Created Time: 2014年06月03日 星期二 17时29分32秒
************************************************************************/
/** Demonstrating Floating-Point Output */
// 浮点数输出示例,三种格式的浮点数输出.
#include <ios>
#include<iostream>
#include<string>
using namespace std;
/// Print a floating-point number in three different formats.
/// @param precision the precision to use when printing @p value
/// @param value the floating-point number to print
void print(int precision, float value)
{
cout.precision(precision);
cout << "科学计数法格式输出" << endl;
cout << scientific << value << '\n';
cout << "定点数格式输出" << endl;
cout << fixed << value << '\n';
// Set the format to general.
cout.unsetf(ios_base::floatfield);
cout << "一般格式输出"<< endl;
cout << value << '\n';
}
/// Main program.
int main()
{
print(6, 123456.789f);
print(4, 1.23456789f);
print(2, 123456789.f);
print(5, -1234.5678e9f);
return 0;
}
/*
三种格式的浮点数输出说明
首先是precision(int)的说明:
关于setprecision(int),MSDN上的解释为:
即当输出的数据类型为浮点型时,setprecision(int)表示设置输出数的有效位数,
当输出的是定点数或用科学计数法表示的数时,setprecison(int)表示设置输出数小数点后的位数。
故通常控制浮点数输出时小数点后的位数的做法为:先将要输出的数设置为定点数,然后使用setprecision(int).
然后关于科学格式:
指数被打印为e或者E,随后是基数为10的指数.且指数有符号,即使指数为0,也至少有两位数字
关于定点格式:
不打印指数,小数点前有多少位打印多少位,小数点总是被打印,精度取决与小数点后的数字的位数.
关于默认格式:
如果指数小于或者等于-4,或者说大于精度,数字会以科学格式打印.
否则,以无指数格式打印,但是不像传统的定点输出,小数点后的0会被移除.
需要时,值会以四舍五入的来适应分配的精度.
*/
结果如下:
Over, 第一部分C++基础!
第三部分预计会推迟几天,,要复习,快考试了。。