文章目录
复合类型有数组,字符串,结构,指针
1.数组(array)是一种数据格式,存储多个同类型的值。
数组声明需指出三点:
- 存储在每个元素中的值的类型
- 数组名
- 数组中的元素数
short months[12];
//创建一个名为months的数组,有12个元素,每个元素都可以存储一个short类型的值
下标或者索引从零开始,例如months[11]是months数组的最后一个元素。超过下标范围,编译器不会指出错误,但可能会破坏数据或代码,导致程序异常终止。
中括号值必须是整数或const值,也可以是常量表达式,它不能为变量。
称为复合类型的原因,不单称为数组,而是short数组,强调它是使用其他类型来创建的。
C++输出数组分两种情况:字符型数组和非字符型数组
只有定义数组时才能使用初始化,初始化数组时等号可省略。
不能将一个数组赋值给另一个数组,但可以使用下标分别给数组赋值,没赋值的元素编译器设置为0。
int months[12];
months[0] = 1;
months[1] = 2;
cout << months << endl; //会把数组名当作地址来输出
cout << "months[0] sizeof= " << sizeof months[0]<<endl;
cout << "months sizeof= " << sizeof months<<endl;
//输出数组内容需要用到循环
for (int i = 0; i < 12; i++) {
cout << months[i] << " ";
}
cout << endl;
char days[7] = {'1','2'};//初始化
//字符数组名会当作字符串输出
cout << days << endl;
//想要字符数组地址,需要强制转换,void *是空指针类型
cout << static_cast <void*> (days) << endl;
//结果
000000C65E4FFA58
months[0] sizeof= 4
months sizeof= 48
1 2 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460
12
000000C65E4FFAC4
模板类vector和array是数组的替代品。
vector也是一种动态数组,使用时必须包含头文件vector,命名空间std。存储在自由存储区
创建一个名为vt的vector对象,可存储n_elem个类型为typename的元素。n_elem可以是整型变量,也可以是整型常量
vector<typename> vt(n_elem);
array(C++11)位于命名空间std,需要头文件array。array对象的长度是固定的,也使用栈(静态内存分配),不是自由存储区,效率与数组相同,但更安全,更方便。
创建一个名为arr的array对象,包含n_elem个类型为typename的元素
array<typename, n_elem> arr;
与vector不同的是,n_elem不能是变量
2.字符串是存储在内存的连续字节中的一系列字符。
C++两种处理字符串的方式,一种C-风格字符串,另一种string类库方法
可以将字符串存储在char数组中。C-风格字符串的特殊性质:以空字符结尾,被写作\0。
char cat[5]={'d','g','h','j','\0'};
C++处理字符串的函数是逐个处理字符串中的字符,直到空字符为止。若数组中没有空字符,cout会把数组字符全打出,接着将内存中随后的字节打出直到遇到空字符。
以上太罗嗦,有好用方法字符串常量,隐式的包括了空字符。
char cat[5]="dghj";
字符串存储到数组的方法:数组初始化为字符串常量,将输入读入到数组中。
strlen()函数返回的是存储在数组字符串的长度,而不是数组本身的长度,它只计算可见的字符,空字符不会计算在内。
char cat[10];
static char dog[10] = "string";
cin >> cat;
cout << cat << endl;
cout << strlen(cat) << endl;
cout << dog << endl;
cout << dog[2];
//结果
dfgh dlfk
dfgh
4
string
r
输入和输出显示有差别,是因为,cin使用空白(空格、制表符、换行符)来确定字符串结束的位置,所以只读取了一个单词并将其放入数组中,且自动添加空字符。第二个单词就留在输入队列中,第二次输入时读取并放到另一个数组中。
istream类中提供了一些面向行的类成员函数:***getline()和get()***都是读取一行输入直到换行符。
**getline()**通过回车键输入的换行符来确定输入结尾,会自动添加空字符。
有两个参数,一个数组名称,一个读取的字符数(空字符会占一个)。
停止方式:
读取指定数目的字符
遇到换行符。
char cat[20];
static char dog[20] = "string";
cin.getline(cat,20);
cout << cat << endl;
cout << strlen(cat) << endl;
cout << dog << endl;
//结果
cnv \ndcd
cnv \ndcd
9
string
**get()**有几种变体,一种与getline()类似,区别是get不再读取并丢弃换行符,会留在输入队列中。所以连续两次调用get(),第二个get()读取到换行符视为已到达行尾。
另一种变体,没有参数,可读取下一个字符,用来处理换行符。
get还能将两个类成员拼接起来。cin.get(cat, 20).get();
读取空行后将设置失效位(failbit),意味着接下来的输入会被阻断,需恢复输入,用以下命令:cin.clear();
char cat[20];
static char dog[20] = "string";
cin.get(cat,20);
cout << cat << endl;
cin.get(cat, 20);
cout << cat << endl;
cout << strlen(cat) << endl;
cin.get(cat,20);
//结果
ggrksdmkd ff
ggrksdmkd ff
0
处理字符串的第二种方法:string类库
使用string类,程序必须包含头文件string,位于名称空间std中,必须提供using编译指令。string类定义隐藏了字符串的数组性质,使得字符串可以像普通变量一样对待,是string类和字符数组主要区别。
类设计可以使程序能够自动处理string的大小。
一个string对象可以赋值给另一个string对象。
#include <iostream>
#include <string>
using namespace std;
int main() {
string cat = "fish.";
string dog = "tone";
cout << cat << endl << dog << endl;
cat = dog;
cat += dog;//能附加
cout << cat << endl << dog << endl;
return 0;
}
//结果
fish.
tone
tonetone
tone
头文件cstring提供函数完成字符串赋值等操作
**strcpy()**函数可以将字符串复制到字符数组中
**strcat()**函数将字符串附加到字符数末尾
#include <iostream>
#include <string>
#include<cstring>
using namespace std;
#pragma warning(disable:4996) //vs会报警显示不安全,这个可以关
int main() {
char char1[20];
char char2[20]="carrots";
strcpy(char1, char2);
cout << char1<<endl;
strcat(char1, "like");
cout << char1 << endl;
}
//结果
carrots
carrotslike
注意数组和string的使用句法不同
char char1[20];
string str1;
cin.getline(char1, 20);//getline是一个类方法
cout << "char1= " << char1 << endl;
getline(cin, str1);//getline是一个普通函数
cout << "str1= " << str1 << endl;
//结果
cxf ghh
char1= cxf ghh
bbv bfg
str1= bbv bfg
C++11新增一种类型——原始字符串,在原始字符串中,字符就表示自己,例如\n不表示换行符只表示两个常规字符。默认定界符是 “( 和 )” ,并使用前缀R来标识原始字符串,语句要用到 “( 和 )” ,可以使用 “+*( 和 )+乘号” 做定界符
cout << R"(Tin "king" uses "\n" . )";
cout << R"+*(Tin "king" uses "\n" . )+*";
//结果
Tin "king" uses "\n" .Tin "king" uses "\n" .
3.结构可以储存多种类型的数据
结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。
C++允许在声明结构变量时省略关键字struct
声明放在函数外面被称为外部声明,可以被其后面任何函数所使用。
内部声明只能被该声明所属函数所使用
结构初始化等号可省略
不允许缩窄转换
结构可以将string类作为成员
除了成员变量还可以有成员函数
声明结构体类型仅仅是声明了一个类型,系统并不为之分配内存,就如同系统不会为类型 int 分配内存一样。只有当使用这个类型定义了变量时,系统才会为变量分配内存。所以在声明结构体类型的时候,不可以对里面的变量进行初始化
#include <iostream>
#include <string>
using namespace std;
struct inflatable { //外部声明,结构体类型
char name[20]; //可以写成 string name;
float valume;
double price;
};
int main() {
//inflatable成为类型,使用成员运算符 . 来访问各成员,格式为:结构体变量名.成员名
//hat成为一个结构,hat.name为char变量
inflatable hat = { //内部声明
"Gloat",
1.88,
29.9
};
cout << hat.name << endl;
inflatable cup;
cup = hat;
cout << cup.price << endl;
return 0;
}
//结果
Gloat
29.9
可以使用赋值运算符将结构赋值给另一个同类型结构,这种赋值称为成员赋值(memberwise assignment)
对字符数组型结构体成员进行赋值时一定要使用strcpy()
strcpy(cat.name, “咪咪”); //正确
cat,anme=dog.name; //错误
结构体定义格式
有一种方式同时完成定义结构和创建结构变量:将变量名放在结束括号的后面即可
struct 结构体名称{
数据类型 数据成员1;
数据类型 数据成员2;
}结构体变量名;
struct inflatable { //外部声明
char name[20]; //可以写成 string name;
float valume;
double price;
} cat,cup; //结构变量
还可以声明没有名称的结构类型,叫匿名结构体
struct {
数据类型 数据成员1;
数据类型 数据成员2;
}结构体变量名;
struct {
char name[20];
float valume;
double price;
} cat,cup;
没名称将无法创建这种类型的变量
结构可以包含数组,也可以创建元素为结构的数组
inflatable guests[2] = {
{"Flee",2.10,3.99},
{"Hel",4.15,5.79}
};
cout << guests[0].name << endl;
//guests是一个inflatable数组
//结果
Flee
也允许特定位数的结构成员,与某个硬件设备的寄存器对应的数据结构方便
字段类型为整型或枚举,冒号后面的数字指定使用位数,每个成员被称为位字段(bit filed)
struct inflatable {
unsigned int SN :4 ;
unsigned int : 4 ;
bool goodint : 1 ;
} ;
typedef
typedef函数为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。
typedef struct inflatable { //外部声明
char name[20]; //可以写成 string name;
float valume;
double price;
}peo;
//peo和struct inflatable 同义词
结构体嵌套
可以用typedef嵌套,也可以不用
struct inflatable { //外部声明
char name[20]; //可以写成 string name;
float valume;
double price;
struct date{
int day;
int month;
}birthday;
}cat;
访问结构体成员要用级联方式直到最底层成员才能引用
cat.birthday.day=7;
结构体指针
结构体指针就是指向结构体内存地址的指针。
结构体指针的定义方式为 结构体名称* 指针变量=&结构体变量。
指向结构体的指针常用箭头成员运算符->
声明一个结构体指针记得初始化
//第四种
struct dog;
typedef struct dog DOG;
struct dog{
char name[20];
float valume;
struct DOG* pt;
};
//第三种
struct inflatable { //外部声明
char name[20]; //可以写成 string name;
float valume;
double price;
struct inflatable* t;
}cat;
//当有结构体变量cat时,指针中存放的正是变量cat在内存中的地址。所以不是指针指向了结构体自己,而是指针指向了结构体变量。
//没有时不会分配内存空间
int main(){
//第一种
struct inflatable p1;
inflatable* p=&p1;
//第二种
inflatable* p=&cat;
p -> price=10.0; //等同于(*p).price=10.0;
//p -> price为指向inflatable结构体price成员的指针
//错误用法
inflatable* p1;
p1->price=10.0;
//代码会报错:空指针访问异常,这是因为这个指针还没有初始化,因此他没有内存空间,自然没这个参数。
//可以使用new申请了内存空间,解决问题
}
p -> price/等同于(*p).price,是因为p是指向结构的指针,*p是值也就是结构体本身,所以(*p).price是该结构的price成员。C++运算符优先规则要求使用括号。
结构体可以声明一个自定义的类,所以构造函数初始化也可以用于结构体初始化中,可在二叉树中遇到。
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
//TreeNode 结构体初始化
TreeNode(int x) :val(x), left(NULL), right(NULL) {};
//将int型变量赋值给结构体中的int型变量val,两个TreeNode指针型变量left,right都赋值为NULL。
};
在类中,如果 Classy 是一个类,而 meml、mem2 和 mem3 都是这个类的数据成员,则类构造函数可以使用如
下的语法来初始化数据成员:
ciassy::Classy(int n,intm):meml(n),mem2(0),mem3(n*m + 2) { }
上述代码将meml初始化为n,将mem2初始化为0,将mem3 初始化为n*m+2。从概念上说,这些初始化工作是在对象创建时完成的,此时还未执行括号中的任何代码。请注意以下几点:
- 这种格式只能用于构造函数;
- 必须用这种格式来初始化非静态 const数据成员(至少在 C++11 之前是这样的);
- 必须用这种格式来初始化引用数据成员。
数据成员被初始化的顺序与它们出现在类声明中的顺序相同,与初始化器中的排列顺序无关警告:不能将成员初始化列表语法用于构造函数之外的其他类方法。
学习参考链接:https://segmentfault.com/a/1190000042907586
4.union共用体能够存储不同的数据类型,只能同时 存储一种类型
union onell {
int int1;
float float2;
double double3;
};
onell pail;
pail.float2 = 6;
cout << pail.float2;
//结果
6
可以使用onell变量来存储int 、float 、double,条件是不同的时间进行
共用体每次只能存储一个值,所以,共用体的长度为最大成员长度
用途:数据项使用两种或更多格式时,可节省空间
匿名共用体(anonymous union)没有名称,成员成为位于相同地址处的变量
5.枚举创建符号常量的方式
这种方式可以代替const
enum spectrum{red,blue,yellow,brown,green,orange};
spectrum为新类型名称,也被称为枚举(enumeration)
将red等作为符号常量,对应整数从零起,常量叫做枚举量(enumerator),枚举量是整型,但int类型不能自动转换为枚举类型
可以在算术表达式中同时使用枚举和常规整数
通过赋值运算符可以设置枚举量的值,后面没有被初始化的枚举量比前面的枚举量大一
enum spectrum{red,blue=100,yellow,brown,green,orange}; //yellow的值为101,在这,第一个默认为0
也可以创建多个相同值的枚举量
enum spectrum{red,blue=1,yellow,brown=2,green,orange};
//第一个和第二个都是1,第二个和第三个都是2
枚举的取值范围可以通过强制类型转换增加赋给枚举变量的合法值
如何取值:上限:找到枚举量的最大值,最小的2的幂,再减一。
枚举量最小值不小于0,下限为0,否则,与寻找上限相同方式,加负号
enum spectrum{red=-6,blue=2,yellow,brown,green,orange=9};
spectrum bits;
bits=spectrum(6);
枚举量的最大值为9,2的4次幂16比他大,再减一,上限为15,所以6合法
最小值为-6,2的3次幂-8(加负号),下限为-7
6.指针
- *和&是自右向左运算符
- int a=5, *p , *q *t; int b[10]={1,3,5,7,9}; int c;
- int *u=&c; //指针初始化,其中的✳表示u为指针,而不是✳u为指针
- p=&a; //地址赋给指针,指针指向该地址对于的东西。
- //&✳p ,p ,&a 三者等价,表示a的地址。*&a ,a ,*p 三者等价,表示a的值
- 怎么看,因为自右向左,先看p为指向a的指针,*p为a的值,&*p为a的地址
- q=b; t=&b[5]; //c++中规定数组名既代表数组本身,又代表整个数组的地址,还是数组首元素的地址值
- //由于一个数组名对应一个指针常量,只要不改变数组的值,仍然可以用指针形式的表达式。
- b++; //是错的 *b=i; //是对的
- *p=*p+1; //*p表示a的值加一
- q=q+1; //q表示指向下一个指针,在数组中,修改指针变量的值,是修改指针指向谁 t-q;
- //相同类型指针相减,表示两个指针之间对象的个数,如果p2指针地址大于p1则结果为正,否则为负
强调:数组名是一个常量(不允许进行赋值操作),它代表数组首元素的首地址。
指针是一个变量,存储的是值的地址,而不是值本身,用到地址运算符&获得位置
使用常规变量时,值是指定的量,地址是派生量。对于指针而言,地址是指定的量,值是派生量。因此,指针名表示的是地址。
*(星号)运算符被称为间接值(indirect value)或解除引用(dereferencing)运算符,应用于指针,可得到该地址存储的值。
int updates = 6;
int * pupdates;
//表明*pupdates的类型为int,*运算符被用于指针,所以pupdates变量本身必须是指针,没有*,pupdate就是常规变量
//所以,我们说pupdates指向int类型,还说pupdates的类型是指向int的指针,或int*
//指针类型为何是int,一般而言,指针的类型表明的就是他所指向的对象的类型
pupdates = &updates; //值的地址赋给指针,使得指针指向该地址的值
cout << "updates= " << updates << endl;
cout << "*pupdates= " << *pupdates << endl; //*pupdates与常规int变量updates等效
cout << pupdates << endl;
//结果
updates= 6
*pupdates= 6
00000010B232F614
*两边的空格有没有都行,一般有。
int* pt; //强调指针,pt是指向int的指针
int *pt; //强调值,*pt是一个int类型的值
int*pt;
在C++中,int*是一种复合类型——指向int的指针
在声明语句中初始化指针,被初始化的是指针而不是它指向的值
int higg=8;
int * pt=&higg;
语句将pt(不是*pt)的值设置为&higg
不同类型的指针之间不能赋值
一个指针变量可以指向只读型对象,加const关键字
int x;
int *p1 = &x;//指针可以被修改,值也可以被修改
const int *p2 = &x;//指针可以被修改,值不可以被修改(const int)
int *const p3= &x;//指针不可以被修改(*const),值可以被修改
const int *const p4= &x;//指针不可以被修改,值也不可以被修改
const double y=5.67;
double *p5=&y; //把一个const对象的地址赋给一个非const对象的指针是错误的
const *p6=&y; //正确
实际编程过程中,指向const的指针常用作函数的形参,以此确保传递给函数的参数对象在函数中不能被修改。
new关键字
在运行阶段为一个int值分配未命名的内存,并使用指针来访问这个值,使用关键字new,new会找到一个长度正确的内存块,并返回该内存块的地址。然后,程序员将该地址赋给一个指针。
例如上面结构体指针最后有个错误用法,就是没有初始化,所以没有内存空间,可用new来解决。
int * pn = new int;
delete pn;
new int告诉程序需要适合存储int的内存,new运算符根据类型确定需要多少字节的内存,找到并返回其地址。再将地址赋给pn,pn是被声明为指向int的指针,*pn是值
new分配的内存块与常规变量不同,一般为栈(stack)的内存区域,new在堆(heap)或自由存储区(free store)的内存区域分配内存
delete运算符使得使用完内存后,将其归还内存池
不能使用delete释放声明变量所获得的内存,只能释放使用new分配的内存
在编译时给数组分配的内存被称为静态联编(static binding),意味着数组是在编译时加入程序的。
而使用new,运行阶段需要创建数组就创建,不需要就不创建,还可以在运行时选择数组长度,称为动态联编(dynamic binding)。
数组在程序运行时创建叫做动态数组(dynamic array)。
使用delete和new遵循如下规则
- 不要使用delete来释放不是new分配的内存
- 不要使用delete释放同一块内存两次
- 如果使用new[ ]为数组分配内存,则应使用delete [ ] 来释放
- 如果使用new[ ] 为一个实体分配内存,则应使用delete(没有方括号)来释放
- 对空指针应用delete是安全的
使用new创建动态数组
创建一个包含10个int元素的数组
int * psome = new int [10]; //地址被赋值给指针psome
delete [] psome; //释放内存,[]告诉程序释放整个数组
new运算符返回第一个元素的地址,该地址被赋给指针psome
psome指向数组的第一个元素,其余元素如何指向:把指针当作数组名使用即可。第二个元素,使用psome[1],依此类推。
double* p3 = new double[3];
p3[0] = 0.3;
p3[1] = 0.5;
p3[2] = 0.9;
cout << p3[0]<<endl;
p3 = p3 + 1;
cout << p3[0] << endl;
p3 = p3 - 1;
delete[] p3;
//结果
0.3
0.5
不能修改数组名的值,但指针是变量,可以修改它的值。减一是为了给delete提供正确的地址
使用new创建动态结构
第一步:创建结构,需要同时使用结构类型和new
第二步:访问其成员,不能使用成员运算符点,而使用箭头成员运算符->,用于指向结构的指针
例如,要创建一个未命名的inflatable类型,并将其地址赋给一个指针
inflatable *ps = new inflatable;
ps->price;
这是将足以存储inflatable结构的一块可用内存的地址赋给ps。
C++管理数据内存的方式:自动存储、静态存储、动态存储、线程存储(C++11新增)
- 自动存储:在函数内部定义的常规变量使用自动存储空间,被称为自动变量(automatic variable)。意味着它们在所属函数被调用时自动产生,该函数结束时自动消亡,自动变量是局部变量,它们通常存储在栈中,这意味着执行代码块时,变量依次加入,释放时按相反顺序,被称为先进后出(LIFO)。
- 静态存储:整个程序执行期间都在,变量成为静态的两种方式,一种是函数外面定义它,一种是声明变量时使用关键字static。
- 动态存储:new和delete运算符管理一个内存池,在C++中被称为自由存储空间(free store)或堆(heap)。该内存池用于静态变量和自动变量的内存是分开的。数据的生命周期不完全受程序或函数的生存空间控制。new和delete的相互影响可能导致占用的自由存储区不连续。不同时使用new和delete可能会导致内存泄漏,C++一个好方式:智能指针,有助于完成同时使用new和delete。
多维数组指针
二维数组举例,
- 二维数组名是指向行的,“&二维数组名”就指向了整个二维数组。
- "二维数组名[i]"是指向i行的首元素的。“&二维数组名[i]”就指向了一行
int a[3][4]; //三行四列数组
二维数组a可以分解为3个一维数组来处理,有三个a[0] a[1] a[2]数组
其中一维数组a[0]的元素有a[0][0], a[0][1], a[0][2], a[0][3] 4个元素
一维数组a[1]的元素有a[1][0], a[1][1], a[1][2], a[1][3] 4个元素
C允许 多维数组可以分解为多个一维数组来处理
a 是二维数组名,a 代表整个二维数组首元素的地址,但是首元素是一个具有int类型元素的一维数组,所以 a 代表的是首行的起始地址 (即第 0 行的起始地址,&a [0]),即a=&a[0],✳a = a [0]。a+1 代表 a [1] 行的首地址,即 & a [1]=a+1。
a [0] 代表一维数组 a [0] 中 0 列元素的地址,即 & a [0][0]=a[0]。a [1] 代表一维数组a[1]中0列元素的地址,即 & a [1][0]。
0行1列地址为&a[0][1]。因为a[0]是0列的地址,所以,该一维数组中序号为 1 的元素可以用 a [0]+1 来表示(也就是指针加一指向下一个元素),则,✳(a [0]+1) 就是 a [0][1] 元素的值。
而 a [0] 又是和 ✳(a+0) 无条件等价的,因此也可以用 ✳(✳(a+0)+1) 表示 a [0][1] 元素的值。依此类推,✳(a [i]+j) 或 ✳(✳(a+i)+j) 是 a [i][j] 的值。
//p为整型的指针变量
//p = a[0] 等同于 p = &a[0][0]; 也即0行首元素的地址
int* p;
for (p = a[0]; p < a[0] + 12; p++)
cout << *p << " ";
对a取地址操作代表整个数组的首地址,类型为数组类型
int (*p)[3][4] = &a;
int (*p)[4]; //相当于 p = a;或者 p = &a[0];
//[]表示定义一个数组,4表示数组中有4个元素,int表示数组为整型数组。*表示p是一个指针变量。
//也就是p指针指向一个二维数组中的首个一维数组,所以,p+1不是指向一维数组的下一个元素,而是指向下一个一维数组。
int *(p[5]); //指针数组,可以去掉括号直接写作
// *matrix 两端的括号必不可少:
int *matrix[10]; // 10个指针构成的数组
int (*matrix)[10]; // 指向含有10个整数的数组的指针,省略了[],int (*matrix)[][10];
区分以下,看前后,谁在前先说谁,例如,数组指针是指向数组的指针,指针数组是全是指针的数组
指向指针的指针
通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
一个指向指针的指针变量必须如下声明,即在变量名前放置两个星号。
通过*的个数可以区分指针的级别,即为 **表示指向指针的指针,***表示指向指针的指针的指针。
int **p;
int var = 60;
int *ptr1 = &var; // 指针变量 ptr1 指向变量 var 的地址
int **ptr2 = &ptr1; // 指针的指针 ptr2 指向指针 ptr1 的地址
数组指针
数组的指针是指一个指针,它指向数组的首元素。这样的指针可以通过递增来遍历整个数组,或者用于指向数组的首地址。
int arr[3] = {10, 20, 30};
int *ptr = arr; // 将指针指向数组的首元素
指针数组
指针的数组是指一个数组,其每个元素都是一个指针。这些指针可以指向不同类型的变量,也可以指向相同类型的变量。
int var1 = 10;
int *ptrArray[3]; // 声明一个指针数组,包含三个指向整数的指针
// 将指针指向不同的变量
ptrArray[0] = &var1;
cout << *ptrArray[0] << endl;
指针函数
像变量内存地址存储在指针变量中,函数的首地址存储在某个函数指针变量中。
// addition是指针函数,一个返回类型是指针的函数
int* addition(int a, int b) {
int* sum = new int(a + b);
return sum;
}
int* m = addition(1, 2);
函数指针
像变量内存地址存储在指针变量中,函数的首地址存储在某个函数指针变量中。这样,可以通过这个函数指针变量来调用所指向的函数。
因为数组不能拷贝,所以函数不能返回数组。函数可以返回数组的指针或者引用。
// minus是函数指针,指向函数的指针,而非对象
int subtraction(int a, int b) {
return a - b;
}
int (*minus)(int, int) = subtraction;
尾置返回类型在形参列表后面以一个 -> 符号开头,并在前面本应该出现返回类型的地方放一个auto。
// 使用尾置返回类型
auto func2(int i) -> int(*)[10];
//可以清楚的看到func2函数返回的是一个指针,而且是一个指向含有10个整数的数组的指针。
指针学习:https://blog.csdn.net/weixin_42289227/article/details/123750707
https://blog.csdn.net/king52113141314/article/details/100740716