文档章节

C/C++高质量编程笔记

来来叔叔
 来来叔叔
发布于 2017/08/04 23:55
字数 1868
阅读 4
收藏 0
 

怕忘记的一些重点,呵呵。

1 运算符优先级
( ),[],->,.,!,~,++,--,sizeof,(正负)+,-,(指针)*,&,*,/,%,+,-,《,》,...

2 if 语句判断条件
布尔型
if (flag) or if(!flag)
整型
if (value==0) or if (value!=0)
浮点型
if ((x>=-EPSINON) && (x<=EPSINON))
指针
if (P == NULL) or if (P != NULL)

3 循环语句效率
多重循环时,最短的循环放在最外层,以减小CPU跨切循环层的次数。

公共语句放在循环体外。

4 常量
#define MAX 100
const int MAX = 100;
const 常量有数据类型,编译器可以进行类型安全检查。
宏常量则没有,并且在字符替换时可能会产生意料不到的错误。

对外公开的常量放在头文件中,私密的常量放在定义文件的头部。

类中的常量
const数据成员只在某个对象生存期内是常量,不同对象的值可以不同。
class A
{
    const int SIZE = 100;//错误
    int array[SIZE];
}
const 数据成员的初始化只能在类构造函数的初始化表中进行:
class A
{
    const int SIZE;
    A(int size);
    int array[SIZE];
}
A::A(int size) : SIZE(size)
{
}

5 函数设计
C语言中,函数的参数和返回值的传递方式有两种:值传递和指针传递,C++中多了引用传递。
(1)参数要书写完整,没有参数则用void填充
(2)如果参数是指针,且仅作输入用,则应在类型前加const
(3)如果输入参数是以值传递的方式传递对象,则宜改用const &的方法传递,省去临时对象的构造和析构。
(4)如果函数的返回值是一个对象,有些场合用“引用传递”可以提高效率,而有些场合只能用值传递,而不能用“引用传递”。

class String
{
    //赋值操作
    String& operate=(const String &other);
    //相加操作
    friend String operator+(const String &s1, const String &s2);
    ...
}
赋值函数中返回*this的引用。
相加操作函数中返回一个临时的String值,如果改用引用传递,那么函数返回值是一个指向局部对象的引用,由于函数结束时局部对象将自动销毁,将导致返回的引用无效。

6 函数内部实现的规则
(1)在函数的入口处,对参数的有效性进行检查。
使用assert,来防止非法参数(调用者出了差错)。

(2)在函数的出口处,对return 语句的正确性和效率进行检查。
* return 语句不可返回指向"栈内存"的指针或者引用。
* 搞清楚返回的究竟是值、指针还是引用。
* 如果返回值是一个对象,要考虑return语句的效率。
return String(s1+s2);

String temp(s1+s2);
return tem;
后者需要创建temp对象,同时完成初始化,然后拷贝构造函数把temp拷贝到保存返回值的外部存储单元中
,最后要销毁temp.前者只需创建一个临时对象并返回它,效率更高。

7 引用与指针的比较
* 引用被创建时必须初始化
* 一旦引用被创建,就不能改变引用的关系(指针可以改变所指的对象)
* 引用更安全

8 内存管理
内存分配的三种方式:
* 从静态存储区域分配。内存在程序编译的时候就已经分配好,在程序整个运行期间都存在。例如全局变量,static变量。
* 在栈上创建。函数内局部变量的存储单元在栈上创建,函数执行结束时自动释放。效率较高,但是分配的内存容量有限。
* 在堆上分配,动态内存分配,使用malloc或new创建,使用free或delete释放。

9 指针使用要点:
判断内存分配是否成功,初始化,不要越界,释放分配的内存,释放后赋NULL。

10 指针与数组的对比
数组在静态存储区或栈上创建,在生存期内对应一块内存,其地址与容量保持不变,只有数组的内容可以改变。
指针可以随时指向任意类型的内存。
* 修改内容
char a[]="hello";
a[0]='x';//正确
char *p="world";
p[0]='x';//错误

指针p指向常量字符串"world"(位于静态存储区,内容为world\0),常量字符串的内容是不可以被修改的。
* 内容复制与修改
复制字符串应用strcpy
比较字符串应用strcmp
* 计算内存容量
用运算符sizeof可以计算数组的容量,但是不能计算指针所指的内存容量。
char a[]="hello world";
char *p = a;
cout<<sizeof(a)<<endl;// 12
cout<<sizeof(p)<<endl;// 4

void Func(char a[100])
{
     cout<<sizeof(a)<<endl;// 4
}

11 用函数分配内存
// 由于形参的原因,并不能为p分配内存,而且会造成内存泄漏
void GetMemory(char *p, int num)
{
    p = (char *) malloc(sizeof(char)*num);
}

正确的方法:用指针的指针,用指针的引用,或者返回动态内存

void GetMemory1(char **p, int num)
{
    *p = (char *) malloc(sizeof(char)*num);
}

void GetMemory1(char *&p, int num)
{
    p = (char *) malloc(sizeof(char)*num);
}

char* GetMemory1(int num)
{
    char *p = (char *) malloc(sizeof(char)*num);
    return p;
}

12 malloc/free与new/free的区别
* malloc/free是C++/C语言的标准库函数,new/delete是C++的运算符
* new/free能自动执行对象的构造函数和析构函数

