一.指针和指针类型
这里我们在讨论一下:指针的类型。我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢? 准确的说:有的。当有这样的代码:
int num = 10;
p = #
要将&num(num的地址)保存到p中,我们知道p就是一个指针变量,那它的类型是怎样的呢? 我们给指针变量相应的类型。
char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
这里可以看到,指针的定义方式是: type + * 。 其实: char* 类型的指针是为了存放 char 类型变量的地址。 short* 类型的指针是为了存放 short 类型变量的地址。 int* 类型的指针是为了存放 int 类型变量的地址。
指针类型的意义:
1.指针 ± 整数
#include <stdio.h>
//演示实例
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return 0;
}
运行结果:
总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。
2.指针的解引用
//演示实例
#include <stdio.h>
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
char *pi = &n;
*pc = 0x55;//重点在调试的过程中观察内存的变化。
*pi = 0; //重点在调试的过程中观察内存的变化。
system("pause");
return 0;
}
总结: 指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。 比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。
二.指针和数组
1.指针和数组名
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
printf(" arr =%p\n", arr);
printf("&arr[0]=%p\n", &arr[0]);
system("pause");
return 0;
}
运行结果:
由运行结果可见,数组名和数组首元素的地址是一样的。
结论:数组名表示的是数组首元素的地址。
2.指针运算
(1)指针变量可以互相赋值,也可以赋值某个变量的地址,或者赋值一个具体的地址。
int *px, *py, *pz, x = 10;
//赋予某个变量的地址
px = &x;
//相互赋值
py = px;
//赋值具体的地址
pz = 4000;
(2)指针与整数的加减运算
指针变量的自增自减运算。指针加 1 或减 1 运算,表示指针向前或向后移动一个单元(不同类型的指针,单元长度不同)。这个在数组中非常常用。
指针变量加上或减去一个整形数。和第一条类似,具体加几就是向前移动几个单元,减几就是向后移动几个单元。
//定义三个变量,假设它们地址为连续的,分别为 4000、4004、4008
int x, y, z;
//定义一个指针,指向 x
int *px = &x;
//利用指针变量 px 加减整数,分别输出 x、y、z
printf("x = %d", *px); //因为 px 指向 x,所以*px = x
//px + 1,表示,向前移动一个单元(从 4000 到 4004)
//这里要先(px + 1),再*(px + 1)获取内容,因为单目运算符“*”优先级高于双目运算符“+”
printf("y = %d", *(px + 1));
printf("z = %d", *(px + 2));
3.关系运算
假设有指针变量 px、py。
px > py 表示 px 指向的存储地址是否大于 py 指向的地址;
px == py 表示 px 和 py 是否指向同一个存储单元;
px == 0 和 px != 0 表示 px 是否为空指针。
//定义一个数组,数组中相邻元素地址间隔一个单元
int num[2] = {1, 3};
//将数组中第一个元素地址和第二个元素的地址赋值给 px、py
int *px = &num[0], *py = &num[1];
int *pz = &num[0];
int *pn;
//则 py > px
if(py > px){
printf("py 指向的存储地址大于 px 所指向的存储地址");
}
//pz 和 px 都指向 num[0]
if(pz == px){
printf("px 和 pz 指向同一个地址");
}
//pn 没有初始化
if(pn == NULL || pn == 0){
printf("pn 是一个空指针");
}
三.指针和数组关系代码实践
示例代码:
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i<sz; i++)
{
printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i);
}
system("pause");
return 0;
}
运行结果:
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。所以 p+i 其实计算的是数组 arr 下标为i的地址。
那我们就可以直接通过指针来访问数组。实例代码如下:
#include <stdio.h>
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i));
}
system("pause");
return 0;
}
运行结果:
总结:
1.*p = 1,此操作为赋值操作,即将指针指向的存储空间赋值为 1。此时 p 指向数组 arr 的第一个元素,则此操作将 arr 第一个元素赋值为 0,即 arr[0] = 1。
2.p + 1,此操作为指针加整数操作,即向前移动一个单元。此时 p + 1 指向 arr[0]的下一个元素,即 arr[1]。通过p + 整数可以移动到想要操作的元素(此整数可以为负数)。
3.p,(p+0)指向 arr[0]、p + 1 指向 arr[1]、、、类推可得,p+i 指向 arr[i],由此可以准确操作指定位置的元素。
4.在 (p + 整数)的操作要考虑边界的问题,如一个数组长度为 2,(p+3) 的意义对于数组操作来说没有意义。