【C语言】第八期——指针
目录
1 初始指针
2 获取变量的地址
3 定义指针变量、取地址、取值
3.1 定义指针变量
3.2 取地址、取值
4 对指针变量进行读写操作
5 指针变量作为函数参数
6 数组与指针
6.1 指针元素指向数组
6.2 指针加减运算(了解)
6.2.1 指针加减具体数字
6.2.2 指针加减指针
6.3 数组名与数组元素首地址的关系
1 初始指针
通过前面的教程我们知道变量是用来存储数据的,变量的本质是给存储数据的内存地址起了一个好记的别名
比如我们定义了一个变量 int a= 10 ,这个时候可以直接通过a这个变量来读取内存中保存的10 这个值,在计算机底层a这个变量其实对应了一个内存地址
指针也是一个变量,但它是一种特殊的变量,它存储的数据不是一个普通的值,而是另一个变量的内存地址
每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表 示了在内存中的一个地址
刚开始学C语言的指针操作,我们只需要记住两个符号 :&(取地址) 和 *(根据地址取值 /定义指针变量)
2 获取变量的地址
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。C语言中使用&字符放在变量 前面对变量进行取地址操作
#include <stdio.h>
int main(void)
{
int a = 10;
printf("a的地址是:%p\n", &a);
return 0;
}
3 定义指针变量、取地址、取值
3.1 定义指针变量
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:
type *var-name;
在这里,type 是指针的基类型,它必须是一个有效的 C 数据类型,var-name 是指针变量的名称。用 来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是 指针
以下是有效的指针声明:
int* ip; //一个整型的指针
double* dp; //一个 double 型的指针
float* fp; //一个浮点型的指针
char* ch //一个字符型的指针
所有指针的值都是一个地址,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是 一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同
3.2 取地址、取值
#include <stdio.h>
int main(void)
{
// 定义一个int变量a
int a = 10;
printf("a的地址是:%p\n", &a);
// 定义int类型的指针变量p
int* p_a = &a;
printf("指针p_a的值:%p\n", p_a);
printf("指针p_a的地址:%p\n", &p_a);
printf("a的值:%d\n", a);
printf("根据指针p_a的值去内存取值得到的结果为:%d", *p_a);
return 0;
}
总结:
- 取地址操作符&和取值操作符是一对互补操作符, & 取出地址, 根据地址取出地址指向的值
- 对变量进行取地址(&)操作,可以获得这个变量的地址
- 指针变量的值是地址
- 对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值
4 对指针变量进行读写操作
#include <stdio.h>
int main(void)
{
int a = 10;
int b = 20;
int* p1, * p2; // 定义指针变量 p1、 p2
p1 = &a;
// p1 指向变量 a
p2 = p1;
// p2 指向变量 a
printf("&a=%p p1=%p p2=%p\n", &a, p1, p2);
*p1 = 20;
printf("a的值%d,取指针得到的值%d", a, *p1);
return 0;
}
运行结果:
&a=000000612A17FA74 p1=000000612A17FA74 p2=000000612A17FA74
a的值20,取指针得到的值20
5 指针变量作为函数参数
在C语言中,函数参数不仅可以是字符型、整型、浮点型等,还可以是指针类型,作用是将变量地址传递给函数形参
#include <stdio.h>
void modify1(int *c)
{
*c = 20;
}
int main(void) {
int a = 10;
modify1(&a);
printf("%d", a);
return 0;
}
6 数组与指针
6.1 指针元素指向数组
数组本质上是一片连续的内存空间,每个数组元素都对应一块独立的内存空间,它们都有相应的地址。
因此,指针变量既然可以指向变量,也就可以指向数组元素
数组的元素本质上完全可以当做是单独的变量对待,只不过没有名称而已
int a[5]={1,2,3,4,5}; //定义长度为5的int数组
int *p_a=&a[0]; //定义指向int变量的指针变量p_a,把a数组第0个元素地址赋给指针变量p_a
注意:&a[0]等价于&(a[0]),由于[ ]运算符比取地址运算符&优先级高,因此&(a[0])中的小括号可以省略,简写为:&a[0]
在计算机中内存的最小单位是字节,每个字节都对应一个地址
如果一个变量占用多个字节,就会占用 多个内存地址
例如: char 类型变量占1字节就对应1个地址,short 类型变量占2字节对应2个地址,int 类型变量占4 字节对应4个地址.....·其他类型依次类推
同理,数组元素类型不同占用的内存地址也不同
下面通过例子来验证以上分析
#include<stdio.h>
int main(void)
{
char c[5];
short s[5];
int i;
for (i = 0; i < 5; i++)
{
printf("&c[%d]=%p ", i, &c[i]);
printf("&s[%d]=%p \n", i, &s[i]);
}
return 0;
}
运行结果:
&c[0]=000000000061FE17 &s[0]=000000000061FE0C
&c[1]=000000000061FE18 &s[1]=000000000061FE0E
&c[2]=000000000061FE19 &s[2]=000000000061FE10
&c[3]=000000000061FE1A &s[3]=000000000061FE12
&c[4]=000000000061FE1B &s[4]=000000000061FE14
说明:不同设备上面输出的地址可能不一样的,数组中每个元素地址都是连续的
6.2 指针加减运算(了解)
6.2.1 指针加减具体数字
指针本质上就是内存地址,在32 位操作系统下,内存地址是 4 字节的整数。既然是整数就可以进行 加、减、乘、除等算术运算。不过需要注意的是,在 C 语言中一般只讨论指针加、减运算,乘、除等其 他算术运算都没有意义
在实际开发中,指针加、减运算多用于数组(或连续内存空间)。当指针变量p 指向数组元素时,p+1 表 示指向下一个数组元素,p-1 表示指向上一个数组元素
#include <stdio.h>
int main(void)
{
int a[3] = { 1, 2, 3 };
int* p = &a[0];// 指针 p 指向 a[0]
printf("%p %d\n", p, *p); // 输出 a[0] 的地址 和 a[0] 的值
p = p + 1;// p 加 1
printf("%p %d\n", p, *p); // 输出 a[1] 的地址 和 a[1] 的值
return 0;
}
运行结果:
000000811557F968 1
000000811557F96C 2
注意:实现指针加减的时候需要注意越界问题
6.2.2 指针加减指针
在C语言中,两个指针相加是没有意义的,而两个指针相减却有特殊的意义,不过只有当两个指针都指向同一数组中的元素时才有意义
一个数组中的元素时,对它们进行减法运算,得到的结果是这两个指针所指向元素之间相隔的元素个数 (不是之间有的个数,之间有的元素数要在此基础上减一),而不是它们地址差值的字节数。其计算方式是用两个指针的地址差值除以指针所指向数据类型的大小
用公式表示为:
(指针2的地址 - 指针1的地址) / sizeof(指针所指向的数据类型)
6.3 数组名与数组元素首地址的关系
C语言中,数组名与数组首元素地址等价。也就是说,在程序中,输出数组名与输出数组首元素地址是相同的
#include <stdio.h>
int main(void)
{
int num[5];
printf("%p\n", num); // 输出数组名
printf("%p\n", &num[0]); // 输出数组首元素地址
return 0;
}
输出结果:
000000000061FE00
000000000061FE00
我们就可以通过把数组名复制给指针变量,来把数组首地址给指针变量
#include <stdio.h>
int main(void)
{
int num[5] = {1, 2, 3, 4, 5};
int *p_num = num; // 把num的首地址赋值给指针变量
printf("p_num指针的值=%p \n p_num对应数组元素的值%d", p_num, *p_num);
return 0;
}
我们也可以通过p_num来访问数组里面的每个元素
#include <stdio.h>
int main(void)
{
int num[5] = {1, 2, 3, 4, 5};
int *p_num = num; // 把num的首地址赋值给指针变量
printf("p_num指针的值=%p ,num的地址是=%p p_num对应数组元素的值%d\n", p_num, num,
*p_num);
printf("p_num访问第一个元素=%d\n", p_num[0]);
printf("p_num访问第二个元素=%d\n", p_num[1]);
return 0;
}
运行结果:
p_num指针的值=000000000061FE00 ,num的地址是=000000000061FE00 p_num对应数组元素的值1
p_num访问第一个元素=1 p_num访问第二个元素=2
持续更新中...