??xml version="1.0" encoding="utf-8" standalone="yes"?>
define中的#?#Q?br>Q?Q?可以define中的参数转化为字W串Q例如:(x)
#define PRINT(x) printf(#x “ is %d”, x);
Q?Q?#可以define中的参数转化为某个标识符的一部分Q例如:(x)
int tmp_a = 23;
#define PRINT(x) printf(#x “ is %d”, tmp_##x);
define的位|:(x)
宏定义可以出现在所有函数外部或者某函数内部Q遵循两个规则:(x)
W一Q?nbsp;内部定义覆盖外部定义。如果全局的宏定义与某内部宏定义重名时QVC6.0~译器会(x)提示warning但不出错Q且以内部宏定义为准?br>W二Q?nbsp;定义点后均可使用Q不以函数内外划分作用域Q仅以文本中出现位置前后划分?br>
define解析序Q?br>#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
void macrotest(void)
{
printf("%s,",h(f(1,2)));
printf("%s\n",g(f(1,2)));
}
最后答案是Q?2, f(1,2)
分析Q解析一个串从左臛_Q一遍之后再从头开始。所以h(f(1,2)) -> g(f(1,2)) -> g(12) -> 12Q而g(f(1,2)) -> #(f(1,2)) -> f(1,2)?br>
define的缺P(x)
W一Q?nbsp;对于所有的function-like macrosQ所有的参数都要括v来,以防止macros(a+b)的情况出玎ͼ而且要注意是否有cMmacros(i++)的情况出玎ͼ防止在文本替换后i++执行多次?br>W二Q?nbsp;宏不做类型检查,而且预处理展开后消׃无ŞQ编译出错了(jin)很难扑ֈ错误?br>W三Q?nbsp;使用宏后?#8220;函数”不能取址Q不能作为函数指针传递给另一个函数?br>W四Q?nbsp;一般用inline函数代替宏函敎ͼcM的,一般用const变量代替宏变量?br>
2.strncpy和strncat
strncpy(dest, src, size);
使用strncpy(a, b, size)函数ӞҎ(gu)size值分两种情况Q?br>W一Qsize比字W串b长度大时Q将b字符串赋laQ再a中size-b.length的多余位|赋gؓ(f)\0?br>W二Qsize比字W串b长度时Q将size长度的b子字W串赋给aQ但不自动在后面d\0?br>
strncat(dest, src, size);
使用strncat(a, b, size)函数ӞҎ(gu)size值分两种情况Q?br>W一Qsize比字W串b长度大时Q将b字符串赋laW一个\0l束W处Qƈ自动在右面添加\0Q多余的size-b.length位置不赋倹{?br>W二Qsize比字W串b长度时Q将size长度的字W串赋给aW一个\0l束W处Qƈ且自动在后面d\0?br>
3.printf和scanf
printf(“%x, %x, %x”, a, b, c);
printf注意事项Q?br>W一Q?pirntf参数从右向左依次压栈?br>W二Q?nbsp;字符?×和后面参C左至右依ơ映,当参数多出时可忽略不计?br>W三Q?nbsp;字符?×和后面参C左至右依ơ映,?×多出Ӟ打印出来的结果不可预(因ؓ(f)VC下参C叛_左压栈,所以多出的%×只能对应不可预知的内存)(j)?br>
其他
4.rand()函数的最大取值是0X7fffQ也是2?5ơ方-1?br>
5.对于数组char a[100]Qsizeof(a)的值是100Q表C数l大,而sizeof(&a)按道理来说应该是4Q表C指向数la的指针的大小Q但是某些MSVC版本对arrayName?amp;arrayName是不区分的,需要安装sp1的MSVC的补丁才可去掉这个bug?br>
6.C语言中,不写q回cd的函敎ͼ一般默认ؓ(f)int型,而C++中必L明返回类型。但在一般的~译器实CQ可能会(x)做放宽处理,例如VC6.0中可以接受C++函数没有q回cdQ默认ؓ(f)int?br>
7.q回gؓ(f)数组指针
如果函数q回值是int(*)[NUM]cdQ不可写成int(*)[NUM] func() {}的Ş式,而应该写成:(x)
int (*func)() [NUM] {}
或者用typedef来简化:(x)
typedef int(*)[NUM] type;
type func() {}
那么Q如何保存函数的q回值呢Q具体如下:(x)
int a[num1][NUM];
int (*b)[NUM] = &a[num2];
b = func();
8.l构?br>l构体有赋值操作,但是没有比较操作Q可以重?={这些比较运符Q同Ӟ最好别用memcmp函数q行l构体的比较操作Q因考虑到结构体的对齐问题,且填充的字节是随机的?br>
9.函数指针
void func() {}
printf(“%p %p %p”, func, &func, *func);
其结果是一L(fng)Q原因在于:(x)
函数名就是函数名Q除?jin)少量情况,它?x)退化ؓ(f)函数指针Q即发生function-to-pointer转换。fun单独攄的时候就?x)发生退化,而在&fun的情况下不会(x)退化,所以单独的fun?amp;fun的类型、值都一栗?fun则是fun先发生退化,变成函数指针Q?变成函数cdQ然后再退化成函数指针Q所以函数类型怎么*都一栗(maybeQ?br>
10.(int&)a?int)a的区?br>(int&)a不经q{换,直接得到a在内存单元的|(int)a则是a在内存中的D{换成intcdQ那么存在两U情况:(x)
W一Q?nbsp;acd是intQ此?int&)a?int)a是相{的?br>W二Q?nbsp;acd是float{,׃float在内存中存储的Ş式是W号?指数+数Q而阶码采用增码,为数采用源码Q与int的存储Ş式不同?int)a?x)先内存中的D{换成intcdQ然后给aQ?int&)a则直接将内存中的值给aQ不l过转换Q所以此时两者不相等?br>
windows中常用类型:(x)
后来查明具体原因为:(x)ȝE运行太快,DE序在Func1U程打印语句之前已l退Z(jin)。更正方法ؓ(f)在main中创建线EFunc1后添加同步机制WaitForSingleObject(p, INFINITE)?br>
不包含string头文件时Qcout<<str无法q行Q当重新包含string头文件后Qcout<<strq行成功。ؓ(f)什么?Q?
初步设想Qiostream头文仉接导入了(jin)string头文Ӟ但是相当一部分的string操作定义在string头文件中Q例如程序中?lt;<操作W重载,不包含string头文件的话无法用。所以徏议编E时q是d导入string头文件?br>
2.stringcd声明Q?/strong>
string s;
string s(args);
其中args具体参数如下Q?br>str
str, len
chars
chars, len
chars, index, len
n, c
b, e
注意Q对string的操作,既可以用q代器,也可以用下标Q它比容器具有更多的灉|性。以下用b、e和p表示q代器,pos表示下标Qcp表示指向ccdW串的指针?/span>
3.string操作Q?/strong>
=、assign()Q?br>对string对象赋以新倹{?双可以是stringcd、c_stringcd甚至?a'q样的单一字符。用assign()可以更灵zȝ对stringq行赋|例如Q?br>args具体参数如下Q?br>str
str, len
chars
chars, len
chars, index, len
n, c
b, e
swap()Q?br>交换两个字符串的内容Q例如s1.swap(s2)Q注意里面不可以是c_stringcd?br>
+=、append(args)、push_back()Q?br>在尾部添加字W?=后面可以是string、c_string甚至?a'q样的单一字符。其中args具体参数如下Q?br>str
str, len
chars
chars, len
chars, index, len
n, c
b, e
s.push_back('x') //用于每次增加一个字W?br>
insert()Q?br>在string某个位置插入字符Q插入位|在l定的烦(ch)引处。例如s.insert(4, str)。注意,q种形式的insert()函数不支持传入单个字W,要想传入单个字符必须写成字符串的形式?br>s.insert(p, t) //在p前插入元素t
s.insert(p, n, t) //在p前插入n个t
s.insert(p, b, e) //b和e是P代器
s.insert(pos, args)
其中args具体参数如下Q?br>str
str, len
chars
chars, len
chars, index, len
n, c
b, e
erase()Q删除字W?br>s.erase(p) //删除p指向的元素,q回指向该元素后面元素的q代?br>s.erase(b, e) //删除b和e间的元素Q返回指向该元素后面元素的P代器
s.erase(pos, len) //删除pos下标开始的len个字W?br>
clear()Q?br>清空字符Q例如s.clear()Q效果等同于s=""Q但是内部机制是否一h知?br>
replace()Q替换字W?br>s.replace(pos, args)
其中args具体参数如下Q?br>str
str, len
chars
chars, len
chars, index, len
n, c
b, e
同理把前两个参数换成b和e也可以?br>
+Q?br>串联字符丌Ӏ?br>
==?=?lt;?lt;=?gt;?gt;=、compare()Q?br>比较字符Ԍ可以在string与string、string与c_string间进行比较,例如str1 < str2Qs <= "abc"。compare()函数支持多参数处理,支持用烦(ch)引值和长度定位子串来进行比较,q回0表示相等Q正数表C大于,负数表示于Q例如:(x)
s.compare("abcd")
s.compare(s2)
s.compare(pos, len, s2)
s.compare(pos1, len1, s2, pos2, len2)
s.compare(pos, len, "....")
s.compare(pos1, len2, "....", pos2, len2)
size()、length()Q?br>q回字符数量Q两者等效?br>empty()Q?br>判断字符串是否ؓ(f)I?br>max_size()Q?br>q回字符的可能最大个敎ͼ很可能和机器本n的限制或者字W串所在位|连l内存的大小有关pR?br>capacity()Q?br>q回重新分配前的字符定w?br>reserve()Q?br>重置字符定w?br>
[]、at()Q?br>存取单一字符Q不同点在于at()?x)检查烦(ch)引是否有效,x否超?~s.length()-1的范_(d)如果出?x)抛出out_of_range的异常?br>
>>、getline()Q?br>从stream中读取某|其中getline()是读取一行,直到遇到分行W或者文件结?br><<Q?br>某值写入stream?br>
copy()Q?br>某string写入一个既有的c_string中,例如s.copy(chars, s.size())Q得到的字符?span style="COLOR: red">不以"\0"l尾Q需要注意这炏V?br>c_str()Q?br>函数原型是const char* c_str() const{}Q例如s.c_str()返回一个const char*cdQ且?\0"l尾?br>data()Q?br>函数原型是const char* data() const{}Q例如s.data()q回一个const char*cdQ与c_str()不同的是它返回的字符串不?\0"l尾?br>
substr()Q?br>q回某个子字W串?br>s.substr() //q回s的全部内?br>s.substr(pos) //从pos下标开始的所有字W?br>s.substr(pos, len) //从烦(ch)引pos开始的len个字W?br>
begin()、end()Q?br>提供cMSTL的P代器支持?br>rbegin()、rend()Q?br>逆向q代器?br>get_allocator()Q返回配|器?br>
查找函数Q?br>find
rfind
find_first_of
find_last_of
find_first_not_of
find_last_not_of
参数1是被搜寻的对象,参数2指出搜寻L(fng)索引Q可无)(j)Q参?指出搜寻的字W个敎ͼ可无Q,q回值是索引|cd是string::size_typeQ如果没有找到目标,q回string::npos。注意:(x)string::npos的类型是string::size_typeQƈ不是int而是unsigned int?br>参数如下Q?br>c, pos //从pos下标开始查扑֭WcQpos可默认ؓ(f)0
s2, pos //从pos开始查找stringcds2Qpos可默认ؓ(f)0
cp, pos //从pos开始查扑֭W串cpQpos可默认ؓ(f)0
cp, pos, len //查找cp前n个字W,pos和len不可默认
字符函数Q?/strong>
动态内存分配:(x)
字符串函敎ͼ(x)
函数原型Qvoid *memcpy(void *dest, const void *source, size_t count);
q回D明:(x)q回指向dest的void *指针
函数说明Qmemcpy功能和memmove相同Q但是memcpy中dest和source中的区域不能重叠Q否则会(x)出现未知l果?/p>
原型Qchar *strstr(char *haystack, char *needle);
用法Q?include <string.h>
功能Q从字符串haystack中寻找needleW一ơ出现的位置Q不比较l束WNULL)?br>说明Q返回指向第一ơ出现needle位置的指针,如果没找到则q回NULL?/p>
函数原型Qchar * strcpy(char * strDest,const char * strSrc);
char * strcpy(char * strDest,const char * strSrc)
{
if ((strDest==NULL)||(strSrc==NULL))
throw "Invalid argument(s)";
char * strDestCopy=strDest;
while ((*strDest++=*strSrc++)!='\0')
;
return strDestCopy;
}
memcpy和memmove 的区别:(x)
函数memcpy()从source指向的区域向dest指向的区域复制count个字W,如果两数l重叠,不定义该函数的行为。而memmove()如果两函数重叠,赋g正确q行。memcpy函数假设要复制的内存区域不存在重叠,如果你能保你进行复制操作的的内存区域没有Q何重叠,可以直接用memcpyQ如果你不能保证是否有重叠,Z(jin)保复制的正性,你必ȝmemmove。memcpy的效率会(x)比memmove高一些,如果q不明白的话可以看一些两者的实现Q?/p>
void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp, *s;
if (dest <= src)
{
tmp = (char *) dest;
s = (char *) src;
while (count--)
*tmp++ = *s++;
}
Else
{
tmp = (char *) dest + count;
s = (char *) src + count;
while (count--)
*--tmp = *--s;
}
return dest;
}
12.++i与i++
int arr[] = {6,7,8,9,10};
int *ptr = arr;
*(ptr++) +=123;
Print(“%d %d”, *ptr, *(++ptr));
一定要注意求值顺序,*(ptr++) +=123中先做加?+123Q然后ptr++Q此时指针指?Q对于Print(“%d %d”, *ptr, *(++ptr))Q从后往前执行,先做++ptrQ指?Q然后输???br>注:(x)一般禁止在语句中这样?+q算W,因ؓ(f)?x)依赖不同的~译器而有所不同。例如,TC中printf语句从右向左执行QVC6.0中同样从叛_左执行,但是在遇见后增运符a++或者a--时是在整个printf语句后才执行?br>int i=8;
printf("%d\n%d\n%d\n%d\n",++i,--i,i++,i--);
q个函数的输出结果在VC里是8 7 8 8Q在TC里是8 7 7 8?br>int i=3, j;
j = (i++)*(i++);
q个表达式输出j?Qi最后是5Q因Z个i++是在整个q算式之后才q行的?br>int i=3, j;
j = (++i)*(++i);
q个表达式输出j?5Qi最后是5Q因?+i相当于i?后将i攑օ式子中,所以j=i*iQ且i??br>int i=3, j;
printf(“%d %d”, ++i, ++i);
q个表达式输?, 4Qؓ(f)什么两个g一样呢Q因为printf是函敎ͼ?+i传给printf后,相当于打印的是Ş参,而两?+i传入的Ş参不同?br>注:(x)特别要注意宏、运与函数使用i++?+i的情况,Ҏ(gu)让h困惑……
13.
add ( int a, int b )
{
return a + b;
}
int main(int argc, char* argv[])
{
printf ( "2 + 3 = %d", add ( 2, 3) );
return 0;
}
在C语言中,凡不加返回值类型限定的函数Q就?x)被~译器作回整型值处理;C++语言有很严格的类型安全检查,不允怸q情况(指函C加类型声明)(j)发生。可是编译器q不一定这么认定,譬如在Visual C++6.0中上qadd函数的编译无错也无警告且q行正确?br>#include "stdio.h"
int fun()
{
return 1;
}
main()
{
printf("%d",fun(2));
getchar();
}
在C语言中,可以l无参数的函C送Q意类型的参数Q但是在C++~译器中~译同样的代码则?x)出错。所以,无论在Cq是C++中,若函C接受M参数Q一定要指明参数为void?br>按照ANSI(American National Standards Institute)标准Q不能对void指针q行法操作Q即下列操作都是不合法的Q?br>void * pvoid;
pvoid++; //ANSIQ错?br>pvoid += 1; //ANSIQ错?br>ANSI标准之所以这栯定,是因为它坚持Q进行算法操作的指针必须是确定知道其指向数据cd大小的?br>例如Q?br>int *pint;
pint++; //ANSIQ正?br>pint++的结果是使其增大sizeof(int)?br>但是大名鼎鼎的GNU(GNU's Not Unix的羃?则不q么认定Q它指定void *的算法操作与char *一致?br>因此下列语句在GNU~译器中皆正:(x)
pvoid++; //GNUQ正?br>pvoid += 1; //GNUQ正?br>pvoid++的执行结果是其增大了(jin)1?br>在实际的E序设计中,合ANSI标准Qƈ提高E序的可UL性,我们可以q样~写实现同样功能的代码:(x)
void * pvoid;
char* tmp = (char*)pvoid;
tmp++; //ANSIQ正;GNUQ正?br>tmp += 1; //ANSIQ正;GNUQ正?br>GNU和ANSIq有一些区别,M而言QGNU较ANSI?#8220;开?#8221;Q提供了(jin)Ҏ(gu)多语法的支持。但是我们在真实设计Ӟq是应该可能地q合ANSI标准?br>
Q?Q显式链?br>需要函数指针和W(xu)IN32 API函数LoadLibrary、GetProcAddress装蝲Q用这U蝲入方法,不需?lib文g?h头文Ӟ只需?dll文g卛_Q将.dll文g|入工程目录中)(j)?/p>
LoadLibrary函数利用一个名UC为参敎ͼ获得DLL的实例(HINSTANCEcd是实例的句柄Q,通常调用该函数后需要查看一下函数返回是否成功,如果不成功则q回NULLQ句柄无效)(j)Q此时调用函数FreeLibrary释放DLL获得的内存?br>GetProcAddress函数利用DLL的句柄和函数的名UC为参敎ͼq回相应的函数指针,同时必须使用{Q判断函数指针是否ؓ(f)NULLQ如果是则调用函数FreeLibrary释放DLL获得的内存。此后,可以使用函数指针来调用实际的函数?br>最后要记得使用FreeLibrary函数释放内存?br>
注意Q应用程序如何找到DLL文gQ?/span>
使用LoadLibrary昑ּ链接Q那么在函数的参C可以指定DLL文g的完整\径;如果不指定\径,或者进行隐式链接,W(xu)indows遵循下面的搜烦(ch)序来定位DLLQ?br>Q?Q包含EXE文g的目?br>Q?Q工E目?br>Q?QWindowspȝ目录
Q?QWindows目录
Q?Q列在Path环境变量中的一pd目录
return a;
}
一般在使用q回值引用时Q常q回全局变量{无法析构的变量Q例如:(x)
int a = 5; //a是全局变量
int result;
result = Function(); //不会(x)出现warning
int &Function()
{
return a;
}
注意int &Function()的返回值可以充当左|但是如果x是函数的临时变量Q对其进行引用是危险的;所以要保证q回g?x)因函数q回而被析构。如下:(x)
int x = 0; //x是全局变量
int &Function()
{
return x;
}
void main()
{
Function() = 100; //此时x{于100
}
Q?Q指针可以指向NULLQ而引用不能引用NULL?br>Q?Q引用一旦声明,引用的对象不能改变(不能引用其他对象?jin)?j)Q但是引用对象的值可以改变;指针可以随时改变指向的对象,因此说指针更危险Q引用比指针安全。可以说Q引用是在不牺牲性能的情况下Q更安全的利用指针特性所使用的技术?br>Q?Q理Z存在两种必须用指针的情况Q其他情况下用引用而不是指针:(x)
A.可能存在不指向Q何对?NULL)Ӟ使用指针?br>B.需要指向不同对象时Q用指针?br>Q?Q在函数Function(int* &p)中,使用&目的是ؓ(f)?jin)可以改变p指针本nQ其能指向其他对象Q这U用法和Function(int** p)是一L(fng)Q即指向指针的指针?br>
2.const与指?/strong>
Q?Qconst int a = 10与int const a = 10{h(hun)Q同理const int*与int const*是等L(fng)?br>Q?Qconst int *a是指向const对象的指针,不可通过指针改变对象|而int * const a是const指针Q指针只能指向该对象?br>Q?Q指针指向const对象的情?br>const int a = 40;
int *p;
p = &a; //错,~译错误Q?br>p = (int*)&a; //~译通过Q但是p无法改变a的?br>const int *p;
p = &a; //ok
3.const与引?/strong>
非Const引用只能l定C该引用同cd的对象;
Const引用则可l定C同但相关cd的对象或l定到右倹{?br>Q?Qconst对象Q包括常量、常?变量生成的无名(f)时变量)(j)必须用const引用来引用,而反q来const引用可以引用const和非const变量?br>int a = 5;
const int b = 10;
int &ref = a; //ok
int &ref = b; //error
const int &ref = b; //okQ必Mؓ(f)const引用
const int &ref = a; //ok
const int &ref = 5; //okQ必Mؓ(f)const引用
const int &ref = a + 3; //okQ必Mؓ(f)const引用
Q?Qconst引用可以用不同类型的对象初始化,
对于不同cd间的引用Q?br>double a = 3.5;
const int &ref = a;
实际上其工作程是先定义int tmp = (int)aQ然后const int &ref = tmpQ所以必ȝconst引用Q否则会(x)D错误。常?变量生成的无名(f)时变量同理?br>Q?Qconst引用可以指向需要(f)时对象的对象或?br>const int ival = 1024;
const int* &b = &ival; //error
const int* const &b = &ival; //ok
解释是:(x)
typedef const int * P;
P &b = &ival; //errorQ因?amp;ival的g可改变,而b是非帔R指针
P const &b = &ival; //{h(hun)于const P &b = &ival;
大家可以看到Q将二维数组当作参数的时候,必须指明所有维数大或者省略第一l的Q但是不能省略第二维或者更高维的大,q是q译器原理限制的。大家在学编译原理这么课E的时候知道编译器是这样处理数l的Q对于数l:(x)
int p[m][n]Q?br>如果要取p[i][j]的?i>=0 && i<m && 0<=j && j < n)Q编译器是这样寻址的,它的地址为:(x)
p + i*n + j;
从以上可以看出,如果我们省略?jin)第二维或者更高维的大,~译器将不知道如何正的d。但是我们在~写E序的时候却需要用到各个维数都不固定的二维数组作ؓ(f)参数Q这难办了(jin)Q编译器不能识别阿,怎么办呢Q不要着急,~译器虽然不能识别,但是我们完全可以不把它当作一个二l数l,而是把它当作一个普通的指针Q再另外加上两个参数指明各个l数Q然后我们ؓ(f)二维数组手工dQ这样就辑ֈ?jin)将二维数组作?f)函数的参C递的目的Q根据这个思想Q我们可以把l数固定的参数变为维数随即的参数Q例如:(x)
void Func(int array[3][10]);
void Func(int array[][10]);
变ؓ(f)Q?br>void Func(int **array, int m, int n);
在{变后的函CQarray[i][j]q样的式子是不对?不信Q大家可以试一?Q因为编译器不能正确的ؓ(f)它寻址Q所以我们需要模仿编译器的行为把array[i][j]q样的式子手工{变ؓ(f)
*((int*)array + n*i + j);
在调用这L(fng)函数的时候,需要注意一下,如下面的例子Q?br>int a[3][3] =
{
{1, 1, 1},
{2, 2, 2},
{3, 3, 3}
};
Func(a, 3, 3);
Ҏ(gu)不同~译器不同的讄Q可能出现warning 或者error,可以q行强制转换如下调用Q?
Func((int**)a, 3, 3);
补充Q?br>对于最后利用指针代替二l数l的做法E显累赘Q只需要一层的指针卛_Q?br>int a[3][3] =
{
{1, 1, 1},
{2, 2, 2},
{3, 3, 3}
};
函数使用如下Q?br>Func((int*)a, 3, 3);
函数声明如下Q?br>void Func(int *array, int m, int n);
函数中用指针如下:(x)
*(array + n*i + j);
hh.a = 0;
hh.b = -1;
cout << hh.a << endl;
最后的l果是hh.a = 255。原因是hh.b = -1Ӟ低位字节存储11111111Q补码)(j)Q那么整?个字节就?0000000 00000000 00000000 11111111Q即255。(正数的原码、反码、补码都一P负数的原码不变,反码在原码基上取反,补码在原码基上取反加1Q?/p>
注意Q缺省是升序排序Q可以通过函数com改变排序序?br>
sort()定义在在头文?lt;algorithm>中?br>template<typename _RandomAccessIterator>
void __insertion_sort(_RandomAccessIterator __first, _RandomAccessIterator __last)
sort函数是标准模板库的函敎ͼ已知开始和l束的地址卛_q行排序Q可以用于比较Q何容器(必须满随机q代器)(j)QQ何元素,M条gQ执行速度一般比qsort要快。具体事例如下:(x)
注意Q缺省是升序排序。sort中一个改变排序顺序的例子如下Q?/p>
《The C++ Programming Language?《C++E序设计语言?br>最新版本:(x)W三版特别版
UTC++PLQ有其他语言的丰富经验的。(也有人简UC?#8220;TCPL”Q但需与另一本《The C Programmer Language》区分开来)(j)
《Essential C++?br>《Accelerated C++?br>q两本薄一些,都是不错的选择。《Accelerated C++》本人没有读q,从各斚w的评h看,完全值得推荐?/p>
以上几本书都有相应的中文版,而且译的质量都不错。上面的书未必都需要读一遍,但无论如何,TC++PL是应该阅ȝ?br>
Q二Q进阶AQ?/strong>
q个路线侧重于语a本n
《Effective C++?br>最新版本:(x)W二版(W三版国外已上架Q国内一些网上书店也在预订中Q?br>UEC。C++E序员必读!很多时候,我们说C++圣经不是指TC++PLQ而是q一本。《The Pragmatic Programmer》一书中写到Q?#8220;一旦你发现自己要参与C++目的开发,赶快跑(不要赎ͼ(j)C店去购买Scott Mayer的《Effective C++》,可能q要《More Effective C++?#8221;?/p>
《C++ Coding Standards: 101 Rules, Guidelines, and Best Practices?《C++ ~程规范?br>个h认ؓ(f)此书应ؓ(f)C++E序员必备的案头书。几乎Effectivepd和Exceptionalpd都在q里得到?jin)ȝ。最新的模版、异常的业界l验都在q里的到?jin)体现。可能的唯一~陷是对一个新手而言Q关?#8220;Z么这么做”的问题,解释的不够?br>我的看法是:(x)如果你不理解其中的条ƾ,记忆Qƈ且照做;如果你理解其中的条款Q我猜你一定会(x)同意书中的观炏V我认ؓ(f)q本书中的内容至在2009q以前都不会(x)q时Qh们将qؓ(f)传诵它制定的101条戒律?br>q不知道他的Uͼ也许“101”?x)成Z个候选者?
提到《Effective C++》,那么另外三本书一一出水面Q?br>《More Effective C++?br>《Exceptional C++?br>《More Exceptional C++》?br>C《Exceptional C++ Style》也是值得一看的好书?br>上述几本书,一本也不应该放q?br>个h上述书籍按顺序阅诅Rƈ且,在将来反复阅读这几本书?br>
Q三Q进阶BQ?/strong>
q个路线侧重于程序库?
《The C++ Standard Library?《C++标准E序库—自修教E与参考手册?br>听说qSTL吗?q本书会(x)教你最基本的,也是最重要的STL的用。这本书Q应该是必读的?/p>
《Effective STL?br>?x)用STLq不够,q必ȝ道什么时候选择什么STLlgQ这是STL使用的必M?/p>
《Generic Programming and the STL: Using and Extending the C++ Standard Template Library?《泛型编E与STL》?br>q本书理论性较强,但是真的很严谨,而且q不是非帔R懂。理解其中对于Concept的解释,是非常重要的?
《C++ STL?br>q不是讲qC用程序库的,而是讲述E序库实现原理的。肠胃不好的Q需要慢慢吸收?/p>
q个路线的书Q仍然是按顺序阅诅R?br>q阶A、进阶B两个路线应该是可以ƈ行的?br>
其他q阶参考书
提出q些参考书Q只是避免争议,也ؓ(f)开阔视野,W者ƈ不曾完全读过所有的?/p>
《Thinking in C++?《C++~程思想?br>q本书及(qing)其中文版传言好坏都有Q没有认真看q,不做评h(hun)Q如果确有兴,不妨试一下该书?/p>
以下几本书基本上涉及(qing)的都是语a本nQ大体上可以按照以下的顺序阅诅R?/p>
《C++必知必会(x)?br>如果早一q_(d)q本书将是重量的,然而它?01和《Exceptional C++ Style》盖q一头?/p>
《C++ Gotchas: Avoiding Common Problems in Coding and Design?《C++E序设计陷阱?br>q又是一本我未曾读过Q而且q受好评的书?/p>
《STL 源码剖析?br>q本书我刚到手,p??赎ͼ以至于到现在也没有看q。看q这本书的朋友,可以l一个合适的评h(hun)?
高Q?br>《The Design and Evolution of C++?《C++语方的设计和演化?br>UD&EQ内容ƈ不艰深,Bjarne的书Q仅此,值得一诅R?br>前段旉Q互动网?块一本(人民币)(j)贱卖此书Q现在好像没?jin)?/p>
《Inside The C++ Object Model?《深度探索C++对象模型?br>CE序员读后一定会(x)觉得C++原来q不秘?/p>
《C++ Template?br>在阅读STL、Boost或者Loki的源代码之前Q请仔细阅读本书Q它可以减轻一些阅ȝ?ch)恼。这本书是讨论C++模版的权威?
《Modern C++ Design Generic Programming and Design Patterns Applied?《C++设计新思维——泛型编E与设计模式之应用?br>UMCD。在阅读MCD之前Q徏议先阅读一下《C++ Template》?/p>
《对象揭U:(x)Java、Eiffel和C++?br>你对C++不满吗?q本书可以部分地帮你完成抱怨的目标。也许它q可以让你不q信C++?/p>
最后,一份C++标准文档也是应该加以咀嚼的?
q有一些书c,q不能简单的归于C++Q也难以在纯_的书本学习(fn)中加以掌握。《Design Patterns?《设计模式》一书就归于此类?/p>
所有上q的书籍Q要么谈论C++语言本nQ要么谈论STL的,要么D有之(当然严格讲STL也是C++语言非常重要的一部分Q。偶?dng),某些书中条目也?x)涉及(qing)实际工程。这些书q不是C++软g开发的全部Q但是他们很重要。阅读这些书Q未必需要化费太多的_֊Q有时候是?x)困难,但也有时候会(x)很快速?br>最后,~程语言q计算机科学技术的全部Q尤其对于在校的学生来说Q打好基、开阔视野都是非帔R要的?
其中各参数说明如下:(x)
llpThreadAttributesQ指向一?SECURITY_ATTRIBUTES l构的指针,该结构决定了(jin)U程的安全属性,一般置?NULLQ?
ldwStackSizeQ指定了(jin)U程的堆栈深度,一般都讄?Q表C线E堆栈大与创徏它的U程相同Q?
llpStartAddressQ表C新U程开始执行时代码所在函数的地址Q即U程的v始地址。一般情况ؓ(f)(LPTHREAD_START_ROUTINE)ThreadFuncQThreadFunc 是线E函数名Q函数原型如下:(x)
DWORD WINAPI threadfunc(LPVOID param);
llpParameterQ指定了(jin)U程执行时传送给U程?2位参敎ͼ即线E函数的参数Q?
ldwCreationFlagsQ控制线E创建的附加标志Q可以取两种倹{如果该参数?Q线E在被创建后׃(x)立即开始执行;如果该参Cؓ(f)CREATE_SUSPENDED,则系l生线E后Q该U程处于挂v状态,q不马上执行Q直臛_数ResumeThread被调用;
llpThreadIdQ该参数q回所创徏U程的IDQ?/p>
2.U程(zhn)挂和恢复:(x)创徏新的U程后,该线E就开始启动执行。但如果在dwCreationFlags中用了(jin)CREATE_SUSPENDEDҎ(gu),U程q不马上执行Q而是先挂P{到调用ResumeThread后才开始启动线E?/p>
3.U程优先U操作:(x)
4.U程退出:(x)当调用线E的函数q回后,U程自动l止?/p>
注意Q?br>(1)TerminateThread函数可能?x)引L(fng)l不E_Q而且U程所占用的资源也不释放。因此,一般情况下Q徏议不要用该函数? 各参数如下:(x) 注意Q?br>(1)使用TerminateThread后,需调用CloseHandle( )函数释放U程所占用的堆栈?br>(2)释放资源后,线EHANDLE|成NULL?br>
(2)如果要终止的U程是进E内的最后一个线E,则线E被l止后相应的q程也应l止?
(3)释放资源后,线EHANDLE|成NULL?br>(4)使用TerminateThread后,需调用CloseHandle( )函数释放U程所占用的堆栈?/span>
MFC下多U程~程之工作线E编E?/strong>
1.U程创徏Q?/p>
CWinThread*AfxBeginThread(
AFX_THREADPROC pfnThreadProc,
LPVOID pParam,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);
l参数pfnThreadProc是线E执行体函数Q函数原形ؓ(f): UINT ThreadFunction( LPVOID pParam)?
l参数pParam是传递给执行函数的参敎ͼ
l参数nPriority是线E执行权限,可选|(x)
THREAD_PRIORITY_NORMAL、THREAD_PRIORITY_LOWEST、THREAD_PRIORITY_HIGHEST、THREAD_PRIORITY_IDLE?
l参数dwCreateFlags是线E创建时的标志,可取值CREATE_SUSPENDEDQ表C线E创建后处于挂v状态,调用ResumeThread函数后线El运行,或者取?#8220;0”表示U程创徏后处于运行状态?
lq回值是CWinThreadcd象指针,它的成员变量m_hThread为线E句柄,在Win32 API方式下对U程操作的函数参数都要求提供U程的句柄,所以当U程创徏后可以用所有Win32 API函数对pWinThread->m_ThreadU程q行相关操作?
注意Q如果在一个类对象中创建和启动U程Ӟ应将U程函数定义成类外的全局函数Q或者类中的?rn)态函C乎也可以Q?/span>
2.U程(zhn)挂和恢?/ 优先U操作:(x)同上?br>
3.U程退出:(x)当调用线E的函数q回后,U程自动l止?/p>
//U程可以在自w内部调用来l止自n的运行?/span>
void AfxEndThread(UINT nExitCode, BOOL bDelete = TRUE);
//可以在线E的外部调用来强行终止一个线E的q行?/span>
BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode );
q程间通信
1.全局变量方式Q?br>(1)q程和线E共享全局变量Q可利用该全局变量辑ֈ通信的目的?br>(2)进E的HADNLE作ؓ(f)参数传递给U程函数Q然后线E可Ҏ(gu)此HANDLE对进E的变量q行操作?br>
2.消息通信方式Q?/p>
BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
BOOL PostThreadMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
BOOL PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam =0 );
q回值如果公布了(jin)消息Q则q回非零|否则q回0?nbsp;
参数message指定?jin)要公布的消息?nbsp;
wParam指定?jin)附加的消息信息。这个参数的内容依赖于要公布的消息?nbsp;
lParam指定?jin)附加的消息信息。这个参数的内容依赖于要公布的消息?nbsp;
说明Q这个函数将一个消息放入窗口的消息队列Q然后直接返回,q不{待对应的窗口处理消息。消息队列中的消息是通过调用Windows的GetMessage或PeekMessage函数来获得的。可以通过Windows的PostMessage函数来访问其它应用程序?nbsp;
BOOL PostThreadMessage( UINT message , WPARAM wParam, LPARAMlParam );q回值如果成功,则返回非零|否则q回0?nbsp;
参数message用户自定义消息的ID?nbsp;
wParamW一个消息参数?nbsp;
lParamW二个消息参数?nbsp;
说明Q调用这个函C向其它CWinThread对象发送一个用戯定义消息。发送的消息通过消息映射宏ON_THREAD_MESSAGE被映到适当的消息处理函数?nbsp;
3.同步方式Q具体参?a href="http://www.shnenglu.com/andxie99/archive/2006/10/10/13517.html">http://www.shnenglu.com/andxie99/archive/2006/10/10/13517.html?br>
]]>
以strcpy函数Z子,ȝ一下:(x)