เริ่มต้นใช้งานการดีบัก gdb ซึ่งเป็นคำแนะนำคุณภาพสูงที่เขียนโดย Daniel
สถาปัตยกรรมคอมพิวเตอร์แนวทางเชิงปริมาณการแปลไฟล์ PDF
การออกแบบระบบโปรแกรมอัตโนมัติ
แผนการเติบโตของโปรแกรมเมอร์
การแสดงภาพแบบไดนามิกของโครงสร้างข้อมูลและอัลกอริธึม
การใช้ภาษา C บริสุทธิ์ของโครงสร้างข้อมูลพื้นฐานและอัลกอริธึม
บันทึกการสัมภาษณ์วิทยาการคอมพิวเตอร์
บันทึกการสัมภาษณ์วิทยาการคอมพิวเตอร์ 2
กระบวนการโค้ดภาพ
การอ้างอิงรหัสการปฏิบัติด้านวิศวกรรมต่างๆ
คู่มือการทำงานพร้อมกันแบบมัลติเธรด C++ ใช้งานได้จริง
บทช่วยสอน c/c++
หากต้องการเรียนรู้ C++ คุณควรอ่านหนังสือเล่มไหนทีละขั้นตอน
แค็ตตาล็อกชุดโครงสร้างข้อมูลและอัลกอริทึม
หลังจากตอบคำถามทั้ง 65 ข้อนี้แล้ว อัตราการผ่านการสัมภาษณ์จะเพิ่มเป็นสองเท่าโดยไม่มีปัญหา
การทดลองโค้ด c++
ซอร์สโค้ดค้นหาหนังสือยอดนิยม
การค้นหาซอร์สโค้ดเป็นภาษาอังกฤษ
ดัชนีหนังสือการเขียนโปรแกรมภาษาจีนฟรี
การสัมภาษณ์โค้ดดีกว่าและแนะนำเป็นอย่างยิ่ง! - - - -
บันทึกการตรวจสอบ nowcoder
บันทึกการสอบ LeetCode
ทบทวน C++ กับฉัน
5 แนวคิดอัลกอริทึมที่ใช้กันทั่วไปใน Leetcode
โครงสร้างข้อมูล บล็อก อ้างอิง แผนผังแผนผังคิว
GitHub Pages+Jekyll เพื่อสร้างบล็อกส่วนตัว
ชุดเครื่องมือมาร์กดาวน์
GitHub ระบบปฏิบัติการ Tsinghua
คอลัมน์บล็อก การเขียนโปรแกรมสภาพแวดล้อม Linux
คอลัมน์บล็อกการเขียนโปรแกรมเครือข่าย Linux
คอลัมน์บล็อกเพื่อเรียนรู้ C++ ทีละขั้นตอน
บล็อกคอลัมน์ภาษา C
Fish C Studio C/C++/Python/Wed/โครงสร้างข้อมูลและอัลกอริทึม
การเขียนโปรแกรมอินเทอร์เฟซแบบกราฟิก
บันทึกบล็อกอัลกอริทึมการสัมภาษณ์
อัลกอริธึมพื้นฐานของ Liu Guoping
CPP11 รหัสพิเศษใหม่ การต่อสู้จริง
คุณสมบัติใหม่แนวคิด C++11/14/17 และข้อมูลโค้ด
บทช่วยสอนการทำงานพร้อมกันของ Cplusplus โดยละเอียด "คู่มือการเขียนโปรแกรม C++ พร้อมกัน"
คำแนะนำเชิงลึกเกี่ยวกับการทำงานพร้อมกันและการเขียนโปรแกรมแบบมัลติเธรดตามมาตรฐาน C++ 11 ใหม่ C++ Concurrency In Action
คำแปลภาษาจีนของ "ตำราอาหาร C++17 STL" เวอร์ชันภาษาอังกฤษ
การเรียนรู้แฮช
Oracle Corporation Editor Oracle Solaris Studio 12.4 Information Library (ภาษาจีนตัวย่อ) คู่มือผู้ใช้ c/cpp คู่มือการคำนวณเชิงตัวเลข ตัววิเคราะห์โค้ด ตัววิเคราะห์ประสิทธิภาพ ตัววิเคราะห์เธรด
หลักการรวบรวมของสถาบันเทคโนโลยีฮาร์บิน
หลักการรวบรวม - การใช้งานตัววิเคราะห์คำศัพท์
เทคโนโลยีการรวบรวม Western Electric
gitbook เทมเพลตการเขียนหนังสือออนไลน์
การเรียนรู้บรรณานุกรมทีละขั้นตอน
svn สร้าง trunk และกิ่งใหม่
git clone --recurse-submodules https://github.com/xxxxx.git
โปรดทราบว่าคุณต้องนำพารามิเตอร์ --recurse-submodules มาด้วยเมื่อทำการโคลน ไม่เช่นนั้นการดาวน์โหลดจะไม่สมบูรณ์
1. c
2. c++
3. python
4. 汇编语言
5. 数据机构和算法 面试
6. 操作系统os
7. 单片机stm32 arduino Ti-msp430 树莓派 px4 arm
8. 数据挖掘
9. 人机工程学
10. 计算机科学
《Essential C++》
这是一本内容不多但很实用的C++入门书籍,强调快速上手与理解C++编程。
本书主要围绕一系列逐渐复杂的程序问题,以及用以解决这些问题的语言特性展开讲解。
你不只学到C++的函数和结构,也会学习到它们的设计目的和基本原理。
《C++ Primer》
本书对C++基本概念、技术、以及现代C++编程风格进行了全面而且权威的阐述,是C++初学者的最佳指南;
本书可以帮助你编写实用的程序,而无需首先精通每个语言细节。
对于中高级程序员,本书也是不可或缺的参考书。
《Effective C++》和《More effective C++》作者是Scott Meyers。
你应该熟读它们,并清楚地理解每个项目。
该书围绕55条准则,每一条都介绍了一个可让你写出更好的C++程序代码的方法,并以特别设计过的例子详加讨论。
《Exceptional C++(C++编程剖析)》和《More exceptional C++》
这两本书中都包含了40个C++编程问题,这些问题会让你磨练自己的技能,最终成为优秀的C++程序员。
这些问题是Herb Sutter精心挑选,与ISO/ANSI C++官方标准相一致,
帮助程序员在设计、架构和编码过程中保持良好的风格,从而使编写的C++软件更健壮、更高效。
《Inside the C++ object model(深度探索C++对象模型)》
本书专注于C++面向对象程序设计的底层机制,
包括结构式语意、临时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承,
帮助你理解程序的底层实现,以便写出更高效的代码。
《The design and evolution of C++(C++语言的设计与演化)》
本书作者也是C++语言的设计者Bjarne Stroustrup,作者在书中综合性地介绍了C++的发展历史,
C++中各种重要机制的本质意义和设计背景,这些机制的基本用途和使用方法,
讨论了C++所适合的应用领域及其未来的发展前景,既没有忽略关键性的详情,又没有过多地陷入技术细节。
《The C++ standard library(C++标准程序库)》
这是标准模板库字典,你可以在本书中找到STL相关的一切知识。
本书焦点放在标准模板库、检查容器、迭代器、函数对象和STL算法上。
每一个元素都有深刻的呈现,包括其介绍、设计、运用实例、
细节解说、陷阱、意想不到的危险,以及相关类别和函数等。
《Effective STL》
这是Scott Meyers的第三本C++专著,也是学习STL最权威的书籍。
作者对书中的50个指导方针都作了详尽的分析,并配以示例。
通过这些规则,C++开发者可以最大限度地使用STL。
《Generic programming and the STL(泛型编程与STL)》
本书阐述了泛型程序设计的核心理念:concepts(概念)、modeling(模型)和refinement(改善),
并为你展示这些观念如何导出STL的基础概念:iterators(迭代器)、
containers(容器)和function objects(函数对象)。
按照本书所述,你可以把STL想象成一个由concepts组成的library,你将学习到STL正式结构并理解其强大的优势。
《Exceptional C++ style》
作者为Herb Sutter。本书同样提出了40个C++风格相关的问题
,对一些至关重要的C++细节和相互关系提出了新的见解,
为当今的关键C++编程技术(如泛型编程、STL、异常安全等)提供了新的策略,
帮助开发者在开销与功能之间、优雅与可维护性之间、灵活性与过分灵活之间寻找完美的平衡点。
《C++ template》
这是一本关于C++模板的完整的参考手册和教程,它强调模板的使用实践,包含了现实世界中的例子。
每个C++程序员都应该好好读一读这本书。
《Modern C++ design(现代C++设计)》
作者Andrei Alexandrescu为C++程序员打开了一个新的局面。
本书提供了一些针对软件设计的前沿方法,如联合设计模式、泛型编程,
使程序员可以编写有表现力的、灵活的、高度可重用的代码。
《Thinking in C++(C++编程思想)》
C++ 领域权威著作,介绍了C++实用的编程技术和最佳的实践方法。
Webbench是一个在Linux下使用的非常简单的网站压测工具。
它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能,
最多可以模拟3万个并发连接去测试网站的负载能力。
Webbench使用C语言编写, 代码实在太简洁,源码加起来不到600行。
หน้าแรกของโครงการ: http://home.tiscali.cz/~cz210552/webbench.html
tinyhttpd是一个超轻量型Http Server,使用C语言开发,全部代码只有502行(包括注释),
附带一个简单的Client,可以通过阅读这段代码理解一个 Http Server 的本质。
หน้าแรกของโครงการ: http://sourceforge.net/projects/tinyhttpd/
cJSON是C语言中的一个JSON编解码器,非常轻量级,C文件只有500多行,速度也非常理想。
cJSON也存在几个弱点,虽然功能不是非常强大,但cJSON的小身板和速度是最值得赞赏的。
其代码被非常好地维护着,结构也简单易懂,可以作为一个非常好的C语言项目进行学习。
หน้าแรกของโครงการ: http://sourceforge.net/projects/cjson/
cmockery是google发布的用于C单元测试的一个轻量级的框架。
它很小巧,对其他开源包没有依赖,对被测试代码侵入性小。
cmockery的源代码行数不到3K,你阅读一下will_return和mock的源代码就一目了然了。
主要特点:
免费且开源,google提供技术支持;
轻量级的框架,使测试更加快速简单;
避免使用复杂的编译器特性,对老版本的编译器来讲,兼容性好;
并不强制要求待测代码必须依赖C99标准,这一特性对许多嵌入式系统的开发很有用
หน้าแรกของโครงการ: http://code.google.com/p/cmockery/downloads/list
libev是一个开源的事件驱动库,基于epoll,kqueue等OS提供的基础设施。
其以高效出名,它可以将IO事件,定时器,和信号统一起来,统一放在事件处理这一套框架下处理。
基于Reactor模式,效率较高,并且代码精简(4.15版本8000多行),是学习事件驱动编程的很好的资源。
หน้าแรกของโครงการ: http://software.schmorp.de/pkg/libev.html
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。
它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态数据库驱动网站的速度。
Memcached 基于一个存储键/值对的 hashmap。
Memcached-1.4.7的代码量还是可以接受的,只有10K行左右。
หน้าแรกของโครงการ: http://memcached.org/
Lua很棒,Lua是巴西人发明的,这些都令我不爽,但是还不至于脸红,最多眼红。
让我脸红的是Lua的源代码,百分之一百的ANSI C,一点都不掺杂。
在任何支持ANSI C编译器的平台上都可以轻松编译通过。我试过,真是一点废话都没有。
Lua的代码数量足够小,5.1.4仅仅1.5W行,去掉空白行和注释估计能到1W行。
หน้าแรกของโครงการ: http://www.lua.org/
SQLite是一个开源的嵌入式关系数据库,实现自包容、零配置、支持事务的SQL数据库引擎。
其特点是高度便携、使用方便、结构紧凑、高效、可靠。足够小,大致3万行C代码,250K。
หน้าแรกของโครงการ: http://www.sqlite.org/
UNIX V6 的内核源代码包括设备驱动程序在内 约有1 万行,这个数量的源代码,初学者是能够充分理解的。
有一种说法是一个人所能理解的代码量上限为1 万行,UNIX V6的内核源代码从数量上看正好在这个范围之内。
看到这里,大家是不是也有“如果只有1万行的话没准儿我也能学会”的想法呢?
另一方面,最近的操作系统,例如Linux 最新版的内核源代码据说超过了1000 万行。
就算不是初学者,想完全理解全部代码基本上也是不可能的。
หน้าแรกของโครงการ: http://minnie.tuhs.org/cgi-bin/utree.pl?file=V6
NetBSD是一个免费的,具有高度移植性的 UNIX-like 操作系统,
是现行可移植平台最多的操作系统,可以在许多平台上执行,
从 64bit alpha 服务器到手持设备和嵌入式设备。
NetBSD计划的口号是:”Of course it runs NetBSD”。
它设计简洁,代码规范,拥有众多先进特性,使得它在业界和学术界广受好评。
由于简洁的设计和先进的特征,使得它在生产和研究方面,
都有卓越的表现,而且它也有受使用者支持的完整的源代码。
许多程序都可以很容易地通过NetBSD Packages Collection获得。
หน้าแรกของโครงการ: http://www.netbsd.org/
sizeof有三种语法形式,如下:
1) sizeof( object ); // sizeof( 对象 );
2) sizeof( type_name ); // sizeof( 类型 );
3) sizeof object; // sizeof 对象;
与计算机类型有关,32为计算机,地址长度为4字节
64位的计算机,地长度为 8字节
这里的指针包括所有类型的指针:
字符指针、整形指针、字符串指针、指针的指针、函数指针、数组指针等。
数组的sizeof值等于数组所占用的内存字节数,如:
char a1[] = "abc";
int a2[3];
sizeof( a1 ); // 结果为4,字符串末尾还存在一个NULL终止符
sizeof( a2 ); // 结果为3*4=12(依赖于int,这里int为4字节)
// 这里注意 &a2和a2的值是相等的,都是a2[0]的地址
// 但是 &a2 的类型为 int *[10]
// 而a2的类型为 int* p
//数组元素数量求取
int c1 = sizeof( a1 ) / sizeof( char ); // 总长度/单个元素的长度(知道元素类型)
int c2 = sizeof( a1 ) / sizeof( a1[0] ); // 总长度/第一个元素的长度(不知道元素类型)
需要看编译器是几个字节对齐 的,一般为4字节对齐
typedef struct
{
int a; // 占据第一个4字节
char b; // 占据第二个4字节
}A_t;
typedef struct
{
int a; // 占据第一个4字节
char b;// 占据第二个4字节中的第一个字节
char c;// 占据第二个4字节中的第二个字节
}B_t;
typedef struct
{
char a;// 占据第一个4字节的第一个字节
int b; // 占据第二个4字节
char c;// 占据第三个4字节的第一个字节
}C_t;
การอ้างอิงบล็อก stl ที่มีประสิทธิภาพ
判断两个浮点数a和b是否相等时,不要使用 a==b ,
应该判断两者的绝对值之差fabs(a-b)是否小于一个阈值 ,如1e-9
if(fabs(a-b) < 1e-9)
应该先将char 强制转换为 unsigned char后在用作下标。
char index_;
unsigned char index = (unsigned char)index_;
vector 和 string 定义的对象 会自动 构造和析构,不用担心内存泄漏的问题
使用new[]分配的动态数组,需要配合 delete[]类释放会造成内存,否者会造成内存泄漏的问题
例如 定义一个二维数组,指针的指针
自己用new实现:
int * * arr_pp new int * [ row_num ]; // 定义一个存储指针的数组的指针 行数
for ( i = 0 ; i < row_num ; ++ i )
arr_pp [ i ] = new int [ col_num ]; // 一个一个new 指针每一行是一个行向量的指针
用 vector实现,一行代码搞定,还不到担心内存泄漏的问题
vector < vector < int >> v_i2 ( row_num , vector < int > ( col_num , 0 )); //初始化为一个0矩阵
vector < int > m ;
m . reserve ( 1000 ); //提前保留1000的内存
//使用 reserve 避免不必要的重新分配
int val = 1024 ; //整形变量
int & refVal = val ; // 整形引用 refVal 指向 val ,是val的另一个名字,
// 引用必须被初始化,引用不是对象,只是为所存在的对象起的一个别名。
refVal = 2 ; // 把2 赋值给refVal 也就是 赋值给了 val
int i = refVal ; // 相当于 i = val;
int & refVal2 = 10 ; // 错误,非常量引用只能绑定(bind)在对象向,
// 不能与字面值或某个表达式的计算结果绑定在一起, 且引用的类型 必须和 对象的类型一致
const int & rci = 10 ; // 常量引用可以绑定到 字面值 非常量 一般表达式
double dval = 3.14 ; // 浮点数
int & refVal3 = dval ; // 错误,引用的类型 和 对象 必须一致
int ival = 42 ; // 整数
int * p = & ival ; // 指针定义 p存放 ival对象存放的地址,也即是 p 指向 变量 ival的指针 &ival 为取的 ival变量的 存储地址
double dval = 3.14 ; // 浮点数
double * pd = & dval ; // double 类型 指针
double * pd2 = pd ; // pd存放 的是 dval存放的地址
int * pi = pd ; // 错误, 指针pi 的类型 和 右边指针对象 类型 不匹配
pi = & dval ; // 错误, 视图把 double 类型对象的地址 给 int类型的指针 错误 左右两边类型 必须匹配
ใช้ตัวชี้เพื่อเข้าถึงวัตถุเพื่อรับค่าที่เก็บไว้ในอักขระอ้างอิงที่อยู่เพื่อเข้าถึงวัตถุ
int ival = 42 ; //整形 变量
int * p = & ival ; //指针变量定义初始化, p 存放着 变量ival 在内存中的地址
std:: cout << * p ; // 表达式里 *p 为 解引用 取的p存放的地址 指向的值
int & ref_i = ival ; // 引用声明定义, ref_i 是一个引用
int * p ; //指针声明定义,p是一个指针
p = & ival ; // 表达式 p为指针(地址),&val 为取的 val 地址
* p = ival ; //表达式 *p 相当于 ival *是一个解引用
int & ref_i2 = * p ; // &ref_i2 为引用定义 *p 相当于 ival, *是一个解引用
ตัวชี้โมฆะ
int * p1 = nullptr ; // 等价于 int *p1 = 0; 空指针 p1 不指向 任何 对象
int * p2 = 0 ; // 空指针 等价于 int *p1 = 0;
int * p3 = NULL ; // 空指针 等价于 int *p1 = 0;
int zero = 0 ;
int * p4 = zero ; // 错误,不能把 int 变量直接赋值 给指针
int i = 42 ;
int * pi1 = 0 ; // pi1 被初始化为空指针,但没有指向 任何对象
int * pi2 = & i ; // pi2 被初始化,存有 i 的地址
int * pi3 ; // 定义 未初始化
pi3 = pi2 ; // pi3 和 pi2指向同一个 对象 i
pi2 = 0 ; // 现在 pi2 被赋值为 空指针 不指向任何对象 指针被改变, 指向的对象不变
pi2 = & i ; // 现在 pi2 又指向 i
* pi2 = 0 ; // 指针pi2 没变 , *pi2 被改变 即pi2指向的对象 i 发生了变化
เมื่อใช้ตัวชี้เนื่องจากเงื่อนไขเป็นตัวชี้ค่าว่าง ค่าตรรกะจะเป็นเท็จ และตัวชี้อื่นๆ ที่ชี้ไปยังวัตถุ (ตัวชี้ที่ไม่ใช่ศูนย์) มีค่าตรรกะเป็นจริง
ความเท่าเทียมกัน == ตัวดำเนินการ ไม่เท่ากับ != ตัวดำเนินการ
ตัวชี้ประเภท void* สามารถชี้ไปยังที่อยู่ประเภทใดก็ได้และสามารถจัดเก็บที่อยู่ประเภทใดก็ได้
ใช้เป็นพารามิเตอร์ฟังก์ชัน ซึ่งจำเป็นเมื่อใช้ในส่วนเนื้อหาของฟังก์ชัน โดยแปลงเป็นตัวชี้เป็นประเภทจริงที่ส่งเข้ามา
double obj = 3.14 , * pd = & obj ; // double 类型 的变量 double类型的指针
void * pv = & obj ; // obj 可以是任意类型的对象
pv = pd ; // pv 可一存放任意类型的指针(地址)
double * pd = ( double * )( pv ); // void* 类型的指针 强制转化成 double* 类型的指针
กำหนดตัวแปรหลายตัว
int i = 1024 , * p = & i , & r = i ; //i是整形变量 p是一个整形指针 r是一个整形引用
int * p1 , p2 ; // * 仅仅修饰 p1 ,即p1是 指向整形的指针 p2是整形变量
int * p1 , * p2 ; // p1 和 p2 都是指向 整形的指针
ตัวชี้ไปยังตัวชี้
int ival = 1024 ;
int * pi = & ival ; //指向整形变量的指针
int * * ppi = & pi ; //指向整形指针的指针 ppi ---> pi ------> ival
std:: cout << ival << "n" // 直接输出 变量值
<< * pi << "n" // 1次解引用 得到变量值
<< * * ppi << "n" ; //2次解引用 的到变量值
การอ้างอิงถึงตัวชี้เป็นนามแฝงสำหรับวัตถุตัวชี้ ไม่มีการอ้างอิงถึงวัตถุ
int i = 42 ; //整形对象
int * p ; //指向整形类型的指针
int * & r_p = p ; //引用r_p的类型为 整形的指针引用int*&,r_p 是指针p的一个别名
//从右向左 离变量最近的符号为 & 即为 引用,* 引用的为 指针类型
r_p = & i ; // 相当于 p = &i p 指向 i
* r_p = 0 ; // 相当于 *p = 0 即 i =0 改变了指针指向对象的值
// 这里 *p *解引用指针的类型其实相当于 原变量的别名 引用
หลังจากแก้ไขตัวแปรแล้ว คุณสามารถป้องกันไม่ให้มีการแก้ไขตัวแปรได้
const int bufSize = 512 ; //初始化常量 一旦创建后就不能被修改
bufSize = 1024 ; // 错误,常量不能被赋值
const int i = get_size (); // 一个函数赋值 运行时初始化
const int j = 42 ; //编译时初始化
const int k ; //错误,常量定义式必须初始化
double dvel = 3.14 ; // 也可以由其他类型变量 强制转换成 常量
const int ci = dvel ; // 由double类型变量 强制转换成 整形常量 3
extern const int bufSize = 1024 ; //定义了一个变量,想在其他文件也使用 bufSize 必须在定义之前 加extern
extern const int bufSize ; // 另一个文件中 声明 bufSize 后 就可以使用了
การอ้างอิงที่เชื่อมโยงกับค่าคงที่ การอ้างอิงถึง const คือการอ้างอิงถึงค่าคงที่ ไม่สามารถแก้ไขนามแฝงของค่าคงที่ได้ และการอ้างอิง const ไม่ใช่วัตถุ
const int c_i = 1024 ; // 常整数
const int & r_c_i = c_i ; // 常整数 c_i 的 引用(别名)
r_c_i = 42 ; // 错误r_c_i 是常量引用 不能被修改
int & r_c_i2 = c_i ; //错误 常整数 不能赋值给 int变量 左右两边类型必须一样
อนุญาตให้เชื่อมโยงการอ้างอิงคงที่ไปยังวัตถุที่ไม่ใช่ const ตัวอักษร หรือแม้แต่นิพจน์ทั่วไป
int i = 52;
const int &r1 = i; // 允许将 常量引用 const int & 绑定到 int变量上
const int &r2 = 42;// 绑定到 字面值上
const int &r3 = r1 * 2;// 绑定到一个 表达式上
int &r4 = r1 * 2;// 错误,r4是非常量 引用,只能绑定到 其对应类型的对象上
double dval = 3.14;//浮点数
const int &ri = dval;//常量引用 绑定到 非常量上
//相当于 先把 非常量转化成常量 强制类型转换 常量引用实际上绑定了一个临时变量
const int temp = dval;//
int i = 42;// int 变量
int &r1 = i;// 整数变量引用 r1为 i 的别名
const int &r2 = i;//常量 引用 r2 绑定到 变量 i上
r1 = 0;// 相当于 i =0
r2 = 0;// 错误 r2 时常量引用 不允许改变
ตัวชี้ไปยังค่าคงที่ const int * ค่าที่ตัวชี้ชี้ไปไม่สามารถเปลี่ยนแปลงได้ กล่าวคือ *p ไม่สามารถกำหนดหรือเปลี่ยนแปลงได้
const double pi = 3.14 ; //双精度 浮点型 常量
double * ptr_d = & pi ; // 错误,浮点型变量指针 不能绑定一个 常量的存储地址
const double * ptr_d_c = & pi ; // 双精度常量 针 ptr_d_c 指向一个 双精度常量
* ptr_d_c = 42 ; // 不能给 pi 赋值 指向常量的指针的解引用相当于 绑定的常量 ,因此不能赋值
doubel dvel = 3.14 ; //双精度变量
ptr_d_c = & dvel ; //允许 常量指针ptr_d_c 指向一个变量dvel 但是不能通过 常量指针ptr_d_c 修改变量dvel
ตัวชี้คงที่ *const ตัวชี้ไม่สามารถเปลี่ยนแปลงได้ กล่าวคือ ไม่สามารถเปลี่ยนตัวชี้ได้ แต่วัตถุที่ชี้ไปไม่มีผล
int errNumber = 0 ; //
int * const conpErr = & errNumber ; // * 可变指针 *const 常量指针不可变
// 指向整形的 常量指针,conpErr 一直指向 errNumber
* conpErr = 3 ; //相当于 errNumber = 3
const double pi = 3.14 ; //
const double * const cd_cp = & pi ; //指向 常量的常量指针,
// 即 指针本身cd_cp不能变, 其指向的值 *cd_cp也不能变
นิพจน์คงที่คือปริมาณ/สูตรที่สามารถกำหนดได้ ณ เวลาคอมไพล์ constexpr int ce = 20;
const int * p = nullptr ; // 指向整形常量 的指针
constexpr int * p = nullptr ; // 指向整形变量的 常量指针
// constexpr 声明中出现 指针 仅仅说明 指针为常量指针
int * const p = nullptr ; //指向 整形变量的 常量指针
const int * const p = nullptr ; // 指向 整形常量 的常量指针
constexpr const int * p = nullptr ; // 指向 整形常量 的常量指针
constexpr int ci = 42 ; // ci 是整形常量
int j = 0 ;
constexpr int * pci = & j ; // 指向整形的 常量指针
typedef double wages ; // wages 是double类型的 同义词
typedef wages base , * p ; // base 也是double类型的 同义词。 p是double * 的同义词
wages d_money = 1.00 ; //等有价于 double d_money = 1.00
p p_dmoney = & d_money ; //等价于 double *p_dmoney = &d_money;
cout << p_dmoney << endl ;
// 别名声明 alias declaration
using SI = Sales_Item ; // SI 是 Sales_Item 的 同义词
SI item ; //等价于 Sales_Item item;
// 指针、常量const 类别别名
typedef char * pstring ; // pstring等价于 char * 指向char 的指针(是指针)
const pstring cstr = 0 ; // cstr是指向 char 的 常量指针
// !!!!不是指向常量字符的 指针 不能直接替换 const修饰的主语是指针
const pstring * ps ; // ps是一个指针 它指向的对象 是 指向char的常量指针
auto item = val1 + val2 ; //item 初始化为 val1 和 val2相加的结果 类型 相同
// 一条语句定义多个变量时,各变量类型必须一致
auto i = 0 , * p = & i ; //正确 i是整数, p是指向整形的指针
auto sz = 0 , pi = 3.4 ; // 错误 sz 和 pi 类型不一致
// 引用 指针 常量 与 auto
int i = 0 , & r = i ; //r是i的别名 int类型
auto a = r ; // a 是一个整形数
// auto 会忽略掉 顶层const
const int ci = i , & cir = ci ; // 常整数
auto b = ci ; // b是一个整数,ci的顶层 const(最外层修饰 为顶层)特性被忽略
auto c = cir ; // c是一个整数,ci的顶层 const特性被忽略
auto d = & i ; // d是一个指向整形的指针
auto e = & ci ; // e是一个指向整形常量的指针 const
// 外又被 取地址符号修饰,所以这里的 const是 底层const 不被忽略
// 如果希望 auto 推断出的类型是 一个顶层 const,需要在其前面 明确指出
const auto f = ci ; // ci的推演类型是 int ,f是 const int
// 将引用设置为 auto 还按之前的初始化规则 保留 顶层 const
auto & g = ci ; // g 是一个 整形常量的 引用 (别名)
auto & h = 42 ; // 错误,非常量 引用 不能绑定 到 字面值
const auto & j = 42 ; // 正确, 常量引用可以绑定到 字面值
// 将 指针设置为 auto, 也按之前的初始化规则 保留顶层 const
auto * k = & ci ; // k为指向 整形常量的 指针
auto * l = 0 ; // l为空指针
const auto * m = & ci ; // m 为 指向整形常量的 常量指针
int i = 1024 ;
const int c_i = i ;
auto b = c_i ; // b是一个 整数 ,c_i的 顶层 const被忽略
auto e = & c_i ; // e 是一个 指向 整形常量的引用 这里的const是底层const 不被忽略
auto k = c_i , & ll = i ; // k 是整数, ll 是一个整数引用
auto k = c_i , & o = c_i ; // 错误,k 是整数变量 o是一个整数常量引用 类型不一致
auto & m = c_i , * p = & c_i ; //正确 m是整数常量引用,p是指向整数常量的指针
auto n = & c_i , * p = & c_i ; // 正确 n是整数常量 引用(底层const,不被忽略) p是指向整数常量的指针
decltype ( f ()) sum = x ; // sum 的类型为 函数 f() 的返回值类型 初始化为 x 就像 int sum = x; 一样
const int ci = 0 , & cj = ci ; // ci 整形常量 cj 整形常量的引用
decltype ( ci ) x = 0 ; // x的类型 同ci 是 整形常量 const int 不忽略 顶层 const
decltype ( cj ) y = x ; // y的类型 同cj 是 整形常量的引用 const int & y绑定到x上
decltype ( cj ) z ; // 错误 z是一个 引用 ,必须初始化
// decltype和引用 指针
int i = 42 , j = 12 , * p = & i , & r = i ;
decltype ( r ) a = j ; // a的类型和r的类型一致,为整数的引用 int& a绑定到j上
decltype ( r + 0 ) b ; //正确 加法的结果为 整形 int 因此 b为整形, 这里只定义 没有初始化
decltype ( * p ) c ; // 错误 其实*p 解引用指针 相当于i的别名 也就是引用
// 所有这里 c的类型为 整数引用 int &,是个引用,必须初始化
// decltype 的表达式如果 加上括号,得到的结果将是引用
decltype ( i ) e ; // e 是一个未初始化的 整形变量
decltype (( i )) d = e ; // d是一个 整数的引用 绑定到 整形变量 e上 双层引用括号 的结果 永远都是
// 赋值表达式 也会产生 引用 引用的类型就是 等式左边变量的类型 如果 i是int i = x的类型是 int&
string str ( "some string" );
for (auto c : str ) // auto自动推断类型
cout << c << endl ;
// 范围for 引用 改变 内容
string s ( "Hello World!!!" );
for ( auto & c : s ) // c是 字符串中每个元素的一个别名
c = toupper ( c ); //变成大写
cout << s << endl ;
ประเภทตัวห้อยของสตริงคือ string::size_type หมายเลขที่ไม่ได้ลงนามสามารถรับได้โดย decltype(s.size()) s[0] เป็นอักขระตัวแรกและ s[s.size()-1] เป็นอักขระตัวสุดท้าย .
// 第一个字符改为大写
string s ( "some string" );
if (! s . empty ())
s [ 0 ] = toupper ( s [ 0 ]); //第一个字符改为大写 在 cctype头文件中
// 第一个单词改为大写
for ( decltype ( s . size ()) index = 0 ;
index != s . size () && ! isspace ( s [ index ]; ++ index ))
s [ index ] = toupper ( s [ index ]);
เนื่องจากเวกเตอร์สามารถจัดเก็บประเภทใดก็ได้ คุณต้องรู้ล่วงหน้าว่าวัตถุประเภทใดที่ถูกจัดเก็บ vector ivec; vector;
// 初始化方式
vector < int > ivec ( 10 , -1 ); // 直接初始化 10个元素 全为 -1
vector < int > ivec2 = ivec ; //拷贝初始化
vector < int > ivec3 { 10 }; //一个元素 10
vector < int > ivec3 { 10 , 1 }; //两个元素 10 和 1
vector < string > svec { "a" , "an" , "the" }; //列表初始化 直接方式
vector < string > svec2 = { "a" , "an" , "the" }; //列表初始化 拷贝方式
// 默认初始化
vector < int > ivec ( 10 ); // 10个元素,每个值都是0
vector < string > svec ( 10 ); // 10个元素,每个值都是空 string 对象
vector < string > svec2 { 10 }; // 10个元素,每个值都是空 string 对象
vector < string > svec3 { 10 , "hi" }; // 10个 "hi"元素
vector < string > svec3 ( 10 , "hi" ); // 10个 "hi"元素
// 使用 .push_back() 添加元素
vector < int > ivec2 ; //空vec对象
for ( int i = 0 ; i != 100 ; ++ i )
ivec2 . push_back ( i ); // 一次把整数值 放到 ivec2尾部 结束后 ivec2有100个元素 0~99
// 实时添加 string 元素
string word ;
vector < string > text ; //空对象
while ( cin >> word )
text . push_back ( word ); // 把word添加到 text 后面
//使用范围for + 引用 访问 并改变vector元素
vector < int > iv { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 }; // 列表直接初始化
for (auto & i : v ) // 对于v中每个 元素的 引用 需要改变其值
i *= i ; // 变成原来值 的 平方
for (auto i : v ) // 仅读取其中的变量
cout << i << " ";
cout << endl ;
// vector 对象大小 类型为size_type
vector < int > :: size_type se = iv . size ();
// 使用索引[] 访问 计算vector对象元素索引 统计各个分数段上 出现的 成绩个数
// 索引不能添加元素
vector < unsigned > scores ( 11 , 0 ); //11个分数段, 0~9,10~19,...,90~99,100 计数值全部初始化为0
unsigned grade ;
while ( cin >> grade ){
if ( grade <= 100 ) ++ scores [ grade / 10 ];
}
// cin 读入一组词 改成大写 存入 vector中 #include <cctype> 使用toupper()
vector < string > sv ;
string word1 = "qwe" ;
cout << word1 << endl ;
while ( cin >> word1 ){
for (auto & c : word1 ) c = toupper ( c );
sv . push_back ( word1 );
cout << word1 << endl ; vector
}
// 修改 字符串 第一个元素为大小字符
string s ( "some string" );
if ( s . begin () != s . end ()){ //确保 s非空
auto it = s . begin (); // it 指向 s的第一个字符 类似指针 的作用
* it = toupper ( * it ); // 将当前字符改写成大写形式 *it 解引用迭代器 得到其所指向的 对象 是其指向对象的别名 引用
}
// 字符串的第一个单词 改写成大写
for (auto it = s . begin (); it != s . end () && ! isspace ( * it ); ++ it )
* it = toupper ( * it );
// 迭代器类型 iterator (具有读写功能) const_iterator 具有 读功能 不具有写功能
// 对象为常量 只具有常量类型的迭代器 const_iterator 对象为变量具有 iterator 和 const_iterator
vector < int > :: iterator it ; // 迭代器 it 可以读写 vector<int> 类型容器 的元素
string :: iterator it2 ; // it2 可以读写 string对象 中的字符
vector < int > :: const_iterator it3 ; //it3只能读元素,不能写元素
string :: const_iterator it4 ; //it4只能读字符,不能写字符
// cbegin() cend() 返回 常量 迭代器 仅能读取 容器元素 不能修改
vector < int > iv ; // 变量
const vector < int > civ ; // 常量
auto it1 = iv . begin (); // it1的类型为 vector<int>::iterator 能读写iv的元素
auto it2 = iv . cbegin (); // it2的类型为 vector<int>::const_iterator 能读iv的元素 不能修改 iv的元素
auto it3 = civ . begin (); // it3的类型为 vector<int>::const_iterator 能读civ的元素 不能修改 civ的元素
// 访问 容器元素对象的 成员函数 (*it).empty 等同于 it->empty() 解引用 和成员访问
vector < string > text ;
for (auto it = text . cbegin (); it != text . cend () && ! it -> empty (); ++ it )
cout << * it << endl ;
// 迭代器 运算
auto mid = iv . begin () + iv . size ()/ 2 ; //指向容器的中间位置
if ( it < mid ) // 处理前半部分元素
// 两个迭代器相减 得到的类型为 带符号整数 difference_type
// 常规二分查找算法
// 升序数组 查找的元素 范围开始 结束
int BinarySearch ( int * array , int key , int low , int high )
{
int mid ;
while ( low <= high ) // 缩小范围
{
mid = ( low + high ) / 2 ; //更新中间元素的 下标
if ( key == array [ mid ]) //中间元素是否 等于所查找的元素
return mid + 1 ; //相等 返回元素下标
else if ( key < array [ mid ]) //所查元素 比 中间元素小 则在 前区间查找
high = mid - 1 ; //将区间 右侧 退后 到 中间元素下标前一个元素 搜索 范围为 low,mid-1
else //所查元素 比 中间元素大 则 在后区间查找
low = mid + 1 ; //将区间 左测 提至 中间元素下标后一个元素 搜索 范围 mid+1,high
}
return 0 ;
}
// 使用迭代器完成二分查找
vector < int > text // 升序容器
auto b = text . begin (), e = text . end (); //起始 结束位置
auto mid = b + ( e - b )/ 2 ; //中间位置
while ( low <= end && * mid != key ){
if ( key < * mid ) e = mid - 1 ; //所查元素 比 中间元素小 则在 前区间查找
else b = mid + 1 ; // 所查元素 比 中间元素大 则 在后区间查找
mid = b + ( e - b )/ 2 ; //更新 中间位置
}
// 使用索引[] 访问 计算vector对象元素索引 统计各个分数段上 出现的 成绩个数
// 索引不能添加元素
vector < unsigned > scores ( 11 , 0 ); //11个分数段, 0~9,10~19,...,90~99,100 计数值全部初始化为0
unsigned grade ;
while ( cin >> grade ){
if ( grade <= 100 ) ++ scores [ grade / 10 ];
}
// 使用迭代器 访问 计算vector对象元素索引 统计各个分数段上 出现的 成绩个数
vector < unsigned > scores ( 11 , 0 ); //11个分数段, 0~9,10~19,...,90~99,100 计数值全部初始化为0
unsigned grade ;
auto it0 = scores . begin ();
while ( cin >> grade ){
auto it = it0 + grade / 10 ;
if ( grade <= 100 ) ++ * it ;
}
อาร์เรย์จะคล้ายกับเวกเตอร์ประเภทไลบรารีมาตรฐาน ซึ่งจัดเก็บคอนเทนเนอร์ของออบเจ็กต์ประเภทเดียวกัน วัตถุจะต้องเข้าถึงได้ผ่านตำแหน่งของพวกมัน แตกต่างจากเวกเตอร์ ขนาดของอาร์เรย์ถูกกำหนดและไม่เปลี่ยนแปลง และองค์ประกอบไม่สามารถเพิ่มลงในอาร์เรย์ได้ตามต้องการ อาร์เรย์ไม่อนุญาตให้คัดลอก ในขณะที่เวกเตอร์อนุญาตให้คัดลอก โปรดทราบว่าชื่ออาร์เรย์เทียบเท่ากับที่อยู่ขององค์ประกอบแรกของอาร์เรย์ ia[10] ia === &ia[0]
constexpr unsigned sz = 42 ; //constexpr修饰,常量表达式
int arr [ 10 ]; //字面值常量初始化 含有10个整数的数组
int arr2 [ sz ]; //常量表达式初始化 含有42个个整数的数组
int * parr [ sz ]; //常量表达式初始化 含有42个指向整数的指针的数组
定义时必须指定数组类型,不能由auto来推断
不存在引用的数组,引用不是对象!!!
string nums [] = { "one" , "two" , "three" }; // 数组元素是string对象
string * sp = & nums [ 0 ]; // p指向nums的第一个元素
string * sp2 = nums ; // 等价于 string *sp2 = &nums[0]
auto sp3 ( nums ); //sp3 是一个string指针,指向nums的第一个元素
// 而decltype关键字 声明的 不发生上述转换
decltype ( nums ) sa = { "two" , "three" , "four" }; //sa 是一个 含有3个string对象的 数组
##【2】เริ่มต้นองค์ประกอบอาร์เรย์อย่างชัดเจน
const unsigned sz = 3 ; //
int ia1 [ sz ] = { 0 , 1 , 2 }; //列表初始化 含有3个元素
int ia2 [] = { 0 , 1 , 2 }; //维度为3
int ia3 [ 5 ] = { 0 , 1 , 2 }; //等价于 {0, 1, 2, 0, 0}
// 字符数组
char ca1 [] = { 'C' , 'P' , 'P' }; //列表初始化
char ca2 [] = { 'C' , 'P' , 'P' , ' ' }; //含有显式的 空字符
char ca3 [] = "CPP" ; //字符串字面值初始化 自动添加表示字符串结束的空字符
// string 对象初始化 字符数组
string s ( "Hello World" );
const char * str = s . c_str (); // 用string对象初始化 字符数组 需要使用 c_str() 方法 最好再重新拷贝一份
// 数组 初始化 vector 对象
int i_arr [] = { 1 , 2 , 3 , 4 , 5 , 6 };
vector < int > ivec ( begin ( i_arr ), end ( i_arr )); //全部副本
vector < int > sub_ivec ( i_arr + 1 , i_arr + 4 ); // 包含 {2, 3, 4, 5}四个元素
// 不允许拷贝和赋值
char ca4 = ca3 ; // 错误
// 复杂的数组声明定义
int * parr [ 10 ]; // 是数组,包含10个整形指针的数组
int & rarr [ 10 ] = ?; //错误,不存在 引用数组,引用不是对象
int ( * Parray )[ 10 ] = & arr ; //是指针,指向一个含有10个整数的数组
int ( & Rarray )[ 10 ] = arr ; //是引用,引用一个含有10个整数的数组
//下标访问修改元素
unsigned score [ 11 ]; //11个分数段
unsigned grade ;
while ( cin >> grade ){
if ( grade <= 100 ) ++ score [ grade / 10 ]; //对应段 计数+1
}
// 范围for 访问修改所有元素
for ( auto i : score ) //可以设置为 引用就可以修改元素了
cout << i << " ";
cout << endl ;
// 指针访问数组
int iarr [] = { 0 , 1 , 2 , 3 , 4 }; //含有5个元素
int * pi = iarr ; //指向第一个元素的指针 iarr[0]
int * pi2 = iarr + 2 ; //指向第三个元素的指针 iarr[2]
auto num = end ( iarr ) - begin ( iarr ); // num的值是5 就是iarr包含元素的数量
// ptrdiff_t 类型 是signde类型 结果可能为负
++ pi ; //指向第二个元素 iarr[1]
j = pi [ 1 ]; // 等价于 *(p+1),就是 iarr[2], 就是 2
k = pi [ -1 ]; // 等价于 *(p-1),就是 iarr[0], 就是 0
pi + 3 ; //指向最后一个元素
* pi ; //第二个元素 4
int last = * ( iarr + 4 ); // 等价于 last = iarr[4];
int * end = & iarr [ 6 ]; //指向尾后的位置 到达不了 不能执行解引用运算!!!!!
// 使用 for
fot ( int * begin = arr ; begin != end ; ++ begin )
cout << * begin << endl ; //输出每一个元素
// 使用 while
while ( begin < end ){ //指针指向相关的对象 可以比较大小(单位(间隔)一样大)
cout << * begin << endl ; //输出每一个元素
++ begin ;
}
//标准库函数 begin() end() 函数得到指针
int iarr = { 0 , 1 , 2 , 3 , 4 }; //函数5个元素
int * beg = begin ( iarr ); //首元素指针
int * end = end ( iarr ); //尾后指针 不能执行解引用运算!!!!!
while ( beg != end && * beg >= 0 ) ++ beg ; //找第一个负值元素
constexpr size_t row = 3 , col = 4 ;
int iarr [ row ][ col ]; //定义未初始化
//下标运算符(size_t 类型) for 循环初始化
for ( size_t i = 0 ; i != row ; ++ i ){
for ( size_t j = 0 ; j != col ; ++ j ){
iarr [ i ][ j ] = i * col + j ; //元素索引为其 值
cout << iarr [ i ][ j ] << ' ' ; // 访问输出 数组元素
}
cout << endl ;
}
// 范围for 初始化
size_t cnt = 0 ;
for (auto & row1 : iarr ) //每一行 引用 int (&row1)[4] 是引用 引用一个含有4个整数的数组
{
for (auto & col1 : row1 ){ // int &col1 每一行的每一个元素 引用 可以读写 除去最内层外 其它必须使用 引用
col1 = cnt ; //赋值
cout << col1 << ' ' ; // 访问 输出数组元素
++ cnt ;
}
cout << endl ;
}
// 指针访问
int ( * p )[ 4 ] = iarr ; //p 指向一个含有4个整数的数组 iarr的 第一行 圆括号必不可少
p = & iarr [ 2 ]; // iarr的 第3行
// for 循环访问
for ( auto p = ia ; p != ia + row ; ++ p ){ // 相当于定义 int (*p)[4] = iarr; p 指向 含有4个整数的数组
for ( auto q = * p ; q != * p + col ; ++ q )
// *p 为含有4个元素的数组 q指向数组的首元素,即指向一个整数 int *q = *p
cout << * q << ' ' ;
cout << endl ;
}
// 使用 标准库函数 begin() 和 end()
for ( auto p = begin ( ia ); p != end ( ia ); ++ p ){
// 相当于定义 int (*p)[4] = iarr; p 指向 含有4个整数的数组
for ( auto q = begin ( * p ); q != end ( * p ); ++ q )
// *p 为含有4个元素的数组 q指向数组的首元素,即指向一个整数 int *q = *p
cout << * q << ' ' ;
cout << endl ;
}
// 使用类型别名
using int_arr_tpye = int [ 4 ]; // int_arr_tpye为包含4个元素的整形数组
typedef int int_arr_tpye [ 4 ]; // 效果同上
for ( int_arr_tpye * p = ia ; p != ia + row ; ++ p ){ // 相当于定义 int (*p)[4] = iarr; p 指向 含有4个整数的数组
for ( int * q = * p ; q != * p + col ; ++ q ) // *p 为含有4个元素的数组 q指向数组的首元素,即指向一个整数
cout << * q << ' ' ;
cout << endl ;
}
รวม: ชื่อฟังก์ชันประเภทส่งคืน (รายการพารามิเตอร์ที่เป็นทางการ) เนื้อหาของฟังก์ชันประเภทส่งคืนของฟังก์ชันไม่สามารถเป็นอาร์เรย์หรือประเภทฟังก์ชันได้ แต่สามารถเป็นตัวชี้ไปยังอาร์เรย์หรือประเภทฟังก์ชันได้
int fact ( int val ){
int ret = 1 ;
while ( val > 1 ) ret *= val -- ;
return ret ; // 返回主调函数 结束函数调用
}
int main (){
int j = fact ( 5 ); // 实参5 初始化 形参(int val)
cout << "5! = " << j << endl ;
return 0 ;
}
พารามิเตอร์ที่เป็นทางการและตัวแปรที่กำหนดไว้ในส่วนเนื้อหาของฟังก์ชันจะเรียกรวมกันว่าตัวแปรภายในเครื่อง ซึ่งจะมองเห็นได้เฉพาะภายในขอบเขตของฟังก์ชันเท่านั้น ออบเจ็กต์อัตโนมัติในเครื่องจะมีอยู่เฉพาะในระหว่างการดำเนินการของตัวฟังก์ชัน ในขณะที่ออบเจ็กต์คงที่ในเครื่องสามารถมีอยู่ได้หลังจากเรียกใช้ฟังก์ชันแล้ว .
// 定义
int count_call ( void ){
int c = 0 ; //局部自动对象 每一次调用都初始化为 0
static int sc = 0 ; //局部静态变量 第一次调用初始化为0 以后每次调用在前一次值上 +1
cout << ++ sc << " " << ++ c << endl ;
}
// 调用
int main (){
for ( int i = 0 ; i < 10 ; ++ i ) count_call (); //sc 输出 1 2,...10,c 输出一直是1
return 0 ;
}
// 源文件 fact.cc
#include "fact.h"
int fact ( int val ){
int ret = 1 ;
while ( val > 1 ) ret *= val -- ;
return ret ; // 返回主调函数 结束函数调用
}
// 函数声明头文件 fact.h
#ifndef FACT_H
#define FACT_H
int fact ( int val ); // 函数声明
#endif
// 主函数调用 fact_main.c
#include <iostream>
#include "fact.h"
using namespace std ;
int main (){
int j = fact ( 5 ); // 实参5 初始化 形参(int val)
cout << "5! = " << j << endl ;
return 0 ;
}
// 编译
gcc fact_main . c fact . cc - o main
เมื่อพารามิเตอร์ที่เป็นทางการเป็นประเภทอ้างอิง มันจะถูกส่งผ่านโดยการอ้างอิง สิ่งที่ส่งผ่านจริง ๆ คือนามแฝงของพารามิเตอร์จริง และไม่มีการคัดลอกเมื่อค่าของพารามิเตอร์จริงถูกคัดลอกไปยังพารามิเตอร์ที่เป็นทางการ พารามิเตอร์ที่เป็นทางการ และพารามิเตอร์จริงเป็นวัตถุอิสระสองตัว
int n = 0 ;
int i = n ; // n拷贝给i
i = 42 ; //i的值改变, n的值不变 函数对形参做的所有操作 都不会影响实参 例如 fact(i) 不会改变i的值
int n = 0 ;
int & r_i = n ; //r_i 是 n 的引用 即别名 同一个变量
r_i = 42 ; //r_i 和 n 都变成 42
int n = 0 , i = 42 ;
int * p_n = & n , * p_i = & i ; // 指针
* p_n = 100 ; // n 的值 变为100 指针p_n(变量你存储的地址) 不变
p_n = p_i ; // 现在 p_n 和 p_i 都指向了 i
// 指针形参 函数
void reset ( int * pi ){
* ip = 0 ; //改变了指针 pi 所指向的对象的值
ip = 0 ; // 值改变了 形参ip的值 实参未被改变
}
// 调用
int i = 42 ;
cout << "address of i =" << & i << endl ;
reset ( & i ); // i 的值改变为0
cout << "i = " << i << endl ; // i 的值改变为0
cout << "address of i =" << & i << endl ; // i 的存储地址未改变
// C 程序中 通常使用 指针类型的形参 来访问和改变 函数外部的对象
// C++ 程序中,建议使用引用类型的形参代替 指针形参,这样会更安全,也省时间(引用 无拷贝操作)
// 使用 引用避免拷贝 拷贝大的类对象或容器 都比较低效 费时
void reset ( int & i ){
i = 0 ; // 改变了i所引用的对象
}
// 调用
int j = 42 ;
reset ( j ); // 采样传 引用方式,它的值被改变 调用时 形参i 只是 实参j的一个别名,在函数reset内部对i的操作,即对j的使用
cout << "j = " << j << endl ;
// 比较两个字符串的长度
bool isShorter ( const string & rs1 , const string & rs2 ){
return rs1 . size () < rs2 . size ();
}
// 函数返回多个值 返回字符在某个字符串中第一次出现的位置,并返回出现的 总次数
string :: size_type find_char ( const string & crs , char c , string :: size_type & occurs ){
// 字符串 查找的字符 出现的次数
auto ret = crs . size (); //初始化 第一次出现的位置
occurs = 0 ; //初始化 出现的次数
for ( decltype ( ret ) i = 0 ; i != crs . size (); ++ i ){
if ( crs [ i ] == c ){ // 出现字符 c
if ( ret == crs . size ()) //位置 还未改变 为 第一次出现
ret = i ; //记录第一次出现的位置
++ occurs ; //出现次数 +1 通过形参引用间接返回 出现的次数
}
}
return ret ; //返回第一次出现的位置
}
// 调用
string s ( "some string" );
string:: size_type count = 0 ;
auto index = find_char ( s , 'o' , count );
// 判断 string对象是否是 一个句子
bool is_sentence ( const string & crs ){
// 如果 find_char() 的string参数 必须为 string & 那么不能直接把 const string & 带入
// 需要再定义一个 string对象, 另其为 crs 的副本,再带入
string:: size_type count = 0 ;
return ( find_char ( crs , '.' , count ) == ( crs . size () - 1 )) && count == 1 ;
}
1 不允许拷贝数组
2 在使用数组时会将其转换成指针(指向数组首元素的指针)
// 三个函数等价 形参 都是 const int * 类型
void print ( const int * );
void print ( const int []);
void print ( const int [ 10 ]); // 这里的维度表示期望数组含有多少元素,实际不一定
//调用
int i = 0 ;
j [ 2 ] = { 0 , 1 };
print ( & i ); //&i 是int *类型 可以赋值给 const int *类型
print ( j ); //j 为 &j[0] 是 int * 类型
// C风格字符串 带有一个空字符
void print ( const char * cp ){
if ( cp ) // 确定 cp 不是一个空指针
while ( * cp ) // 只要 指针所指的字符不是 空字符
cout << * cp ++ ; // 打印 字符
}
void print ( const int * beg , const int * end ){
while ( beg != end )
cout << * beg ++ << endl ; //输出当前元素 并将指针向前移动一个位置
}
// 调用
int j [ 2 ] = { 0 , 1 };
print ( begin ( j ), end ( j )); // 使用标准库 begin() 和 end() 函数
void print ( const int ia [], size_t size ){
for ( size_t i = 0 ; i != size ; ++ i )
cout << ia [ i ] << endl ; // 等价于 cout << *(ia+i) << endl;
}
// 调用
int j [ 2 ] = { 0 , 1 };
print ( j , end ( j ) - begin ( j ) ); // 使用标准库 begin() 和 end() 函数 做差来得到数组的大小
void print ( int ( & r_arr )[ 10 ]){ // 注意形式 int (&r_arr)[10] 而 int &arr[10] 成了 包含引用的数组(还不存在,引用不是对象)
for (auto elem : r_arr ) // 变量数组每个元素 范围for
cout << elem << endl ;
}
// 调用 调用时 必须是 大小为10的整形 数组作为实参才可以
int k [ 10 ] = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 }
print ( k ); // 大小必须为10 多一点 少一点 都不行
void print ( int ( * p_arr )[ 10 ], int rowSize ){} // 形参是 指向 一个含有10个整数的指针
// argc:argument counter 参数计数,argv:argument vector 参数 字符串 容器
int main ( int argc , char * argv []){}
int main ( int argc , char * * argv ){} //第二个参数为 字符串数组 即数组的数组 指针的指针 argv 指向 char*
//程序执行 program -d -o outfile data0
则 argc = 5
argv [ 0 ] = "program" ; // 程序名
argv [ 1 ] = "-d" ; // 第一个参数 开始
argv [ 2 ] = "-o" ; // 第二个参数
argv [ 3 ] = "outfile" ; // 第三个参数
argv [ 4 ] = "data0" ; // 第四个参数 最后一个指针
argv [ 5 ] = 0 ; // 最后一个指针之后 的元素为0
// initializer_list 提供的操作
initializer_list < T > lst ; // 默认初始化 T类型元素的空列表 模实际需要指定模板T的 具体类型
initializer_list < T > lst { a , b , c ...}; // 列表中的元素是 const 常量
lst2 ( lst ); // 拷贝一个initializer_list对象,不会新建,原始列表 和 副本 共享元素
lst2 = lst ; // 同上
lst . size (); // 列表 中的元素
lst . begin (); //返回指向lst中首元素的指针
lst . end (); //返回指向lst中尾元素下一个位置的指针
// 因为有 begin() 和 end()对象可以使用 范围for 遍历参数
// 具体
initializer_list < string > ls ; //initializer_list 的元素类型是 string
initializer_list < int > li ; //initializer_list 的元素类型是 int
// 和vector不同的是 initializer_list中的元素是常量 不能被修改
// 定义函数
void error_msg ( initializer_list < string > ls ){
for (auto beg = ls . begin (); beg != ls . end (); ++ beg )
cout << * beg << " " ;
cout << endl ;
}
//调用函数
//expected 和 actual 是string 对象
if ( expected != actual )
error_msg ({ "function" , expected , actual });
else
error_msg ({ "function" , "okey" });
// 传递了一个含有不同数量元素的 initializer_list
// 定义函数 包含 ErrCode
void error_msg ( ErrCode e , initializer_list < string > ls ){
cout << e . msg () << ": "
for ( const auto & elem : ls ) //范围for 遍历
cout << elem << " " ;
cout << endl ;
}
void foo ( param_list , ...) //
void foo ( param_list ...) //
void foo (...) //
// 交换两个值的函数
void swap ( int & r_i1 , int & r_i2 ){
if ( r_i1 == r_i2 ) // 两个值相等 无需交换
return ;
// 若 执行 到这里,说明还需要继续完成下面的功能
int temp = r_i1 ; //
r_i1 = r_i2 ;
r_i2 = temp ;
// 此处 无需 显示的 return 语句 会隐式指向 return
}
// 两个 string 对象是否 最短的部分 是相同的
bool str_subrange ( const string & str1 , const string & str2 ){
if ( str1 . size () == str . size ())
return str1 == str2 ; // 之间判断 相同长度间的部分是否相同
auto size = ( str1 . size () < str2 . size ()) ? str1 . size () : str2 . size (); //得到最短 字符串的 长度
for ( decltype ( size ) i = 0 ; i != size ; ++ i ){
if ( str1 [ i ] != str2 [ i ]) // 如果 有 不相等的 字符 返回 false
return false; // 有 不相等的 字符 返回 false
}
return true; // 否者 相等 返回 true
}
// 不要 返回 函数内部 临时变量的 引用
string temp ( "glo" );
const string & mainip () {
string ret ( "Empty" ); // 函数内部临时变量
return ret ; // 错误 ,不能返回 临时变量 作为 函数返回值的 引用
// return temp;// 返回 一个调用函数之前就出现的 变量 的引用 或者 参数 为引用类型的参数也可以
}
// 返回 两个字符串中 短的那个
const string & shortString ( const string & s1 , const string & s2 ){ // 返回 s1 或者 s2的引用
return s1 . size () < s2 . size () ? s1 : s2 ; //返回 两个字符串中 短的那个
}
// 函数返回类型 为 标准库 类类型 可以直接调用 其成员函数
auto sz = shortString ( s1 , s2 ). size () // 得到最短字符串 的长度
// 返回 非常量的引用 可以作为 左值 被赋值
char & get_char ( string & str , string :: size_type id ){
return str [ id ]; // 获取指定位置的 字符
}
// 调用
string s ( "a value" );
cout << s << endl ; // a value
get_char ( s , 0 ) = 'A' ; // 将s第一个位置上的字符 替换为 大写的 A
cout << s << endl ; // A value
// 而返回为 常量引用 的不能被赋值
shortString ( "hi" , "bye" ) = "X" ; // 错误 函数返回值是个 常量引用 不能被赋值
vector < string > process (){
if ( expected . empty ())
return {}; // 返回一个 空vector对象
else if ( expected == actual )
return { "function" , "okey" };
else
return { "function" , expected , actual };
}
// 计算阶乘的函数
int factorial ( int val ){
if ( val > 1 )
return val * factorial ( val - 1 );
else
return 1 ;
}
// 递归 返回一个vector的元素函数
void print_vec ( vector < int > vi ){
auto it = vi . begin ();
if ( vi . size () > 1 )
{
cout << * it << endl ;
vi . erase ( it );
print_vec ( vi );
}
else
cout << * it << endl ;
}
// 使用类别别名
typedef int arrT [ 10 ]; // arrT是一个类别别名 表示一个 含有 10个整数 的 数组
using arrT = int [ 10 ]; // 同上
arrT * func ( int i ); // 函数func 返回一个 指向 10个整数的数组的 指针
//直接声明
int arr [ 10 ]; //arr 是一个 含有 10个整数的数组
int * arr_p [ 10 ]; //arr_p 是一个数组 含有 10个指整形针 的 数组
int ( * p2 )[ 10 ] = & arr ; // p2 是一个指针, 指向一个含有 10个整数的 数组 arr
// 函数声明 类似
Type ( * function_name ( parameter_list ))[ dimension ]
int ( * func ( int i ) )[ 10 ]; // 声明一个函数 其形参为 int i ,返回类型 为 指针 ,指向 一个 含有 10个整数的 数组
// 函数指针数组
多个函数可以像数组一样被调用
int ( * fun_p_a [])( char * tmp ); //函数指针数组
// 使用 auto 和 尾置返回类型
auto func ( int i ) -> int ( * )[ 10 ]; // 声明一个函数 其形参为 int i ,返回类型 为 指针 ,指向 一个 含有 10个整数的 数组
// 使用 decltype 知道返回数组 类似类别别名 声明 定义
int odd [] = { 1 , 3 , 5 , 7 , 9 };
int even [] = { 0 , 2 , 4 , 6 , 8 };
decltype ( odd ) * arrPtr ( int i ){ //使用decltype(odd) 表面类型与 odd类似
return ( i % 2 ) ? & odd : & even ; // 返回一个指向数组的指针
}
// 声明一个 返回 引用 一个 含有10个string对象的数组 的函数
string ( & func_r ( string str ) )[ 10 ]; // 直接声明
// 使用类别别名
typedef string arrS [ 10 ]; // 类别别 含有10个string对象的数组
using arrS = string [ 10 ]; // 同上
arrS & func ( string str ); // 函数func 返回一个 指向 10个整数的数组的 指针
// 使用 auto 和 尾置返回类型
auto func ( string str ) -> string ( & )[ 10 ];
// 使用 decltype 知道返回数组 类似类别别名 声明 定义
string str_arr [] = { "a string" , "two" };
decltype ( str_arr ) & arrPtr ( string str );
// 打印 数组元素的 几个 同名函数
void print ( const char * cp ); //出入参数为 带有结束符的