内存四区:代码区,全局区,栈区,堆区
## 引用'&'
给变量起别名。
注意:1.必须初始化 2.不可改变
引用的是堆区和栈区
"&"符号进行引用:
int a=10;(定义一个变量)
int & b=a;(给b初始化,即为给a一个别名,而b也就是a)
b=20;(给b赋值为20,也就是给a赋值为20)
cout<<a<<b;(可看见a,b输出的值均为20)
C++ 函数可以返回一个引用,方式与返回一个指针类似。
##### 引用做函数的返回值
注意:1. 不要返回局部变量的引用 2. 函数的调用可以作为左值
可以用:static int a=10;即为静态变量,存放在全局区,其在程序结束才释放
##### 引用的本质
在C++内部实现是一个指针常量(即可以更改所指对象的值但不可以更改地址)
int&p=a;
就等价于:int *const p=&a;
##### 常量引用
作用:修饰形参,防止误操作。加const修饰形参,防止形参改变实参
## NEW
##### new的基本语法
int *func()
{
int *p =new int(10)
//堆区创建整型数据,new返回的是该数据的指针
return p;
}
void test01()
{
int *p=func();
cout<<*p<< endl;
//在堆区 由程序员开辟 由程序员释放
//释放数据 利用 delete即可
delete p;//即已把p的值释放
}
int main()
{
test01();
}
##### 利用new开辟数组
void test02()
{
int*arr= new int[10];
for(int i=0;i<10;i++)
{
arr[i]=i+100;
}//给数组赋值
for(int i=0;i<10;i++)
{
cout<<arr[i]<<endl;
}//打印数组
delete[]arr;//释放数组
}
int main()
{
teat02();
}
## 指针
1. 使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。通过使用一元运算符 ***** 来返回位于操作数所指定地址的变量的值。
#include <iostream>
using namespace std;
int main ()
{
int var = 20; // 实际变量的声明
int *ip; // 指针变量的声明
ip = &var; // 在指针变量中存储 var 的地址
cout << var << endl;
// 输出在指针变量中存储的地址
cout << ip << endl;
// 访问指针中地址的值
cout << *ip << endl;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
20
0xbfc601ac
20
##### 空指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为**空**指针。NULL 指针是一个定义在标准库中的值为零的常量。
#include <iostream>
using namespace std;
int main ()
{ int *ptr = NULL;
cout << ptr ;
return 0;}
}
// ptr 的值是 0
//注意的是,空指针不可以访问
##### 指针递减递加
递加:从数组第一个开始
int *ptr;
ptr=array;
cout <<*ptr;
ptr++;
递减:
int *ptr;
ptr=&array[arraysize];
cout <<*ptr;
ptr--;
##### 指针的比较
指针可以进行大小比较,比如同一个数组中的不同元素。
## 数组
##### 二维数组
二维数组中的元素是通过使用下标(即数组的行索引和列索引)来访问。如:int val = a[2][3];
##### 指向数组的指针
数组名是指向数组中第一个元素的常量指针。e.g: double runoobAarray[50]; 其中**runoobAarray** 是一个指向 &runoobAarray[0] 的指针,即数组 runoobAarray 的第一个元素的地址(使用数组名作为常量指针是合法的。 p.s: 常量指针是指指针指向其地址但内容是不可改变的)。因此,下面的程序片段把 **p** 赋值为 **runoobAarray** 的第一个元素的地址:
double *p;
double runoobAarray[10];
p = runoobAarray;
*(runoobAarray + 4) 是一种访问 runoobAarray[4] 数据的合法方式。
把第一个元素的地址存储在 p 中,就可以使用 *p、*(p+1)、*(p+2) 等来访问数组元素。
#include <iostream>
using namespace std;
int main ()
{
double runoobAarray[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
p = runoobAarray;
// 输出数组中每个元素的值
cout << "使用指针的数组值 " << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "*(p + " << i << ") : ";
cout << *(p + i) << endl;
}
cout << "使用 runoobAarray 作为地址的数组值 " << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "*(runoobAarray + " << i << ") : ";
cout << *(runoobAarray + i) << endl;
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
使用指针的数组值
*(p + 0) : 1000
*(p + 1) : 2
*(p + 2) : 3.4
*(p + 3) : 17
*(p + 4) : 50
使用 runoobAarray 作为地址的数组值
*(runoobAarray + 0) : 1000
*(runoobAarray + 1) : 2
*(runoobAarray + 2) : 3.4
*(runoobAarray + 3) : 17
*(runoobAarray + 4) : 50
##### 传递数组给函数
可以通过指定不带索引的数组名来传递一个指向数组的指针。当传数组给一个函数时,数组类型自动转换为指针类型,因而传的实际是地址。
##### 从函数返回数组
C++ 不允许返回一个完整的数组作为函数的参数。C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 **static** 变量。
如果想要从函数返回一个一维数组,必须声明一个返回指针的函数,如下:
int * myFunction()
{
.
.
.
}
## 字符串
字符串实际上是使用 **null** 字符 \0 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
声明和初始化创建了一个 **RUNOOB** 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 **RUNOOB** 的字符数多一个。
char site[7] = {'R', 'U', 'N', 'O', 'O', 'B', '\0'};
依据数组初始化规则,可以把上面的语句写成以下语句:
char site[] = "RUNOOB";
##### 注意:
如下代码段,当遇到字符中的数字时,想使用时要转换成int整数,利用:(str[i] - '0')的表示。
string str;
cin >> str;
double value1 = 0;
for (int i = 0; i < str.length(); i++)
{
if (isdigit(str[i]))
{
int a = 0;
value1 = ((str[i]-'0') * pow(16, str.length() - 1 - i));
}
## 函数
1. setw() 函数: 用于设置字段的宽度,只对紧接着的输出产生作用。 setw(n), n 表示宽度,用数字表示。可以setfill()配合使用设置其他字符填充。setw和setfill 被称为输出控制符,使用时需要在程序开头写上#include "iomanip",否则无法使用。
2. C++ 中有大量的函数用来操作以 null 结尾的字符串:
| 序号 | 函数 & 目的 |
| --- | --- |
| 1 | **strcpy(s1, s2);**<br>复制字符串 s2 到字符串 s1。 |
| 2 | **strcat(s1, s2);**<br>连接字符串 s2 到字符串 s1 的末尾。连接字符串也可以用 + 号,例如:<br><br><br>string str1 = "runoob";<br>string str2 = "google";<br>string str = str1 + str2; |
| 3 | **strlen(s1);**<br>返回字符串 s1 的长度。 |
| 4 | **strcmp(s1, s2);**<br>如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0。 |
| 5 | **strchr(s1, ch);**<br>返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。 |
| 6 | **strstr(s1, s2);**<br>返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。 |
##### 缺省值
即函数形参的默认值。
注意:1. 有默认值的往右写 2.如果函数声明有默认参数,函数实现就不能有默认参数。所以函数声明和实现只能有一个有默认值
##### 占位参数
函数的形参列表里可以有占位参数,但调用时必须填补位置
##### 函数重载
在同一个作用域下,函数名相同且类型、个数、顺序不同。注意:返回值不可以作为其条件
## I/O 库头文件
下列的头文件在 C++ 编程中很重要。
| 头文件 | 函数和描述 |
| --- | --- |
| <iostream> | 该文件定义了 **cin、cout、cerr** 和 **clog** 对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。 |
| <iomanip> | 该文件通过所谓的参数化的流操纵器(比如 **setw** 和 **setprecision**),来声明对执行标准化 I/O 有用的服务。 |
| <fstream> | 该文件为用户控制的文件处理声明服务。我们将在文件和流的相关章节讨论它的细节。 |
##### 标准错误流(cerr)
预定义的对象 **cerr** 是 **iostream** 类的一个实例。cerr 对象附属到标准输出设备,通常也是显示屏,但是 **cerr** 对象是非缓冲的,且每个流插入到 cerr 都会立即输出。
##### 标准日志流(clog)
预定义的对象 **clog** 是 **iostream** 类的一个实例。clog 对象附属到标准输出设备,通常也是显示屏,但是 **clog** 对象是缓冲的。这意味着每个流插入到 clog 都会先存储在缓冲区,直到缓冲填满或者缓冲区刷新时才会输出。
## 数据结构
C/C++ 数组允许定义可存储相同类型数据项的变量,但是**结构**是 C++ 中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
定义结构,必须使用 **struct** 语句。struct 语句定义了一个包含多个成员的新的数据类型。
在结构定义的末尾,最后一个分号之前,可以指定一个或多个结构变量(也可以在main函数中定义变量)。
##### 访问结构成员
使用成员访问运算符: ' . '
##### 结构体作为函数参数
传参方式与其他类型的变量或指针类似。
##### 指向结构的指针
与定义指向其他类型变量的指针相似。把 & 运算符放在结构名称的前面。为了使用指向该结构的指针访问结构的成员,必须使用 -> 运算符。
##### typedef 关键字
## C++ 类 & 对象
关于类的碎碎念:
类定义了如何表示和控制数据。成员函数归类所有,描述了操纵类数据的方法。
cout.put()是一个成员函数。只能通过类的特定对象来使用成员函数,必须用句点将对象名和函数名称连接。句点被称为成员运算符。
##### C++类定义
以关键字 **class** 开头,后跟类的名称。类的主体是包含在一对花括号中。类定义后必须跟着一个分号或一个声明列表。
##### 定义 C++ 对象
类提供了对象的蓝图,基本上,对象是根据类来创建的。声明类的对象,就像声明基本类型的变量一样。
##### struct 和 class的dif
struct默认权限为公共;class默认权限为私有。
##### 封装
含义一:将属性行为作为一个整体,并加以权限控制。(一般属性用变量,行为用函数。)
含义二:类在设计时,可以把属性和行为放在不同的权限下,加以控制。访问权限有三种:public(公共), protected(保护), private(私有)。只有public在类内类外可以访问,其他的只能访问类内。
##### 构造函数
主要作用于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。语法如下:
类名(){}
没有返回值也不写void;函数名和类名一样;可以有参数
##### 析构函数
主要作用于对象销毁前系统自动调用,执行一些清理工作。
~类名(){}
没有返回值也不写void;函数名与类名一样但是有“ ~ ”;不能有参数
##### 成员函数
成员函数可以定义在类定义内部,或者单独使用**范围解析运算符 ::** 来定义。(在 :: 运算符之前必须使用类名。)在类定义中定义的成员函数把函数声明为**内联**的。