以下内容为大学期间学习C++语言总结的知识:
《C++》基础入门_01——数据存储,表示形式,基本运算
《C++》基础入门_02——面向对象的总体概括
《C++》基础入门_03——程序的开发过程
《C++》基础入门_04——四大语句
《C++》基础入门_05——函数详解篇
《C++》基础入门_06——面向对象的详述
《C++》基础入门_07——数据的共享保护:const
《C++》基础入门_08——利用数组实现对批量数据的处理
《C++》基础入门_09——指针和引用的讲解
《C++》基础入门_10——用户自定义数据类型详细篇
《C++》基础入门_11——友元的讲解
《C++》基础入门_12——类模板
《C++》基础入门_13——运算符的重载
《C++》基础入门_14——继承与派生
《C++》基础入门_15——多态性
《C++》基础入门_16——输入输出流详讲
《C++》基础入门_17——对象串行化
《C++》基础入门_18——异常处理
《C++》基础入门_19——命名空间
《C++》基础入门_20——文件操作
《C++》基础入门_21——在函数中返回数组的常用方法
文章目录
- 在程序中定义一个变量,在编译时给这个变量分配内存单元。系统根据程序中定义的变量类型,分配一定的长度的空间。
- 内存中的每一个字节有一个编号,这就是地址。在地址所标识的内存单元中存放数据。
- 在程序中一般通过变量名对内存单元进行存取操作。程序通过编译将变量名转换成变量的地址,对变量值的存取通过地址进行的。
一、访问方式
- 直接访问:
按变量地址存取变量值的方式称为:直接访问(直接存取)。 - 间接访问:
另一种间接访问的方式:将变量的地址存放在另一个变量中,可以定义专门存放地址的变量。
二、关于内存地址
- 内存空间的访问方式
- 通过变量名访问
- 通过地址访问
- 地址运算符: &
例:
int var;
则&var 表示变量var在内存中的起始地址
int *p=&var;
三、指针变量
3.1 概念
指针:内存地址,用于间接访问内存单元,变量的指针就是变量的地址
指针变量:用于存放变量地址的变量
*:表示指向
指针变量的基类型就是该指针变量指向变量的类型。
int i,j; //定义整型变量
int *point_i,*point_j;// 定义指针变量,此时的int说明指针指向整型数据,point_i是一个指针变量,而*point_i表示point_i所指向的变量
定义:基类型 * 指针变量名
;
- *不是指针变量名的一部分
- 指针是基本数据类型派生出来的类、不能脱离基本类型存在。
int *:读作指向int的指针,或int指针
int *a:a是指向整型数据的指针变量
3.2 初始化
基类型 * 指针变量名=初始地址;
&:取地址运算符
不能给一个指针变量直接赋一个整数。
int *p=&a;
3.3 引用指针变量
- & :取地址运算符
- *:指针运算符
- 优先级相同,按从右向左的方向结合
&a:变量a的地址
*p :指针变量p所指向的存储单元
&*p相当于&a
&a相当于p
3.4 使用
int i;
int *i=&i;
- 注意事项
- 用变量地址作为初值时,该变量必须在指针初始化之前已说明过,且变量类型应与指针类型一致。
- 可以用一个已赋初值的指针去初始化另一个指针变量。
- 不要用一个内部 auto 变量去初始化 static 指针。
3.5 用指针作函数参数
作用:将一个变量地址传给被调用函数的形参
由于是单向传递,只能实参向形参传递数据,形参值的改变无法传回给实参,要想实现在函数中改变的值保留下来传给实参,需要使用指针。
3.6 指针变量的赋值运算
指针名=地址
- “地址”中存放的数据类型与指针类型必须相符。
- 向指针变量赋的值必须是地址常量或变量,不能是普通整数。但可以赋值为整数0,表示空指针。
- 指针的类型是它所指向变量的类型,而不是指针本身数据值的类型,任何一个指针本身的数据值都是unsigned long int型。
- 允许声明指向 void 类型的指针。该指针可以被赋予任何类型对象的地址。
void类型指针的使用
四、指向数组元素的指针
数组元素的指针就是数组元素的地址。
int a[10];
int *p;
p=&a[0];
由于数组名代表数组第一个元素的地址。所以
p=&a[0]等价于p=a;
如果指针变量p已经指向数组中的一个元素,则p+1代表指向数组的下一个元素。
- 通过指针引用数组元素
- *p就是a[0], *(p+1)就是a[1], … (p+i)就是a[i].
- a[i], *(p+i), *(a+i), p[i]都是等效的。
- 不能写 a++,因为a是数组首地址,是常量
五、用指针变量作为函数形参接收数组地址
用数组名作形参,传递的是数组首元素的地址。
c++将形参数组名一律作为指针变量处理。
实际上函数调用时并不存在一个占有存储空间的形参数组,只有指针变量。
六、字符串和指针
c++中有3中方式访问一个字符串:
- 用字符数组存放一个字符串
char s[20]=“hello c++”;
- 用字符串变量存放一个字符串
string s=“hello c++”;
- 用字符指针指向一个字符串
char * str=“hello c++”;
等价于 char *str;
str=“hello c++”;
七、函数与指针
指针变量也可以指向一个函数。
一个函数在编译时被分配一个入口地址。这个函数入口地址被称为函数的指针。
可以用一个指针变量指向函数,然后通过该指针变量调用函数。
- 形式
函数类型 (* 变量名) (函数形参表)
括号不可以省去。
#include <iostream>
using namespace std;
int main() {
int max(int a, int b);
int(*p)(int, int);//定义指向函数的指针变量p
int a, b,m;
p = max; //使p指向函数max;将函数入口地址赋给指针
cin >> a >> b;
m = p(a, b);
cout << m;
return 0;
}
int max(int a, int b) {
int temp;
if (a > b)
temp = a;
else if (a < b)
temp = b;
else
temp = a;
return temp;
}
八、返回指针值的函数
返回指针值的函数被称为指针函数。
返回一个地址。
- 形式:
类型名 *函数名(参数列表)
int *a(int x,int y);
a是函数名,调用它以后可以得到一个指向整型数据的指针。
九、指针数组
- 一个数组的元素都是指针类型的数据,该数组称为指针数组
- 数组的每一个元素是相当于一个指针变量,它的值都是地址。
- 定义型式:
类型名 *数组名[数组长度];Point *pa[2];
由pa[0],pa[1]两个指针组成
运行结果
十、指向指针的指针
指向指针数据的指针。
- 定义:
数据类型 **指针名
;
或者
数据类型 *(*指针名)
- '*'的运算时从右向左的
#include "pch.h"
#include <iostream>
#include <string>
using namespace std;
int main(){
char ** p;
char * name[]= { "you","are","about","dog" };
p = name + 2;//指向name[2]的首地址
cout << *p;//*p==name[2], 输出about
cout << **p;//输出name[2]指向的第一个字符a
return 0;
}
十一、const指针
可以指定指针变量是一个常量,或者指针变量指向的是一个常量。
有一下几种情况:
11.1 指向常量的指针变量
- 一般形式:
const 类型名 * 指针变量名
; - 不能通过指针来改变所指对象的值,但指针本身可以改变,可以指向另外的对象。
- 用指向常量的指针变量只是限制了通过指针变量改变他指向的对象的值。
int a=12,b=5;
const int *p=&a;//定义指向常量的指针p,它指向对象a
*p=8; //想通过指针更改指针所指向的a的值,这是错误的
p=&b;//指针所指对象改变,这是可以的
11.2 常指针
- 若声明指针变量的值为常量,则指针变量的指向不能被改变。
- 一般形式:
类型名 * const 指针变量名
;
这种指针变量被称为:常指针变量简称常指针 - 必须在定义时初始化
例:
char *const name2=“John”;//name2指针只能指向“john”
name2=“abc”;//错误,指针常量值不能改变
11.3 指向常量的常指针
即指针指向一个固定的对象,且该对象的值不能被改变。
- 一般形式:
const 基本类型名 * const 指针变量名
;
int a=10,b=50;
const int * const p=&a;
p=&b;//error,不可以改变所指对象
*p=30;//错误,不可以改变所指对象的值
a=30;//正确,合法
十二、void指针类型
- 不要把指向void类型理解为 :能指向任何类型数据;应该理解为:指向空类型或者不指向确定的类型。
- 若一个指针不指定一个确定的数据类型,它无法访问任何一个具体的数据,只提供一个地址。
- 这种指针是过渡型的,它在需要时必须转换成一个确定的数据类型。
- 可以把非void型指针赋给void型指针,但是不可以直接把void型指针赋给非void型指针,必须强制转换。
int a = 3;
int *p = &a;
char *p2 = "new";
void *p3;
p3 = (void *)p1;//把p1转换成void型指针,赋给p3
cout<<*p3;//错误,p3不指向确定类型
cout << *(int *)p3;//合法,把p3转向int型指针
p2 = (char*)p3;//合法
十三、指针的运算
13.1 指针变量的算术运算
- 指针与整数的加减运算
- 指针p加上或减去n,其意义是指针当前指向位置的前方或后方第n个数据的地址。
- 这种运算的结果值取决于指针指向的数据类型。
- 指针加一,减一运算
–指向下一个或前一个数据。
例如: y=px++ 相当于 y=(px++)
(*和++优先级相同,自右向左运算)
13.2 指针变量的关系运算
- 关系运算
- 指向相同类型数据的指针之间可以进行各种关系运算。
- 指向不同数据类型的指针,以及指针与一般整数变量之间的关系运算是无意义的。
- 指针可以和零之间进行等于或不等于的关系运算。例如: p==0或p!=0
- 赋值运算
向指针变量赋的值必须是地址常量或变量,不能是普通整数。但可以赋值为整数0,表示空指针。
十四、引用
- c++对c的扩展:对一个数据可以建立一个引用,它的作用是为一个变量起个别名。
- 一般形式:
数据类型 &引用名=相同类型的一个变量名; - &是引用声明符,而非取地址符
int a;
int &b=a;//声明b是a的引用
经过以上的声明,使用a,b的作用一样,都代表同一个变量。
注意:
- 引用不是一种独立的数据类型。对引用只有声明,没有定义。
- 声明一个引用同时必须对其初始化,表明它代表哪个变量。
- 声明一个引用后,不能再使之作为另一变量的引用。
int a1,a2;
int &b1=a1;//b1作为a1的引用
int &b1=a2;//错误,不能再作为a2的引用 - 不能建立引用数组
int a=3;
int &b[5]=a;//不能建立引用数组
int &b=a[0];//不能作为数组别名 - 不能建立引用的引用
int a;
int &b=a;//b作为a的引用
int &c=b;//错误,不能建立引用的引用 - 不能建立引用的指针
int a;
int &b=a;//b作为a的引用
int *p=b;//错误,不能建立引用的指针 - 可以去引用的地址
int &b=a;
cout<<&b;//此处&为取地址符
14.1 引用作为函数参数
- 函数参数传递的情况:
- 变量名作为实参和形参。
此时传给形参的是变量值,传递单向的。在执行函数时形参的值改变,并不传回给实参。调用函数时,形参和实参并不属于同一存储单元。 - 传递变量的地址
形参是指针变量,实参是变量地址。调用函数时,形参得到实参变量的地址,因此指向实参变量单元。
仍然是值传递,只是实参是地址而已。 - 以引用作为形参
在虚实结合时,建立变量的引用。使形参名作为实参的引用,可以实现双向传递,共享一段内存单元。
实参是变量名,而传递的却是变量的地址。
- 变量名作为实参和形参。
void sort(int &a, int &b) {//a、b变量的值被交换
int c;
c = a;
a = b;
b = c;
}
int main() {
int i = 10;
int j = 20;
sort(i, j);
cout << i;//输出 20
cout << j;//输出 10
return 0;
}