C---指针

指针

指针是什么

这是个概念性的问题, 指针, 字面上是用来指向某个对象的东西, 在计算机中, 最基本的指向关系就是一个对象的内容其内存地址之间的关系, 就宛如酒店的房间房卡

说到指针, 就要提到一对操作符: 取址&指针*

但要注意的是, &得到的是指针, 而*是用来操作指针的

变量-指针

一个变量的地址就称为这个变量的指针

指针变量

假设我们有两个变量 i和j 而且 我们要获取他们的地址并保存到指针变量中

1
2
3
4
5
6
int i,j;

int *pointer_i, *pointer_j;

pointer_i = &i;
pointer_j = &j;

定义一个指针变量的基本语句

基类 *变量标识符 = &同基类变量名;

基类就是该指针变量所指向的变量类型, 指针名就是标识符, *不算入指针变量名称

但定义指针变量时不能直接给其赋值

所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。

调用时分为调用指针和调用变量

1
cout << pointer_i << " " << *pointer_i;

第一个输出的是i变量的内存地址, 后面则会输出改地址所指向的具体数据

指针详解

NULL指针

在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。

NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

using namespace std;

int main ()
{
int *ptr = NULL;

cout << "ptr 的值是 " << ptr ;

return 0;
}

返回结果:

1
ptr 的值是 0

在VS2013中写cpp可以看到对NULL指针的具体定义为define NULL 0

(只是一个零值)

指针算数运算

加减

指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、–、+、-。

假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:

prt++这个运算会让原本值为1000的指针ptr后移一位到1004

后移量取决于基类长度

指针递增实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

using namespace std;
const int MAX = 3;

int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr;

// 指针中的数组地址
ptr = var;
for (int i = 0; i < MAX; i++)
{
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;

cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;

// 移动到下一个位置
ptr++;
}
return 0;
}

这个就是因为数组索引只能是常量, 所以才会利用到指针的递增特性去循环读取每一个元素, 递减则需要更改运算符和起始指针位置

比较

指针之间可以互相比较, 但其比较的逻辑概念不是大小而是前后

所用运算符是<, >, ==

指针数组

可能有一种情况,我们想要让数组存储指向 int 或 char 或其他数据类型的指针。下面是一个指向整数的指针数组的声明:

基类 *name[NUM]

这里的name是一个数组, 由NUM个基类类型指针组成, 其中每一个元素都是指向对应基类值的指针

一个整形实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
const int MAX = 3;

int main()
{
int var[MAX] = {10, 100, 200};
int *ptr[MAX];

for (int i = 0; i < MAX; i++)
{
ptr[i] = &var[i]; // 赋值为整数的地址
}
for (int i = 0; i < MAX; i++)
{
cout << "Value of var[" << i << "] = ";
cout << *ptr[i] << endl;
}
return 0;
}

其中每个ptr元素都是var中对应索引的指针

对于char型的指针数组, 则可以利用其性质来进行一个字符串数组的定义

下面是正常字符数组的定义

1
2
3
4
5
6
const char names[MAX] = {
'z',
'h',
'e',
'n',
};

如果想定义一个字符串数组, 这样是错误的

1
2
3
4
5
6
const char names[MAX] = {
"zhen",
"h",
"123",
"1",
};

这样会出现类型不匹配的报错

但字符串的开头其实是首个字符的地址, 也就满足了指针数组的性质

对上述代码添加一个*, 既可以用char基类来创建字符串数组

1
2
3
4
5
6
const char *names[MAX] = {
"zhen",
"h",
"123",
"1",
};

指针的指针

指针的指针定义方式有所不同

基类 **name

指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。

指针的指针就是将指针的地址存放在另一个指针里面。

通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。

调用指针指针的时候, 会按链寻址到最后的目标数据上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
int main ()
{
int var = 3000;
int *ptr;
int **pptr;

// 获取 var 的地址
ptr = &var;

// 使用运算符 & 获取 ptr 的地址
pptr = &ptr;

// 使用 pptr 获取值
cout << "var 值为 :" << var << endl;
cout << "*ptr 值为:" << *ptr << endl;
cout << "**pptr 值为:" << **pptr << endl;

return 0;
}

output :

1
2
3
var 值为 :3000
*ptr 值为:3000
**pptr 值为:3000

指针形参

指针可以被当作形参传递给函数,
传入值需要是一个指针或者地址也可以是一个数组

在函数内的调用方式遵循语法即可

函数值返回到指针

函数的返回值可以是指针, 定义时添加*可以改变函数的返回值

1
2
3
4
基类 * functionName()
{

}

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;

// 要生成和返回随机数的函数
int * getRandom( )
{
static int r[10];

// 设置种子
srand( (unsigned)time( NULL ) );
for (int i = 0; i < 10; ++i)
{
r[i] = rand();
cout << r[i] << endl;
}

return r;
}

// 要调用上面定义函数的主函数
int main ()
{
// 一个指向整数的指针
int *p;

p = getRandom();
for ( int i = 0; i < 10; i++ )
{
cout << "*(p + " << i << ") : ";
cout << *(p + i) << endl;
}

return 0;
}
  • Copyrights © 2024 Cdog Shen
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信