CPP_Basic_Summary_0.7

CPP_Basic_Summary_0.7

1、C++要求函数的返回值不能是数组,但可以将数组作为结构或对象组成部分来返回
2、C++的编程风格因为函数原型必须存在,所以提倡main()置于最前面
3、函数原型不要求必须提供变量名,只需要类型列表就可以:

void test(double ar[],int);
void test(double [],int);
void test(double*,int);//三者同义

4、通常如果可能且仅当有意义时,原型自动将被传递的参数强制转换为期望的类型
5、在编译阶段进行的原型化被称为静态类型检查,这种检查可以捕获很多运行阶段难以捕获的错误
6、函数的内部变量(包括参数)是局部变量,函数结束将释放这些内存,按值传递时函数形参传递的是副本
7、在进行诸如阶乘这类大规模计算的时候,采用交替进行乘除运算的方式,可以有效防止中间结果超最大值而溢出
8、数组名在大部分时候等同于指向第一个元素的指针,但有以下情形除外:首先是数组声明用数组名来标记存储位置;其次,对数组名使用sizeof将得到整个数组的长度(字节为单位);然后是将地址运算符&用于数组名时,将返回整个数组的地址
9、将指针(包括数组名)+1,实际上是加上了一个与指针指向类型的长度(字节为单位)相等的值
10、函数调用数组必须通过数组名,也就是指针传递的方式,可以用数组名和数组容量搭配的方式:

void demo(double arr[],int size);

也能使用两个指针来指出数组的开头位置和结尾位置:

int sum_arr(cookies,cookies+size);

11、const double ar[]:保护指针指向的内容不被修改;但只意味着对于ar来说不可以更改,别的指针或许可以,且指针ar本身也可以被修改
12、int* const pt=&age:意味着指针本身不可被修改。简而言之:前置const锁数据,后置const锁指针,同时则都锁。需要非常注意的是,如果数组元素不是基本类型,而是指针或者指向指针的指针,则不能使用const(比如2D数组)
13、C++禁止将const的地址赋给非const指针,若数据类型本身不是指针,则可以将const数据或非const数据的地址赋给指向const的指针,但是只能将非const数据的地址赋给非const指针
14、2D数组的函数定义:int sum(int ar2[] [4],int size);可见是单独传递行数的。ar2[r][c]==*(*(ar2+r)+c)两者完全等价
15、const char* str="name";即可声明指向字符串的指针str,此处const对于C++11标准是必须的
16、处理字符串中字符的标准方式:

while (*str)
{
    statements;
    str++;
}

此循环每次增加使得str指向下一个字符,直到最后的'\0'将使*str==0(空值字符的数字编码),从而中断循环
17、从后向前的循环一般可以节省额外的变量i,比如:

while (n-- >0)
{
    pstr[n]=c;
}

18、子函数结束时,所有局部变量都会被释放,即返回的指针的内存会被释放,但是其值会被返回到main()中,故仍可以通过main()中的指针对新建的字符串相关内容进行访问
19、函数中使用结构可以使用实值直接传递和结构指针两种方式,但是出于效率考虑,应该优先使用指针。除此以外,还有引用的方式可以解决 表示和效率 两方面的问题
20、函数中使用string对象数组:

string list[size];
getline(cin,list[i]);

21、函数中使用array对象,除了基本数据类型,array还可以存储类对象:

array<double,4> expenses;
const array<string,4> sname {"Spring","Summer","Fall","Winter"};
void show(array<double,4> da);
void fill(array<double,4> *pa);
show(expenses);
fill(&expenses);

22、递归(也称 分而治之):C++允许递归调用除了main()以外的子函数:

void recurs(argumentlist)
{
    statements1;
    if (test)//test最终为false将跳出循环
        recurs(arguments);//此处的递归调用应该更新test条件
    statements2;
}//若statements1将按照调用顺序执行n次,则statements2将按照与函数调用相反的顺序执行n次

23、每一套递归调用都创建自己的一套变量,因此若程序达到第5次调用的时候,将有5个独立的变量:

void countdown(int n)
{
    if (n>0)
        countdown(n-1);
}

24、函数的地址是存储其机器语言代码的内存的开始地址。函数指针允许在不同的时间传递不同函数的地址,这意味着可以在不同的时间使用不同的函数。函数的地址就是函数名,需要注意的是区分函数本身和函数的返回值:

process(think);//传递的是函数的地址
thought(think());//传递的是函数的返回值

25、声明一个函数指针,通常可以先写出函数的原型,然后用诸如(*pf)这样的函数指针替换函数名即可:

double (*pf)(int);//pf是指向函数的指针,该函数返回值类型为double,形参为int
double* pf(int);//pf是一个函数,接受int形参,且返回值的类型为double*指针

