C指针2:指针变量
前面已经介绍过数据在内存中的地址称为指针。
C语言中允许用一个变量来存放指针,如果一个变量存储的是一份数据的指针,那么这个变量称为指针变量。即指针变量的值是有一份数据的地址,这样的一份数据可以是数组、字符串、函数,也可以是另外的一个普通变量或指针变量。
举个例子:
有一个指针变量P,它的值是地址为0X01A。我们还有一个char类型的变量c,他存储的是“k”。即char c ="k";但是我们输出char类型的c所占用的地址为0X01A。
此时可以说P指向c。
定义指针变量:
(1)知道了普通变量的定义规则,那么指针变量的定义就是在变量名前加*号即可,格式为:
datatype *name;//*表示这是一个指针变量,datatype表示该指针变量所指向的数据的类型。
//例如:
int *p1;//此时的p1是一个指向int类型数据的指针变量,至于p1究竟指向哪一份数据,应该由赋予它的值决定。
//形式如下
datatype *name=value;
//例如:
int a=10;
int *p_a=&a;//在定义指针变量p_a的同时对它进行初始化,并将变量a的地址赋予它,此时p_a就指向了a;此处p_a需要的是一个地址(注意是p_a需要的是一个地址,而不是*p_a),所以a前边必须要加取地址符,否则是不对的。
(2)同普通变量一样,指针变量也可以被多次写入,只要你想修改指针变量的值,随时都能够改变指针变量的值。举例如下:
//定义普通变量
float a=65.9,b=5.3;
char c='a',d='2';
//定义指针变量
float *p1=&a;//p1的类型是float*不是float//p1需要的是地址;//此处看见*号这个特殊的符号,表明定义的这个变量是指针变量,定义指针变量p1时必须带*号。下边对p1进行赋值时,见下。
char *p2=&c;//p2的类型是char*//p2需要的是地址;
//修改指针变量的值
p1=&b;//对p1进行赋值时,因为已经知道了p1是一个指针变量,所以就没必要再多此一举的带上*号,后边可以像使用普通变量一样来使用指针变量。
p2=&d;//即定义指针变量时必须带*号,给指针变量赋值时不能带*号。
p1,p2指向关系如下图:假设变量a,b,c,d的地址分别为0X1000、0X1004、0X2000、0X2004
(3)通过指针变量取得数据,(PS:看清楚获得的是数据数据数据)格式如下:
//指针变量存储了数据的地址,通过指针变量能够获取地址上的数据,格式如下:
*pointer//此处的*号为指针运算符,用来取得某个地址上得数据。
下面举一个例子看一下输出结果就知道了:
#include <stdio.h>
#include <iostream>
using namespace std;
int main() {
int a = 15;
int *p = &a;//p指向a后,p本身的值就会变成a的地址。
cout << a <<","<<p <<","<<*p << endl;//p是地址,*p是15,在指针变量前边加*表示获取指针指向的数据,或者说表示的是指针指向的数据本身。(此处就是说明了使用指针变量时的*与定义指针变量时的*号意义完全不同)
printf("%d, %d,%#X\n", a, *p, p); //两种方式都可以输出a的值,*p与a等价。
return 0;
}
由前一节的介绍我们知道,CPU 读写数据必须要知道数据在内存中的地址,普通变量和指针变量都是地址的助记符,由上边我们可以看出*p和a输出的结果是一样的,但是他们的运行过程不一样,a只需要一次运算就能够取得数据,而 *p 要经过两次运算,多了一层“间接”。
假设变量 a、p 的地址分别为 0X1000、0XF0A0,它们的指向关系如下图所示:
程序被编译和链接后,a、p 被替换成相应的地址。使用 *p 的话,要先通过地址 0XF0A0 取得变量 p 本身的值,这个值是变量 a 的地址,然后再通过这个值取得变量 a 的数据,前后共有两次运算;而使用 a 的话,可以通过地址 0X1000 直接取得它的数据,只需要一步运算。
也就是说,使用指针是间接获取数据,使用变量名是直接获取数据,前者比后者的代价要高。
(4)通过指针修改内存上的数据
#include <stdio.h>
#include <iostream>
using namespace std;
int main() {
int a = 1, b = 17, c = 2;
int *p = &a; //定义指针变量,(1)此时*p代表的是a中的数据,即*p=a;
*p = b; //通过指针变量修改内存上的数据//(2)将另一份数据赋值给他
c = *p; //通过指针变量获取内存上的数据//(3)再将它赋值给另外一个变量
cout << a <<" , "<< b <<" , "<< c <<" , " <<*p << endl;
printf("%d, %d, %d, %d\n", a, b, c, *p);
return 0;
}
结果如下:
使用指针交换值的例子:
#include <stdio.h>
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 99, temp;//临时变量temp
int *pa = &a, *pb = &b;
cout << a << " , " << b << endl;
printf("a=%d, b=%d\n", a, b);
/*****开始交换*****/
temp = *pa; //*pa=a=10 //将a的值先保存起来//因为下一个语句中a的值会被b的值覆盖
cout << a << " , " << b << ","<<temp<<endl;
*pa = *pb; //将b的值交给a//a的值会被b的值覆盖
*pb = temp; //再将保存起来的a的值交给b
/*****结束交换*****/
printf("a=%d, b=%d\n", a, b);
return 0;
}
结果如下:
总结:
假设有一个 int 类型的变量 a,pa 是指向它的指针,那么*&a
和&*pa
分别是什么意思呢?*&a
可以理解为*(&a)
,&a
表示取变量 a 的地址(等价于 pa),*(&a)
表示取这个地址上的数据(等价于 *pa),绕来绕去,又回到了原点,*&a
仍然等价于 a(是一个int型的数据)。&*pa
可以理解为&(*pa)
,*pa
表示取得 pa 指向的数据(等价于 a),&(*pa)
表示数据的地址(等价于 &a),所以&*pa
等价于 pa(是一个地址)。
ps:星号*
主要有三种用途:
- 表示乘法,例如
int a = 1, b = 2, c; c = a * b;
,这是最容易理解的。 - 表示定义一个指针变量,以和普通变量区分开,例如
int a = 10; int *p = &a;
。 - 表示获取指针指向的数据,是一种间接操作,例如
int a1, b1, *p = &a1; *p = 100; b1 = *p;
。