C++学习笔记
----指针
文章目录
一.指针的概念
- 类型
每一种基本数据类型都有相应的指针类型。 - 内存占用
一个指针占用4个字节,与指针指向的数据类型无关。 - 指针与指针变量
指针:存储单元的地址
指针变量:是地址对应的存储单元中存放的数据为内存地址的变量 - 指针变量的直接访问和间接访问
直接访问指针变量:得到地址值
间接访问指针变量:得到地址对应的存储单元中的数据(也有可能是地址)
二.指针的定义
- 定义 (*)
int i=7, *p;
p = &i;
或者:
int i = 7;
int *p = &i;
cout << "i = " << i << endl;
cout << "*p = " << *p << endl;
cout << "p = " << p << endl;
cout << "&p = " << &p << endl;

其中,p为i的地址,&p为p的地址。
- 定义多个指针
int *p1, *p2;
不可以:
int *p1, p2;
三.指针的初始化
指针变量一定要有初始值。
- 直接用地址常量对指针变量赋值(少)
- 用某个同类型变量的地址:
int i=7, *p;
p = &i;
cout << "i = " << i << endl; //i = 7
cout << "*p = " << *p << endl; //*p = 7
- 用另外一个已经初始化的同类型指针变量:
int i=7, *p1, *p2;
p1 = &i;
p2 = p1;
cout << "i = " << i << endl; //i = 7
cout << "*p1 = " << *p1 << endl; //*p1 = 7
cout << "*p2 = " << *p2 << endl; //*p2 = 7
- 用某个同类型的数组名:
int n[3]={1,2,3}, *p;
p = n; //p = &n[0];
cout << "*n = " << *n << endl; //*n = 1
cout << "*p = " << *p << endl; //*p = 1
- 用new运算符或者malloc函数:
(1)new
a.一维数组
int n;
cin >> n;
int *arr = new int [n]();
...
delete [] arr;
b.二维数组
int row, col;
cin >> row >> col;
int **arr = new int *[row];
for(int i = 0; i < row; i++)
arr[i] = new int [col]();
...
for(int i = 0; i < row; i++)
delete [] arr[i];
delete [] arr;
c.new的初始化
化0:
const int n = 3;
int *num = new int [n]();
for(int i = 0; i < n; i++)
cout << *(num+i) << " "; //0 0 0
delete [] num;
化其他值:
const int n = 3;
int *num = new int [n]{1,2,3};
for(int i = 0; i < n; i++)
cout << *(num+i) << " "; //1 2 3
delete [] num;
(2)malloc
#include<stdlib.h>
a.一维数组
const int n = 3;
int *num;
num = (int *)malloc(sizeof(int)*n);
memset(num, 0, n*sizeof(int));
...
free(num);
b.二维数组
int row, col;
cin >> row >> col;
int **num;
num = (int**)malloc(sizeof(int*)*row);
for(int i = 0; i < row; i++)
num[i] = (int*)malloc(sizeof(int)*col);
...
for(int i = 0; i < row; i++)
free(num[i]);
free(num);
c.malloc的初始化
化0:#include<string.h>
const int n = 3;
int *num;
num = (int *)malloc(sizeof(int)*n);
memset(num, 0, n*sizeof(int));
for(int i = 0; i < n; i++)
cout << *(num+i) << " "; //0 0 0
free(num);
三.指针变量的运算
- 引用运算:
*指针变量
在表达式语句中(而不是在定义语句)表示间接访问该指针变量。 - 自增、自减运算:
++指针变量
--指针变量
指针变量++
指针变量--
(右结合性)
通常用于访问数组,使其指向当前数组元素的下一个或前一个数组元素。
++p:
int num[3] = {1, 2, 3}, *p;
p = num;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "++p = " << ++p << endl;
cout << "p = " << p << endl;

p++:
int num[3] = {1, 2, 3}, *p;
p = num;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "p++ = " << p++ << endl;
cout << "p = " << p << endl;

*++p:
int num[3] = {1, 2, 3}, *p;
p = num;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "*++p = " << *++p << endl;
cout << "*p = " << *p << endl;

*p++:
int num[3] = {1, 2, 3}, *p;
p = num;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "*p++ = " << *p++ << endl;
cout << "*p = " << *p << endl;

*(++p):
int num[3] = {1, 2, 3}, *p;
p = num;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "*(++p) = " << *(++p) << endl;
cout << "*p = " << *p << endl;

*(p++):
int num[3] = {1, 2, 3}, *p;
p = num;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "*(p++) = " << *(p++) << endl;
cout << "*p = " << *p << endl;

++(*p):
int num[3] = {1, 2, 3}, *p;
p = num;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "++(*p) = " << ++(*p) << endl;
cout << "*p = " << *p << endl;