int *p1 = (int *)malloc(sizeof(int)*length);
int *p2 = new int[length];
Obj *a = new Obj;
Obj *b = new Obj(1);
Obj *c = new Obje[100](1);//错误

如果p不是NULL指针,那么free或delete对p连续操作再次会导致程序运行错误。


13 重载、内联、const、vitual:

extern跟C++的函数重载有关系。
C和C++对函数的处理方式是不同的.extern "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。


14 构造函数、析构函数与赋值函数

类的四个缺少函数:
A(void); //缺省的无参数构造函数
A(const A &a);// 缺省的拷贝构造函数
~A(void);//缺省的析构函数
A& operate=(const A &a);//缺省的赋值函数

缺省的拷贝构造函数与赋值函数,采用位拷贝而不是值拷贝。

例:String类的设计

class String
{
public:
String(const char *str=NULL);//普通构造函数
String(const String &other);//拷贝构造函数
~String();//
String& operator=(const String &other);//赋值函数
void Print();
private:
char *m_data;
};

String::String(const char *str)
{
if(str==NULL)
{
   m_data = new char[1];
   *m_data = '\0';
}
else
{
   int length = strlen(str);
   m_data = new char[length+1];
   strcpy(m_data, str);
}
}

String::~String()
{
delete []m_data;
}

String::String(const String &other)
{
int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data,other.m_data);
}

String& String::operator =(const String &other)
{
if(this==&other)
   return *this;

delete []m_data;

int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data,other.m_data);

return *this;
}

void String::Print()
{
cout<<m_data<<endl;
}


 

偷懒的方法
如果不想编写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的缺省函数,以造成错误,怎么办?
只需将拷贝构造函数和赋值函数声明为私有,不用编写代码:
class A
{
   ...
   private:
       A(const A &a);// 私有的拷贝构造函数
       A& operator=(const A &a);//私有的赋值函数
}

如果有人试图进行如下操作,编译器将指出错误:
A b(a);//调用了私有的拷贝构造函数
b = a;   //调用了私有的赋值函数


© 著作权归作者所有

来来叔叔
粉丝 0
博文 100
码字总数 55732
作品 0
广州
高级程序员
私信 提问
重读经典-《Effective C++》Item1:视C++为一个语言联邦

本博客(http://blog.csdn.net/livelylittlefish )贴出作者(三二一@小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正! C++已经是个多重范型编程语言(multiparadigm programming la...

晨曦之光
2012/03/09
65
0
Boost简介

本博客(http://blog.csdn.net/livelylittlefish )贴出作 者(三二一@小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正! Boost简介 是什么? Boost是一个功能强大、构造精巧、跨平台...

晨曦之光
2012/03/09
475
0
4-C++远征之起航篇-学习笔记

c++教程起航篇 我们会讲C++那些事,C++与C语言的关系。 C++诞生于贝尔实验室。 C++之父: 本贾尼·斯特劳斯特卢普 C++社区排行榜 最新排行,c++排名第三,Python排名第四 C++语言的应用领域:...

天涯明月笙
2018/07/20
0
0
《C++ primer》读后感:时代的经典

说起Lippman的C++ Primer,我总是有种特殊感情。这本书既是我进入C++领域的敲门砖,也是我第一次在网络上发表技术文章的对象。当年读书笔记中的青涩迷惘和年少轻狂都还历历在目,转眼已经从第...

凌杰_owlman
2018/05/15
0
0
Effective C++ 笔记(1):视C++为语言联邦

条款一(clause 1) 将C++视为语言联邦:提出了一种将C++分为四种不同次语言的观念,四种次语言分别是: 1、C语言,面向过程的语言,C++完全向下兼容C,在C++中单纯使用C语言的语法除了遵守的一...

oldpan
2017/09/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

JS基础-该如何理解原型、原型链?

JS的原型、原型链一直是比较难理解的内容,不少初学者甚至有一定经验的老鸟都不一定能完全说清楚,更多的"很可能"是一知半解,而这部分内容又是JS的核心内容,想要技术进阶的话肯定不能对这个...

OBKoro1
今天
8
0
高防CDN的出现是为了解决网站的哪些问题?

高防CDN是为了更好的服务网络而出现的,是通过高防DNS来实现的。高防CDN是通过智能化的系统判断来路,再反馈给用户,可以减轻用户使用过程的复杂程度。通过智能DNS解析,能让网站访问者连接到...

云漫网络Ruan
今天
14
0
OSChina 周一乱弹 —— 熟悉的味道,难道这就是恋爱的感觉

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @xiaoshiyue :好久没分享歌了分享张碧晨的单曲《今后我与自己流浪》 《今后我与自己流浪》- 张碧晨 手机党少年们想听歌,请使劲儿戳(这里)...

小小编辑
今天
3.1K
24
SpringBoot中 集成 redisTemplate 对 Redis 的操作(二)

SpringBoot中 集成 redisTemplate 对 Redis 的操作(二) List 类型的操作 1、 向列表左侧添加数据 Long leftPush = redisTemplate.opsForList().leftPush("name", name); 2、 向列表右......

TcWong
今天
47
0
排序––快速排序(二)

根据排序––快速排序(一)的描述,现准备写一个快速排序的主体框架: 1、首先需要设置一个枢轴元素即setPivot(int i); 2、然后需要与枢轴元素进行比较即int comparePivot(int j); 3、最后...

FAT_mt
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部