26、需要注意C++特别规定,若pf是一个函数指针,则:
double y=(*pf)(5)double y=pf(5)是完全等价的,也即此处(*pf)==pf。为强调是函数指针,建议使用前者
27、类似地,以下代码含义完全一致:

cout<<(*p1)(av,3)<<*(*p1)(av,3)<<endl;
//第一部分是函数调用,返回double*指针,第二部分再次解除*,获得具体的double实值
cout<<p2(av,3)<<*p2(av,3)<<endl;
//同理,第一部分函数调用,返回double*指针,第二部分是具体的double实值

28、创建指向整个函数指针数组的指针:

const double* (*(*pd)[3]) (const double*,int)=&pa
//*pd表明pd是指针,右侧[3]说明指针指向一个数组
//*(*pd)最左侧的*表明数组的元素是指针
//观察左右两侧发现数组的元素是函数指针
//左侧const double*是返回值类型,右侧 (const double*,int)是形参

29、typedef用法:
例1:

typedef const double* (*p_fun) (const double*,int);
p_fun p1=f1;
p_fun pa[3] {f1,f2,f3};
p_fun (*pd) [3]=&pa;

例2:

void (*p1)(形参)=f1;
const char* (*p2)(形参)=f2;
void (*ap[5])(形参);
const char* (*(*pa)[10])(形参);
//可简化为:
typedef void (*p_f1)(形参);
p_f1 p1=f1;
typedef const char* (*p_f2)(形参);
p_f2 p2=f2;
p_f1 ap[5];
p_f2 (*pa)[10];

30、指针数组 数组指针 指针函数 函数指针

int *p[4];        //指针数组
  //它是个有4个元素的数组, 每个元素的是指向整型的指针。(数组的每个元素都是指针)
int (*p)[4];      //数组指针。 
  //它是一个指针,指向有4个整型元素的数组。(一个指针指向有4个整型元素的数组)
int *func(void);  //指针函数。
  //无参函数, 返回整型指针。(函数的返回值为int*)
int (*func)(void);//函数指针
  //可以指向无参, 且返回值为整型指针的函数。(函数的返回值为int)

31、复杂函数指针阅读说明:
  右左法则其实并不是C++标准里面的内容,它是从C++标准的声明规定中归纳出来的方法。C++标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。
  右左法则:首先从最里面的圆括号(未定义的标识符)看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
  对这个法则应该进行一个小小的修正,应该从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。
  现在通过一些例子来讨论右左法则:

int (*func)(int *p);

首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个号,这说明func是一个指针,
然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(
func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是 int。

int (*func)(int *p, int (*f)(int*));

func被一对括号包含,且左边有一个号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int 和int ()(int)这样的形参,返回值为int类型。再来看一看func的形参int (f)(int),类似前面的解释,f也是一个函数指针,指向的函数具有int*类型的形参,返回值为int。

int (*func[5])(int *p);

func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个,说明func的元素是指针,要注意这里的不是修饰 func的,而是修饰func[5]的,原因是[]运算符优先级比高,func先跟[]结合,因此修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为int。

int (*(*func)[5])(int *p);

func被一个圆括号包含,左边又有一个,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*形参,返回值为int类型的函数。

int (*(*func)(int *p))[5];

func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。
32、要注意有些复杂指针声明是非法的,例如:

int func(void) [5];

func是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,
那么接收这个数组的内容的东西,也必须是一个数组,但C语言
的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。

int func[5](void);

func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。实际当中,需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性是一大损害。应该用typedef来对声明逐层分解,增强可读性。
33、用typedef的分解方法:

int (*(*func)[5][6])[7][8];

func是一个指向数组的指针,这类数组的元素是一个具有5X6个int元素的二维数组,而这个二维数组的元素又是一个二维数组。

typedef int (*PARA)[7][8];
typedef PARA (*func)[5][6];
int (*(*(*func)(int *))[5])(int *);

func是一个函数指针,这类函数的返回值是一个指向数组的指针,所指向数组的元素也是函数指针,指向的函数具有int*形参,返回值为int。

typedef int (*PARA1)(int*);
typedef PARA1 (*PARA2)[5];
typedef PARA2 (*func)(int*);
int (*(*func[7][8][9])(int*))[5];

func是一个数组,这个数组的元素是函数指针,这类函数具有int*的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。

typedef int (*PARA1)[5];
typedef PARA1 (*PARA2)(int*);
typedef PARA2 func[7][8][9];
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,422评论 3 44
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,500评论 1 51
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 3,771评论 1 10
  • 最近在学Markdown相关的东西,相信在不久的将来,在简书里面能简单的秀下技能。 色花天团最近好事频频,想和老岸...
    果酱阅读 244评论 0 0
  • 项目开发中往往经常使用单例模式,单例的目的: 内存中只有一个对象实例 提供一个全局访问点 OC 中的单例写法 Sw...
    captain_Lu阅读 350评论 0 2