1.FALSE/TRUE与false/true的区别:
false/true是标准C++语言里新增的关键字,而FALSE/TRUE是通过#define,这要用途
是解决程序在C与C++中环境的差异,以下是FALSE/TRUE在windef.h的定义:
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
也就是说FALSE/TRUE是int类型,而false/true是bool类型;所以两者不一样的,只不过
我们在使用中没有这种感觉,因为C++会帮你做隐式转换。
2.bool的大小与BOOL的区别:
bool在C++里是占用1字节,而BOOL是int类型,int类型的大小是视具体环境而定的;所以
来说:false/true只占用1个字节,而TRUE/FALSE视具体环境而言,以下是BOOL在windef
.h中的定义:typedef int BOOL;
3.NULL与0的区别:
还是让我们看一下windef.h中NULL的定义:
#ifndef NULL
#ifdef __cplusplus//这个是指示是用C++来编译程序
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
所以说:它们没有区别,只不过在C里面会做一个强制类型转换。
sheng00 的所有文章
sscanf 特别用法(转)
C程序里面有什么函数吗?
printf( "%sn", buf );
}
其中的format可以是一个或多个 {%[*] [width] [{h | l | I64 | L}]type | ‘ ‘ | ‘t’ | ‘n’ | 非%符号},
char buf[20];
printf( "%sn", buf );
简单常识――关于stream
从文件中读入一行
简单,这样就行了:
ifstream ifs("input.txt");
char buf[1000];
ifs.getline(buf, sizeof buf);
string input(buf);
当然,这样没有错,但是包含不必要的繁琐和拷贝,况且,如果一行超过1000个字符,就必须用一个循环和更麻烦的缓冲管理。下面这样岂不是更简单?
string input;
input.reserve(1000);
ifstream ifs("input.txt");
getline(ifs, input);
不仅简单,而且安全,因为全局函数 getline 会帮你处理缓冲区用完之类的麻烦,如果你不希望空间分配发生的太频繁,只需要多 reserve 一点空间。
这就是“简单常识”的含义,很多东西已经在那里,只是我一直没去用。
—————————————————————————
一次把整个文件读入一个 string
我希望你的答案不要是这样:
string input;
while( !ifs.eof() )
{
string line;
getline(ifs, line);
input.append(line).append(1, ‘n’);
}
当然了,没有错,它能工作,但是下面的办法是不是更加符合 C++ 的精神呢?
string input(
istreambuf_iterator<char>(instream.rdbuf()),
istreambuf_iterator<char>()
);
同样,事先分配空间对于性能可能有潜在的好处:
string input;
input.reserve(10000);
input.assign(
istreambuf_iterator<char>(ifs.rdbuf()),
istreambuf_iterator<char>()
);
很简单,不是么?但是这些却是我们经常忽略的事实。
补充一下,这样干是有问题的:
string input;
input.assign(
istream_iterator<char>(ifs),
istream_iterator<char>()
);
因为它会忽略所有的分隔符,你会得到一个纯“字符”的字符串。最后,如果你只是想把一个文件的内容读到另一个流,那没有比这更快的了:
fstream fs("temp.txt");
cout << fs.rdbuf();
因此,如果你要手工 copy 文件,这是最好的(如果不用操作系统的 API):
ifstream ifs("in.txt");
ofstream ofs("out.txt");
ofs << in.rdbuf();
————————————————————————-
open 一个文件的那些选项
ios::in Open file for reading
ios::out Open file for writing
ios::ate Initial position: end of file
ios::app Every output is appended at the end of file
ios::trunc If the file already existed it is erased
ios::binary Binary mode
————————————————————————-
还有 ios 的那些 flag
flag effect if set ios_base::boolalpha input/output bool objects as alphabetic names (true, false). ios_base::dec input/output integer in decimal base format. ios_base::fixed output floating point values in fixed-point notation. ios_base::hex input/output integer in hexadecimal base format. ios_base::internal the output is filled at an internal point enlarging the output up to the field width. ios_base::left the output is filled at the end enlarging the output up to the field width. ios_base::oct input/output integer in octal base format. ios_base::right the output is filled at the beginning enlarging the output up to the field width. ios_base::scientific output floating-point values in scientific notation. ios_base::showbase output integer values preceded by the numeric base. ios_base::showpoint output floating-point values including always the decimal point. ios_base::showpos output non-negative numeric preceded by a plus sign (+). ios_base::skipws skip leading whitespaces on certain input operations. ios_base::unitbuf flush output after each inserting operation. ios_base::uppercase output uppercase letters replacing certain lowercase letters.
There are also defined three other constants that can be used as masks:
constant value ios_base::adjustfield left | right | internal ios_base::basefield dec | oct | hex ios_base::floatfield scientific | fixed
————————————————————————–
用我想要的分隔符来解析一个字符串,以及从流中读取数据
这曾经是一个需要不少麻烦的话题,由于其常用而显得尤其麻烦,但是其实 getline 可以做得不错:
getline(cin, s, ‘;’);
while ( s != "quit" )
{
cout << s << endl;
getline(cin, s, ‘;’);
}
简单吧?不过注意,由于这个时候 getline 只把 ; 作为分隔符,所以你需要用 ;quit; 来结束输入,否则 getline 会把前后的空格和回车都读入 s ,当然,这个问题可以在代码里面解决。
同样,对于简单的字符串解析,我们是不大需要动用什么 Tokenizer 之类的东西了:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
string s("hello,world, this is a sentence; and a word, end.");
stringstream ss(s);
for ( ; ; )
{
string token;
getline(ss, token, ‘,’);
if ( ss.fail() ) break;
cout << token << endl;
}
}
输出:
hello
world
this is a sentence; and a word
end.
很漂亮不是么?不过这么干的缺陷在于,只有一个字符可以作为分隔符。
————————————————————————–
把原本输出到屏幕的东西输出到文件,不用到处去把 cout 改成 fs
#include <fstream>
{
ofstream outf("out.txt");
streambuf *strm_buf=cout.rdbuf();
cout.rdbuf(outf.rdbuf());
cout<<"write something to file"<<endl;
cout.rdbuf(strm_buf); //recover
cout<<"display something on screen"<<endl;
system("PAUSE");
return 0;
}
输出到屏幕的是:
display something on screen
输出到文件的是:
write something to file
也就是说,只要改变 ostream 的 rdbuf ,就可以重定向了,但是这招对 fstream 和 stringstream 都没用。
————————————————————————–
关于 istream_iterator 和 ostream_iterator
经典的 ostream_iterator 例子,就是用 copy 来输出:
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
vector<int> vect;
for ( int i = 1; i <= 9; ++i )
vect.push_back(i);
copy(vect.begin(), vect.end(),
ostream_iterator<int>(cout, " ")
);
cout << endl;
ostream_iterator<double> os_iter(cout, " ~ ");
*os_iter = 1.0;
os_iter++;
*os_iter = 2.0;
*os_iter = 3.0;
}
输出:
1 2 3 4 5 6 7 8 9
1 ~ 2 ~ 3 ~
很明显,ostream_iterator 的作用就是允许对 stream 做 iterator 的操作,从而让算法可以施加于 stream 之上,这也是 STL 的精华。与前面的“读取文件”相结合,我们得到了显示一个文件最方便的办法:
copy(istreambuf_iterator<char>(ifs.rdbuf()),
istreambuf_iterator<char>(),
ostreambuf_iterator<char>(cout)
);
同样,如果你用下面的语句,得到的会是没有分隔符的输出:
copy(istream_iterator<char>(ifs),
istream_iterator<char>(),
ostream_iterator<char>(cout)
);
那多半不是你要的结果。如果你硬是想用 istream_iterator 而不是 istreambuf_iterator 呢?还是有办法:
copy(istream_iterator<char>(ifs >> noskipws),
istream_iterator<char>(),
ostream_iterator<char>(cout)
);
但是这样不是推荐方法,它的效率比第一种低不少。
如果一个文件 temp.txt 的内容是下面这样,那么我的这个从文件中把数据读入 vector 的方法应该会让你印象深刻。
12345 234 567
89 10
程序:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
ifstream ifs("temp.txt");
vector<int> vect;
vect.assign(istream_iterator<int>(ifs),
istream_iterator<int>()
);
copy(vect.begin(), vect.end(), ostream_iterator<int>(cout, " "));
}
输出:
12345 234 567 89 10
很酷不是么?判断文件结束、移动文件指针之类的苦工都有 istream_iterator 代劳了。
———————————————————————–
其它算法配合 iterator
计算文件行数:
int line_count =
count(istreambuf_iterator<char>(ifs.rdbuf()),
istreambuf_iterator<char>(),
‘n’);
当然确切地说,这是在计算文件中回车符的数量,同理,你也可以计算文件中任何字符的数量,或者某个 token 的数量:
int token_count =
count(istream_iterator<string>(ifs),
istream_iterator<string>(),
"#include");
注意上面计算的是 “#include” 作为一个 token 的数量,如果它和其他的字符连起来,是不算数的。
————————————————————————
Manipulator
Manipulator 是什么?简单的说,就是一个接受一个 stream 作为参数,并且返回一个 stream 的函数,比如上面的 unskipws ,它的定义是这样的:
inline ios_base&
noskipws(ios_base& __base)
{
__base.unsetf(ios_base::skipws);
return __base;
}
这里它用了更通用的 ios_base 。知道了这一点,你大概不会对自己写一个 manipulator 有什么恐惧感了,下面这个无聊的 manipulator 会忽略 stream 遇到第一个分号之前所有的输入(包括那个分号):
template <class charT, class traits>
inline std::basic_istream<charT, traits>&
ignoreToSemicolon (std::basic_istream<charT, traits>& s)
{
s.ignore(std::numeric_limits<int>::max(), s.widen(‘;’));
return s;
}
不过注意,它不会忽略以后的分号,因为 ignore 只执行了一次。更通用一点,manipulator 也可以接受参数的,下面这个就是 ignoreToSemicolon 的通用版本,它接受一个参数, stream 会忽略遇到第一个该参数之前的所有输入,写起来稍微麻烦一点:
struct IgnoreTo {
char ignoreTo;
IgnoreTo(char c) : ignoreTo(c)
{}
};
std::istream& operator >> (std::istream& s, const IgnoreTo& manip)
{
s.ignore(std::numeric_limits<int>::max(), s.widen(manip.ignoreTo));
return s;
}
但是用法差不多:
copy(istream_iterator<char>(ifs >> noskipws >> IgnoreTo(‘;’)),
istream_iterator<char>(),
ostream_iterator<char>(cout)
);
其效果跟 IgnoreToSemicolon 一样。
关于Linux下C/C++程序编译
在编译之前我们需要在系统里安装G++ GCC,它们就是Linux下的C++/C的编译器。代码如下
代码:
sudo apt-get install build-essential
好,现在我们在文本编辑器里写一个C的简单的程序(好像所有学习C或者C++的书都会出现)
代码:
#include <stdio.h>
int main()
{
printf("Hello,World!n");
return 0;
}
现在存盘为Hello.c,打开你的终端,并在文件当前目录输入:
代码:
gcc Hello.c -o hello
编译时可能会出现如下警告:no newline at and of file ,只有在文件结尾添加一个新行就好了。
然后在终端中输入 ./hello ,你就能在终端中看到程序运行结果了。
下面来说下C++是如何编译的
写程序(不用我多说了吧)
代码:
#include <iostream>
using namespace std;
int main()
{
cout<<"Hello,World!n"<<endl;
return 0;
}
存盘为Hello.cpp
使用gcc编译??? 不对,这里我们使用g++来编译C++程序
代码:
g++ Hello.cpp -o hello
编译多个文件我们怎么办??? 来看下面出了三个文件Hello.h, Hello.cpp, MyFirst.cpp
代码:
//file_NO1:Hello.h
class Hello {
Hello();
void Display();
}
//file_NO2:Hello.cpp
#include <iostream>
#include "Hello.h"
using namespace std;
Hello::Hello()
{
}
Hello::Display()
{
cout<<"Hello,World!n"<<endl;
}
//file_NO3:MyFirst.cpp
#include <iostram>
#include "Hello.cpp"
int main()
{
Hello theHello;
theHello->Display();
return 0;
}
在g++中有一个参数-c 可以只编译不连接,那么我们就可以按如下顺序编译文件,
代码:
g++ -c Hello.cpp -o Hello.o
g++ -c MyFirst.cpp -o MyFirst.o
g++ MyFirst.o hello.o -o MyFirst
你是否会问,如果是一个项目的话,可能会有上百个文件,这样的编译法,人不是要累死在电脑前吗,或者等到你编译成功了,岂不是头发都白了,呵呵,所以我们要把上述的编译过程写进以下一个文本文件中:
Linux下称之为makefile
[code]
#这里可以写一些文件的说明
MyFirst: MyFirst.o hello.o
g++ MyFirst.o hello.o -o MyFirst
Hello.o:Hello.cpp
g++ -c Hello.cpp -o Hello.o
MyFirst.o:MyFirst.cpp
g++ -c MyFirst.cpp -o MyFirst.o
[code]
存盘为MyFirst,在终端输入:make MyFist ,程序出现了错误可是所有程序员共同的敌人,在编写程序时我们应该尽量的去避免错误 的出现,不过编写的时候再怎么都不可避免的出现这样那样的错误,对程序进行必要的调试是一个好主意,那我们怎么来调试程序呢,看下面:
[code]
gdb ./文件名
[/code]
以下为调试状态下的可以用到的命令(可以仅输入单词的输入,如break可简为b),尖括号中为说明
[code]
list <显示源代码>
break 行号 <设置断点>
run <运行程序>
continue <继续从断点处执行>
print 变量 <调试时查看变量的值>
del 行号 <删除断点>
step <单步执行,可跟踪到函数内部>
next <单步执行,不可跟踪到函数内部>
quit <退出>
[/code]