(*p)++:
int num[3] = {1, 2, 3}, *p;
p = num;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "(*p)++ = " << (*p)++ << endl;
cout << "*p = " << *p << endl;

- 加减整型常数
+整型常数
-整型常数
通常用于访问数组,使其指向当前数组元素的后n个或前n个数组元素。
两个同类型的指针变量相减:这两者间的同类型数据的个数
指针变量的运算结果与指针变量指向的数据类型有关
四.指针与数组
C/C++的数组名是一个指针变量,表示该数组第一个数组元素。
- 指针数组
p 中的每个元素,都是一个指向 int 型的指针,p是一个int型的指针数组。
#include <iostream>
using namespace std;
int main()
{
int num[3] = {1, 2, 3};
int *p[3] = {NULL};
for(int i = 0; i < 3; i++)
p[i] = &num[i];
for (int i = 0; i < 3; i++)
{
cout << "num[" << i << "] = ";
cout << *p[i] << endl;
}
return 0;
}

- 用指针变量访问数组
#include <iostream>
using namespace std;
int main()
{
int num[3] = {1, 2, 3};
//int *p;
//p = num; //p = &num[0];
int *p = &num[0];
for (int i = 0; i < 3; i++)
{
cout << "num[" << i << "] = ";
cout << *(p+i) << endl;
}
return 0;
}

