一、什么是指针
计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,例如int类型占用4个字节,char类型占用1个字节。为了正确地访问这些数据,必须为每个字节都编上号码,就想门牌号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。我们将内存中字节的编号称为地址或指针。地址从0开始最小的地址为0x0000 0000,最大的地址为0xFFFF FFFF。
二、定义一个指针``
int *p,s; //p是整型指针变量,s是整型变量
char *cpa,*cpb; //cpa和cpb都是char类型指针变量
int a=10;
int *ip; //指针一般要直接进行初始化
ip =&a; //等价于 int *p=&a;
三、空指针和野指针
1、空指针
int *p = NULL; NULL 指针是一个特殊的指针变量,表示不指向任何东西。
2、野指针
2.1 使用未初始化的指针
int i = 3;
int *j;
*j = i;
指针在被定义的时候,如果程序不对其进行初始化的话,它会随机指向一个区域,当程序往这块内存空间写数据时会报错。
2.2 free指针后未把指针置为NULL
char *p;
p = (char*)malloc(20);
free(p);
这儿已经释放了p指向的内存空间。但是p指向的内存地址还没有变,如果别的程序在使用这款空间时会出现一些不可估量的问题。
四、指针的运算
1、指针 +/- 整数 :
int a = 10, *pa = &a, *paa = &a;
double b = 99.9, *pb = &b;
char c = '@', *pc = &c;
//最初的值
printf("&a=%#X, &b=%#X, &c=%#X\n", &a, &b, &c);
printf("pa=%#X, pb=%#X, pc=%#X\n", pa, pb, pc);
//加法运算
pa++; pb++; pc++;
printf("pa=%#X, pb=%#X, pc=%#X\n", pa, pb, pc);
运行结果:
&a=0X28FF44, &b=0X28FF30, &c=0X28FF2B
pa=0X28FF44, pb=0X28FF30, pc=0X28FF2B
pa=0X28FF48, pb=0X28FF38, pc=0X28FF2C
可以看到指针的类型不同,加1的能力也不一样。
typename *p;
p=p+1; 被编译器翻译成 : p = p +sizeof(typename)*1;
2、指针 - 指针 :
两个同类型指针,指向连续空间可以相减。减后的结果是数据元素的大小。
如: int类型指针 - int类型指针结果是整型元素的个数。
char类型指针 - char 类型指针结果是整型元素的个数。
#include "stdio.h"
int main(){
int a[10] = {1,2,3,4,5,6,7,8,9,0};
int sub;
int *p1 = &a[2];
int *p2 = &a[8];
sub = p2-p1;
printf("%d\n",sub); // 输出结果为 6
return 0;
}
五、数组与指针
1、利用指针访问数组
int ar[10] = {1,2,3,4,5,6,7,8,9,0};
int *p=ar;
for(int i=0;i<10;i++)
{
printf("%d",*(p+n);
}
2、指针数组
int *p[20]; //定义一个大小为20,类型为int*类型的数组。
3、数组指针
int main(){
int ar[2][3] = {1,2,3,4,5,6}; // 定义一个二维数组并初始化
int (*p)[3]; // 定义一个数组指针,指针指向一个含有3个元素的一维数组
p = ar; // 将二维数组的首地址赋给 p,此时 p 指向 arr[0] 或 &arr[0][0]
printf("%d\n",(*p)[0]); // 输出结果为 1
p++; // 对 p 进行算术运算,此时 p 将指向二维数组的下一行的首地址,即 &arr[1][0]
printf("%d\n",(*p)[1]); // 输出结果为5
return 0;
}
六、结构体指针
结构体指针是指向结构的指针。可以用->进行成员访问
typedef struct Stu{
char name[10];
int age;
int score;
};
int main(){
struct Stu stu1= {"zhangsan",23,80};
struct Stu *p = &stu1;
printf("%s\n",p->name); // 输出结果为:zhangsna
printf("%d\n",p->score); // 输出结果为:80
return 0;
}
七、函数指针
在C语言中,函数本身不是变量,但是可以定义指向函数的指针,也称作函数指针,函数指针指向函数的入口地址。这种类型的指针可以被赋值、存放在数组中、传递给函数以及作为函数的返回值等等。 声明一个函数指针的方法如下:
int (*pointer)(int *,int *); // 声明一个返回值为int型,形参列表为2个指针变量的函数指针。
#include<stdio.h>
void* Print_Int(void* p) //利用无类型的指针接收地址
{
int* ip = (int*)p;
printf("%d ", *ip);
return ip + 1;
}
void* Print_Double(void* p)
{
double* dp = (double*)p;
printf("%lf ", *dp);
return dp + 1;
}
void Print_Array(void* br, int n, void* (*fp) (void*))
{
for (int i = 0; i < n; ++i)
{
br = (*fp)(br); 利用(*fp)调用函数
}
printf("\n");
}
int main()
{
int ar[] = { 12,23,34,45,56,67,78 };
int in = sizeof(ar) / sizeof(ar[0]);
double dx[] = { 1.2,2.3,3.4,4.5,5.6,6.7,7.8,8.9 };
int dn = sizeof(dx) / sizeof(dx[0]);
Print_Array(ar, in, Print_Int);
Print_Array(dx, dn, Print_Double);
return 0;
}
输出结果:
12 23 34 45 56 67 78
1.200000 2.300000 3.400000 4.500000 5.600000 6.700000 7.800000 8.900000