指针变量
指针是“指向(point to)”另外一种类型的复合类型。复合类型是指基于其它类型定义的类型。
指针在C ++是保存另一个变量的存储器地址的变量。
引用是一个已经存在的变量的别名。
一旦引用被初始化为一个变量,它就不能被更改为引用另一个变量。
理解指针,先从内存说起:内存是一个很大的,线性的字节数组。每一个字节都是固定的大小,由 8 个二进制位组成。最关键的是,每一个字节都有一个唯一的编号,编号从 0 开始,一直到最后一个字节。
程序加载到内存中后,在程序中使用的变量、常量、函数等数据,都有自己唯一的一个编号,这个编号就是这个数据的地址。
指针的值实质是内存单元(即字节)的编号,所以指针单独从数值上看,也是整数,他们一般用16进制表示。指针的值(虚拟地址值)使用一个机器字的大小来存储,也就是说,对于一个机器字为w位的电脑而言,它的虚拟地址空间是,程序最多能访问个字节。这就是为什么 xp 这种 32 位系统最大支持 4GB内存的原因了。
用来保存指针的对象,就是指针对象。如果指针变量 p1 保存了变量 a 的地址,则就说:p1 指向了变量a,也可以说 p1 指向了 a 所在的内存块 ,这种指向关系,在图中一般用 箭头表示:
// 普通变量
int a = 3;
// 定义了变量a,int类型,值为3.内存中有一块内存空间是放a的值
// 对a的存取操作,就是直接到这个内存空间存取
// 内存空间的位置,叫地址
// 存放 3 的地址,可以用 取地址操作符 & 得到,&a
// 指针变量
int *p = NULL;
// 定义了一个指针变量 p,p指向一个内存空间,里面存放的是一个内存地址
// 现在赋值为NULL(就是0,表示特殊的空地址),空指针
// 申请一个空间给 p,*p内容不确定
int *p = new(int);
// 给指针变量 p 赋值, & 发音 and
p = &a;
// 把 a 变量的内存空间地址给了 p
// 直接对 p 存取,操作的是地址
// 通过这个地址,间接地操作,才是整数3
// p的间接操作要使用指针操作符 *, *p 的值才是3
// 指针定义
// 类型说明符 *指针变量名
int a = 10;
int *p;
// 取地址运算符 &
p = &a;
// 间接运算符 *,解引用符 *
*p = 20;
// 指针变量直接存取的是内存地址
cout << p << '\n'; // 0x4097ce
// 间接存取的才是存储类型的值
cout << *p << '\n'; // 20
// *有靠近变量类型的,有靠近变量名称的
// 有什么区别呢
int *p;
int* q;
// *靠近哪一个都可以,编译器都会认为是指针变量,所以本质是一样的
// 推荐靠近变量名称写 int *p
// 指针与引用
#include <bits/stdc++.h>
using namespace std;
int main(){
// 指针在声明后,无论何时都可以初始化为任意值
// 可以分配一个指针来指向一个NULL值
// 指针需要使用 *
// 指针可以改为指向相同类型的任何变量
int a = 5;
int *p;
p = &a;
// or int *p = &a;
cout << *p << '\n';
// 引用被声明时必须进行初始化
int b = 6;
int &ref = b;
cout << ref << '\n';
return 0;
}
指针与数组
// 下标法
a[i];
// 指针法
*(a + i);
指针与字符串
// 字符串的表示形式
#include <bits/stdc++.h>
using namespace std;
int main(){
char s1[] = "Hello s1!";
printf("%s\n", s1);
char *s2 = "Hello s2!"; // 把字符串的第1个元素的地址,赋值给了s2
printf("%s\n", s2);
return 0;
}
// %s 是输出字符串时用到的格式符,在输出项中,给出字符指针变量名,则系统先输出它所指的一个字符数据
// 然后自动使 s2 加1,使之指向下一个字符
// 然后再输出一个字符
// 直到,遇到字符串结束标志'\0'为止
// 字符串指针,作为函数参数
// 可以改变字符串里的内容
#include <bits/stdc++.h>
using namespace std;
char s[110];
void solve(char *s){
int len = strlen(s);
for (int i = 0; i < len; i++) s[i] -= 32;
}
int main(){
scanf("%s", s);
char *p = s;
solve(p);
printf("%s\n", s);
return 0;
}
/*
输入:abc
输出:ABC
*/
// 下面这样写也是等价的
#include <bits/stdc++.h>
using namespace std;
char s[110];
void solve(char *s){
int len = strlen(s);
for (int i = 0; i < len; i++) s[i] -= 32;
}
int main(){
scanf("%s", s);
solve(s); //传递的时候,传递数组的名称,就是指针
printf("%s\n", s);
return 0;
}
// 下面这样写也是等价的
#include <bits/stdc++.h>
using namespace std;
char s[110];
void solve(char s[]){ //形参,写成char s[],这也是个指针
int len = strlen(s);
for (int i = 0; i < len; i++) s[i] -= 32;
}
int main(){
scanf("%s", s);
solve(s);
printf("%s\n", s);
return 0;
}
指针与函数
// 指针作为函数参数
#include <bits/stdc++.h>
using namespace std;
void swap(int a, int b){
int t = a;
a = b;
b = t;
}
int main(){
int a, b;
cin >> a >> b;
swap(a, b);
cout << a << ' ' << b << '\n';
return 0;
}
/*
输入:3 4
输出:3 4
*/
#include <bits/stdc++.h>
using namespace std;
void swap(int *a, int *b){
int t = *a;
*a = *b;
*b = t;
}
int main(){
int a, b;
cin >> a >> b;
swap(&a, &b);
cout << a << ' ' << b << '\n';
return 0;
}
/*
输入:3 4
输出:4 3
*/
// 函数返回指针
#include <bits/stdc++.h>
using namespace std;
int a[110], n, m;
// int* find() 这样写的效果是一样的
int *find(){
for (int i = 0; i < n; i++)
if (a[i] == m)
return &a[i];
return NULL;
}
int main(){
cin >> n >> m;
for (int i = 0; i < n; i++) cin >> a[i];
int *p = find();
if (p == NULL) printf("cannot find\n");
else printf("%d %d\n", p, *p);
return 0;
}
结构体指针
// 引用结构体指针变量指向的结构体变量的成员的方法
struct stu{
int score;
string name;
}*p;
指针名->成员名
(*p).score;
(*指针名).成员名
p->score
// 自引用结构
struct node{
int x, y;
node *next;
}
链表结构
<见后文具体展开>