C/C++学习心得(持续更新中...)
2017-11-05 本文已影响0人
simplson
1. const的用法 (正确使用const将大大改善程序的健壮性)
- const int *p; //指针p1i所指内容是常量,可以不初始化
- int * const p; //指针p2i是常量,所指内容可修改
- const int * const p; //指针p3i是常量,所指内容也是常量
- 由于const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
2. static的用法
- 定义函数内局部静态变量
- 定义文件内全局静态变量
- 定义文件内静态函数
- 定义类内静态成员变量和静态成员函数
- 全局变量、静态全局变量以及静态局部变量都会被放在程序的静态数据存储区(全局可见)中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它们与栈变量、堆变量的区别。
3. virtual的用法
- 虚拟继承
- 实现多态(确定一个函数调用来自父类还是子类)
- 纯虚函数
- 虚析构函数
- 虚函数必须实现,不实现编译器会报错
4. 动态链接库中有个全局变量,两个进程中一个进程改变这个全局变量,另一个进程中使用这个全局变量是否会改变?
答:不会改变,因为进程之间一般不共享数据,进程间通信可以通过IPC,例如共享内存等 。
5. 进程间通信方法中哪种效率最高(共享内存、套接字、管道)?
答:依具体的数据传输量来定,数据量<4500字节,共享内存效率最高;5000<数据量 <11000,套接字效率最高,11000<数据量,管道的效率最高。
6. 定义一个指针,不给它初始化赋值,为什么系统给它默认的地址为0xCCCCCCCC而不是其它的?
答:VC的Debug下是这样的,地址0x0CCCCCCCC处于内核地址空间,一般的应用程序是无权访问的,一旦访问就会报错。这样做是为了使我们在调试的时候能尽早地发现野指针,不让本该在调试阶段发现的问题从眼皮底下溜走。
6. pthread_cond_signal后为什么要加sleep才能实现线程同步?
答:对于条件变量来说,如果pthread_cond_signal之后没有任何线程阻塞在pthread_cond_wait上,那么此条件变量上的信号丢失。
解决办法:用pthread_yield()函数实现让出 线程控制权;也可以用nanosleep来代替sleep 减小休眠时间。
7. (1) map.insert(pair<char *, char *>(str1, str2)); (2) map.insert(pair<int, char *>(i, str)); 默认排序为升序, (1)中按字符串起始地址排序,(2)中按整形值排序 另外map在insert时,如果key重复,则将会替换?
答:不会替换,只是插入失败而已
vector<char *> vec_name;
for(int i = 0; i < 2; i++)
{
char name[128] = {0};
sprintf(name, "%s%d", "name", i);
vec_name.push_back(name);
}
printf("vector[0] = %s \n", vec_name[0]);
printf("vector[1] = %s \n", vec_name[1])
out:
vector[0] = name1
vector[1] = name1
map <char *, int> map_name;
map <char *, int>::iterator iter;
for (int j = 0; j < 2; j++)
{
char key[32] = {0};
sprintf(key, "%s%d", "name", j);
map_name.insert ( pair <char *, int> ( key, j ) );
}
for (iter = map_name.begin( ); iter != map_name.end( ); iter++)
{
printf(" iter->first = %s \n", iter->first);
printf(" iter->second = %d \n", iter->second);
}
out:
iter->first = name1
iter->second = 0
8. 自定义map中的比较函数
struct Cmp {
bool operator()(const char *str1, const char *str2) {
if (strcmp(str1, str2) <= 0) return 1; //升序,反之降序
else return 0;
}
};
map<char *, int, Cmp>map_name;
9. 自定义vector中的比较函数
bool cmp(char a[], char b[])
{
if (strcmp(a, b) <= 0) return 1; //升序
else return 0;
}
vector<char *> clock_time
sort(clock_time.begin(), clock_time.end(), cmp);
10. 如果元素是结构体,那么,可以直接把比较函数写在结构体内。下面的程序详细说明了如何操作:
#include <map>
#include <string>
#include <iostream>
using namespace std;
struct Info
{
string name ;
float score ;
//重载 “<”操作符,自定义排列规则
bool operator < (const Info &a) const
{
//按score由大到小排列。如果要由小到大排列,使用“>”号即可
return a.score < score ;
}
};
int main()
{
map<Info, int> m;
Info info;
//插入元素,按键值的由小到大放入黑白树中
info.name = "Jack";
info.score = 60;
m[info] = 25 ;
info.name = "Bomi";
info.score = 80 ;
m[info] = 10 ;
info.name = "Peti";
info.score = 66.5;
m[info] = 30;
map<Info,int> :: iterator it ;
for(it = m.begin(); it != m.end(); it++)
{
cout << (*it).second << " : ";
cout << ((*it).first).name << " : " << ((*it).first).score << endl;
}
return 0 ;
}
11. 正确使用stl map中的erase方法
- 使用删除之前的迭代器定位下一个元素。STL建议的使用方式
for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
cout<<iter->first<<":"<<iter->second<<endl;
mapTest.erase(iter++);
} - erase() 成员函数返回下一个元素的迭代器
for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
cout<<iter->first<<":"<<iter->second<<endl;
iter=mapTest.erase(iter);
}
12. sscanf用法
char str1[64] = {0};
char str2[64] = {0};
char str3[64] = {0};
//先将 "iios/"过滤掉,再将非'@'的一串内容送到str1中
sscanf("iios/12DDWDFF@122","%*[^/]/%[^@]", str1);
sscanf("iios/12DDWDFF@122","%*[^/]/%s", str2);
sscanf("iios/12DDWDFF@122","%[^/]", str3);
printf("%s\n", str1);
printf("%s\n", str2);
printf("%s\n", str3);
out :
12DDWDFF
12DDWDFF@122
iios
char DesiredTime[128] = {0};
sprintf(DesiredTime, "%s", "1901-01-09 15:23:55");
char year[16] = {0};
char mon[16] = {0};
char day[16] = {0};
char hour[16] = {0};
char min[16] = {0};
char sec[16] = {0};
int iYear,iMon,iDay,iHour,iMin,iSec;
int valu;
printf("\n DesiredTime = %s \n", DesiredTime);
valu = sscanf(DesiredTime, "%4s-%2s-%2s %2s:%2s:%2s", year, mon, day, hour, min, sec);
printf("valu1 = %d \n", valu);
valu = sscanf(DesiredTime, "%d-%d-%d %d:%d:%d", &iYear,&iMon,&iDay,&iHour,&iMin,&iSec);
printf("\n year=%s,mon=%s,day=%s,hour=%s,min=%s,sec=%s \n", year, mon, day, hour, min, sec);
printf("\n iYear=%d,iMon=%d,iDay=%d,iHour=%d,iMin=%d,iSec=%d \n", iYear,iMon,iDay,iHour,iMin,iSec);
printf("valu2 = %d \n", valu);
out:
DesiredTime = 1901-01-09 15:23:55
valu1 = 6
year=1901,mon=01,day=09,hour=15,min=23,sec=55
iYear=1901,iMon=1,iDay=9,iHour=15,iMin=23,iSec=55
valu2 = 6
13. C代码优化方案
- 使用尽量小的数据类型
- 求余运算 a=a%8改为a=a&7 通常只要是求2n方的余数,均可使用位操作的方法来代替
- 平方运算 a=pow(a, 2.0); 改为 a=a*a;
- 用移位实现乘除法运算 a=a4;改为a=a<<2; b=b/4;改为b=b>>2; a=a9改为a=(a<<3)+a;
- 使用复合赋值表达式 a-=1及a+=1
- 结构体成员的布局
- Switch语句中根据发生频率来进行case排序
- 函数优化(Inline函数、不定义不使用的返回值、减少函数调用参数、所有函数都应该有原型定义、尽可能使用常量(const)、把本地函数声明为静态的(static))
- 变量(register变量、同时声明多个变量优于单独声明变量、短变量名优于长变量名,应尽量使变量名短一点、在循环开始前声明变量)