五.指针与函数
- 函数的形成定义为指针变量,函数调用时实参变量的地址拷贝给形参,通过间接访问形参指针变量可以获取和修改实参变量的值,实现在一个函数访问修改另一个函数变量的值。
#include <iostream>
using namespace std;
void swap(int *p1, int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main()
{
int a = 11, b = 12;
int *p1 = &a, *p2 = &b;
swap(p1, p2);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}

- 从函数中返回多个值。
#include <iostream>
using namespace std;
int *swap(int a, int b)
{
int *n = new int [2]();
*n = b;
*(n+1) = a;
return n;
}
int main()
{
int a = 11, b = 12;
int *n;
n = swap(a, b);
cout << "a = n[0] = " << *n << endl;
cout << "b = n[1] = " << *(n+1) << endl;
delete [] n;
return 0;
}

- 形参与实参的结合方式
形参:数组名
实参:数组名
main:
int arr[10];
...
f(arr, 10);
...
---------------------------
f:
int f(int arr[], int n)
形参:指针变量
实参:数组名
main:
int arr[10];
...
f(arr, 10);
...
---------------------------
f:
int f(int *p, int n)
形参:指针变量
实参:指针变量
main:
int arr[10], *p;
p = a;
...
f(p, 10);
...
---------------------------
f:
int f(int *p, int n)
形参:数组名
实参:指针变量
main:
int arr[10], *p;
p = a;
...
f(p, 10);
...
---------------------------
f:
int f(int arr[], int n)
六.动态数组–与malloc相比new的优点
- 可以自动计算所需分配内存的大小,无需显示地给出。
- 可以自动返回指针类型,无需强制类型转换。
- 用new创建一个类对象时,会自动调用类的构造函数,对动态创建的对象初始化。
- 用delete释放类对象时,也会自动调用类的析构函数,释放对象所占用的堆内存等系统资源。
在指针创建时最好初始化为NULL,每次delete指针之后都赋值为NULL,delete之前判断指针是否为NULL,防止delete空指针/野指针或者重复delete
七.字符指针变量与字符串
- 字符串:
(1)只能存储在字符数组中,存储字符串的字符数组大小必须比字符串的长度多一(’\0’).
(2)可以用字符数组名整体实现字符串的输入(cin >> s)和输出(cout << s),而普通数组不行。
(3)gets(s)和cin.getline(s, n, 结束符)可以输入一行包含空格直到换行结束的字符串。
(4)可用strlen(s)查看字符串的字符个数(#include <string.h>).
(5)可用字符指针数组来表示多个字符串。 - 字符指针变量(char)
char str[100] = {'\0'};
cin >> str;
char *p;
p = str;
...
f(p);
其中,f(int *p){ ... }。或者:
char str[100] = {'\0'};
cin >> str;
...
f(str);
- 字符串初始化
化0:
char str[100] = "0";
为空:
char str[100] = {'\0'};
八.文字游戏
- 常量指针、指针常量、指向常量指针的指针常量
(1)常量指针:表示指向指针的标识符是常量不能改变,而指针的值可以改变。
const 数据类型 *常量指针变量名 = &常量标识符; ----> const int *p = &a;
(2)指针常量:表示指针本身是常量,只能指向一个变量,而指针指向的变量的值可以改变。
数据类型 * const 指针常量名 = &变量名; ----> int * const p = &a;
(3)指向常量的指针常量:表示指针本身以及其指向的都是常量,不能改变。
const 数据类型 * const 指针常量名 = &常量标识符; ---->const int * const p = &a;
- 指针数组、指向指针的指针和数组指针
(1)指针数组:数组元素为指针变量的数组。常用于表示多个字符串。
数据类型 *指针数组名[数组长度说明]; ---->int *p[3];
(2)指向指针的指针(二级指针):指针数组的数组名就是一个地址常量(指针的指针)。常用于指向动态分配的二维数组。
数据类型 **指针变量名; ---->int **p;
(3)数组指针:可看成是指向一维数组的指针。 - 返回指针的函数和指向函数的指针
(1)指针函数:函数通过return返回一个地址。
数据类型 *指针函数名(参数表){ ... } ----> int *swap(int a, int b){ ... }
指针函数不能返回局部变量和非指针形参变量的地址,但可以返回:静态局部变量的地址,指针形参变量的地址,动态分配的堆内存的地址。
(2)指向函数的指针变量:其值是某个函数在内存代码区的地址,函数的函数名就是一个表示函数入口的地址常量,可用其对函数指针初始化。
函数返回数据类型 (*函数指针变量名)(参数表) ---->int (*swap)(int a, int b)
作用:作为函数的形参,向函数传递不同的函数实现用不同的方法解决同一个问题,或者向函数传递不同的问题实现同一个方法解决多个问题。用函数指针变量名替换函数名即可完成对函数指针指向的函数的调用。
#include <iostream>
using namespace std;
int text(int (*t1)(int), int (*t2)(int), int a, int b)
{
int sum;
sum = t1(a)+t2(b);
return sum;
}
int t1(int a)
{
return a*a-1;
}
int t2(int b)
{
return b-2;
}
int main()
{
int a = 11, b = 12;
int sum;
sum = text(t1, t2, a, b);
cout << "sum = " << sum << endl;
return 0;
}
九.字符串类string
- 定义
string 字符串变量名; ---->string s;
string 字符串变量名 = 字符串常量; ---->string s = "hello world";
- 可以用string变量名整体实现字符串的输入(cin >> s)和输出(cout << s)。
- 用getline(cin, s)可输入一行包含空格直到换行结束的字符串。
- 可以用string数组表示多个字符串。
- 字符串操作:
(1)赋值=;比较==,!=,<, <=,>,>=;合并+;添加+=
#include <iostream>
using namespace std;
int main()
{
string s1 = "hello ";
string s2 = "world";
cout << (s1<s2) <<endl;
cout << s1+s2 << endl;
s1 = s2;
cout << s1 <<endl;
return 0;
}

(2)访问指定位置字符:数组下标[ ]方式;at( )函数访问
#include <iostream>
using namespace std;
int main()
{
string s = "hello";
cout << "s[1] = " << s[1] << endl;
cout << "s[1] = " << s.at(1) << endl;
return 0;
}
(3)返回字符串个数:size( );length( )
#include <iostream>
using namespace std;
int main()
{
string s = "hello";
cout << "L = " << s.size() << endl;
cout << "L = " << s.length() << endl;
return 0;
}
(4)insert( )插入字符串;erase( )删除字符(串);clear( )删除全部字符;replace替换字符;swap( )交换两个字符串;find( )查找字符;substr( )提取子串;empty( )判断字符串是否为空
#include <iostream>
using namespace std;
int main()
{
string s = "hello";
string str = "hey";
cout << s.insert(5, "world") << endl;
cout << s.erase(1, 2) <<endl;
cout << s.replace(0, 2, str, 1, 2) << endl;
s.swap(str);
cout << s << " " << str <<endl;
cout << str.find("yo", 0) << endl;
cout << str.find('e', 5) << endl; //找不到
cout << str.substr(3, 5) << endl;
s.clear();
cout << s << endl;
cout << s.empty() << endl;
return 0;
}

- string与char[ ]的相互转换
(1)copy(p, n, m=0); 将字符串从第m个字符开始后的n个字符拷贝到指针p指向的字符数组中,复制不会自动添加串尾符’\0’。返回值是一个表示复制字符个数的整数。
#include <iostream>
using namespace std;
int main()
{
string s = "hello";
string str = "hey";
char p[100] = {'\0'};
s.copy(p, 4, 1);
p[4] = '\0';
cout << p << endl;
return 0;
}
(2)c_str( ); 返回一个const类型的指向可读不可改的以’\0’结尾的字符数组的指针。
#include <iostream>
using namespace std;
int main()
{
string s = "hello";
const char *c = NULL;
c = s.c_str();
cout << c << endl;
s = "world";
cout << c << endl;
return 0;
}
(3)data( ); 同c_str( ),但指向的字符数组不一定带串尾符’\0’。
#include <iostream>
using namespace std;
int main()
{
string s = "hello";
const char *c = NULL;
c = s.data();
cout << c << endl;
s = "world";
cout << c << endl;
return 0;
}
只读,不可改: