第七章 指针

指针(pointer)简介

  • 指针是一个值为内存地址的变量(或数据对象)

见图c

c

声明即初始化指针变量

  • 基本用法:数据类型 * 指针变量名;

  • 例如:

    • int * ptr_num;
    • char * ptr_name;
    • float * money_ptr;
    • double * p_price;
  • 注意:

    在头文件<stdio.h>中,NULL被定义为常量

    int * ptr_num = NULL;

    指针的初始值设为空,表示指针不指向任何地址

取地址符&

见图d

d

1
2
3
4
int num = 1024;
int * ptr_num;
//取num变量的地址赋值给ptr_num
ptr_num = &num;

间接运算符

见图e、f

e

f

1
2
3
4
5
int num = 1024;
int * ptr_num;
ptr_num = & num;

*ptr_num = 1111;

指针使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
void main()
{
int num = 1024;//整型变量
int *ptr_num;//整型指针变量
//取num的地址赋值给ptr_num变量
ptr_num = &num;
printf("num的值为:%d\n",num);
printf("num的内存地址为:%p\n",&num);
printf("ptr_num的值为:%p\n",ptr_num);
printf("ptr_num的内存地址为:%p\n",&ptr_num);
printf("*ptr_num指向的值为:%d\n",*ptr_num);
}
/* 打印结果:
num的值为:1024
num的内存地址为:0028FF44
ptr_num的值为:0028FF44
ptr_num的内存地址为:0028FF40
*ptr_num指向的值为:1024
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
void main()
{
int num1 = 1024;
int num2 = 2048;
int *ptr1, *ptr2;
ptr1 = &num1;
ptr2 = &num2;
printf("num1的值是%d\tnum1的地址是:%p\n",num1,ptr1);
printf("num2的值是%d\tnum2的地址是:%p\n",num2,ptr2);
//ptr2 = ptr1;
*ptr2 = *ptr1;
printf("重新赋值后:\n");
printf("num2的值是%d\tnum2的地址是:%p\n",num2,ptr2);
}

指针小结

  • 指针同样是一个变量,只不过该变量中存储的是一个对象的内存地址

  • 如果一个变量存储另一个对象的地址,则称该变量指向这个对象

  • 指针变量可以赋值,指针的指向在程序执行中可以改变

  • 指针p在执行中某刻指向变量x,在另一时刻也可以指向变量y

  • 注意:

    1、指针变量的命名规则和其他变量的命名规则一样

    2、指针不能与现有变量同名

    3、指针可存放c语言中的任何基本数据类型、数组和其他所有高级数据结构的地址

    4、若指针已声明为指向某种类型数据的地址,则它不能用于存储其他类型数据的地址

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
#include <stdio.h>
#include <stdlib.h>

void main()
{
int num = 1024;
int* ptr_num = &num;
int** ptr_num2 = &ptr_num; //二级指针,两个星号

int num2 = 2048;
int* mtr_num = &num2;
printf("num的值为:%d\t内存地址为:%p\n",num,ptr_num); //&取内存地址,与直接用地址变量的名一样
printf("num的内存地址为:%p\n",&num);
printf("ptr_num的值为:%p\n", ptr_num);
printf("ptr_num的内存地址为:%p\n",&ptr_num);
printf("ptr_num指向的值为:%d\n",*ptr_num);
printf("ptr_num2的值为:%p\n",ptr_num2);
printf("ptr_num2的内存地址为:%p\n",&ptr_num2);
printf("ptr_num2指向的值为:%d\n",**ptr_num2); //两个*代表通过指针的指针访问原指针空间
printf("-----------------------------------------------------\n");
printf("num的值是%d\tnum的地址是:%p\n", num, ptr_num);
printf("num2的值是%d\tnum的地址是:%p\n", num2, mtr_num);
//将变量1值赋给变量2
//num2 = num; //等价 *mtr_num = *ptr_num
//直接操作指针
mtr_num = ptr_num; //是mtr_num的值(变量)赋给了ptr_num的值(变量被更改),导致两个指针都指向一个内存空间
printf("重新赋值后:\n");
printf("num的值是%d\tnum的地址是:%p\n", num, ptr_num);
printf("num2的值是%d\tnum2的地址是:%p\n", num2, mtr_num);
*mtr_num = 11111111; //所以这里的指针,指向了num,改它就相当于改了num的值,而不是num2
printf("重新赋值后:\n");
printf("num的值是%d\tnum的地址是:%p\n", num, ptr_num);
printf("num2的值是%d\tnum2的地址是:%p\n", num2, mtr_num);

mtr_num = NULL; //防止野指针的乱入,所以经常用完后把野指针设为空
}

指针与数组

  • 数组:
    • 存储在一块连续的内存空间中
    • 数组名就是这块连续内存空间的首地址
1
2
3
4
double score[5] = {98,87,65,43,76};
double * ptr_score;
ptr_score = &score[0];
//ptr_score = score;

见图g

g

指针运算

  • 指针的算数运算
    • 指针的递增和递减(++、–)
1
2
3
4
5
6
7
8
int i;
double score[5] = {98,87,65,43,76};
double * ptr_score;
ptr_score = score;
for(i = 0;i < 5;i++)
{
printf("%.2lf\n",*ptr_score++);
}
  • 注意:一个类型为T的指针移动,以sizeof(T)为移动单位

数组与指针小结

  • int num[50];//num是数组名,也是数组的首地址

  • num的值与&num[0]的值是相同的

  • 数组第i+1个元素可表示为:

    • 第i+1个元素的地址:&num[i]或num+i
    • 第i+1个元素的值:num[i]或*(num+i)
  • 为指向数组的指针赋值:

    • int * ptr_num = num; 或int * ptr_num = &num[0];
  • 指针变量可以指向数组元素

    • int * ptr_num = &num[4]; 或 int * ptr_num = num + 4;
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
#include <stdio.h>
#include <stdlib.h>

void main()
{
int i;
double score[] = { 98,87,65,43,76 };
double* ptr_score;
ptr_score = score;
printf("double型数组的地址占%d个字节\n",sizeof(ptr_score));
printf("数组的首地址:%p\t数组首元素的地址:%p\n",score,&score[0]); //数组名就是数组的首地址
for (i = 0; i < 5; i++)
{
//printf("%.2lf\n", ptr_score[i]);
//printf("%.2lf\n", *(ptr_score + i));
printf("%.2lf\n", *ptr_score++); //打印数组的每个元素
}
//指针的递增和递减,double类型指针每次移动以8字节移动,每一个元素占8字节
printf("******************************************************\n");
//假设我们希望再次打印数组的每个元素
//重新访问数组元素前,记得重置指针位置
ptr_score = score; //如果是用 *(ptr_score + i)则不用,否则 *ptr_score++ 会访问不知名的内存地址
for (i = 0; i < 5; i++)
{
//printf("%.2lf\n", ptr_score[i]);
//printf("%.2lf\n", *(ptr_score + i));
printf("%.2lf\n", *ptr_score++);
}
//在c语言中指针可以随意加或减,如果超出现在内存空间,可能会指向其他内存空间
}

数组与指针示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
void main()
{
int array[] = {15,20,25,30,35};
int i;//循环变量
int * ptr_array = array;
for(i = 0;i < 5;i++)
{
printf("第%d个元素的值为%d\t地址为:%p\n",i+1,*ptr_array,ptr_array);
}
}
/* 结果为
第1个元素的值为15 地址为:0028FF20
第2个元素的值为20 地址为:0028FF24
第3个元素的值为25 地址为:0028FF28
第4个元素的值为30 地址为:0028FF2C
第5个元素的值为35 地址为:0028FF30
*/

指针与二维数组

  • 首地址:&a[0] [0]
  • 使用指针访问二维数组中的元素
    • *(a[1] + 2)
    • *( *(a[1] + 2))
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
38
39
40
41
42
43
44
#include <stdio.h>
#include <stdlib.h>
#define N 5

void main()
{
//数组名就是数组的首地址(数组首元素地址)
//二维数组的理解:二维数组是由n个1维数组组成
int i;
int j;
double score[5][3] = {
{55, 66, 77},
{52, 62, 72},
{15, 26, 37},
{54, 65, 76},
{55, 66, 77},
};
double(*ptr_score)[3] = score;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 3; j++)
{
//printf("%.2lf\t",score[i][j]); // score[i] => *(score + i)
//printf("%.2lf\t", *(score[i] + j));
//printf("%.2lf\t", *(*(score + i) + j));
printf("%.2lf\t", *(*(ptr_score + i) + j));
}
printf("\n");
}

/*
//遍历第一行数据:第一行的数组名就是score[0]
for (i = 0; i < 3; i++)
{
printf("%.2lf\t", score[0][i]);
}
printf("\n");
//遍历第二行数据:score[1]
for (i = 0; i < 3; i++)
{
printf("%.2lf\t", score[1][i]);
}
*/
}
更新于

请我喝[茶]~( ̄▽ ̄)~*

Chen 微信支付

微信支付

Chen 支付宝

支付宝

Chen 贝宝

贝宝