指针是一种保存变量地址的变量。
- 变量放在机器中有编号的存储单元中,就像变量放在房间里,房间有门牌号
- 指针这种变量专门用来存放门牌
- 一般而言,一个存储单元存储8位,比如一个int类型占位32位,那么它就被放在四个连续的存储单元中,而指针变量一般存放变量存储最开始的那个存储单元的地址
指针类型变量声明
数据类型 *变量名;
- 和普通变量声明一致,就是在变量名前加了个星号*
代码示例
int *pi;//声明了一个变量pi,用他来存放int类型变量的地址
char *pc; //声明了一个变量pi,用他来存放char类型变量的地址
- 也可以叫pi为指向int类型的指针
- 指针只能指向特定类型的对象
指针类型变量使用
- 如何获取变量地址
- 使用&操作符可以得到变量的地址
数据类型 *变量名 = &之前声明过的变量名;
代码示例
int a = 10;
int *pa = &a;//将变量a的地址赋值给指针变量
- 如何通过指针来操作变量
- 使用*操作符间接引用变量,访问指针指向的内容
*指针变量名; //获取指针指向的内容
代码示例
#include <stdio.h>
int main(int argc, char const *argv[])
{
int a = 10;
int b;
int *pa = &a;
b = *pa; // 将pa指针指向的内容赋值给b,b=10
*pa = 100; // pa指针指向的内容变更为100,那么a也将变更为100
printf("a:%d\n", a); // 100
printf("b:%d\n", b); // 10
return 0;
}
运行结果:
a:100
b:10
指针与数组
指针访问数组元素
- 指针运算符
- 指针可以应用++/–/+n/-n运算
- +1表示指针后移一个数据类型单元
- -1表示指针前移一个数据类型单元
- 指针可以应用++/–/+n/-n运算
- 数组是一组连续的数据类型存储单元
- 数组元素依序占据数据类型单元
- 可以应用指针运算前后移动访问数组元素
代码示例
#include <stdio.h>
int main(int argc, char const *argv[])
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *pi = &a[2]; // 指针指向数组中的某个元素
printf("pi point to %d\n", *pi); //3
pi++; //指针后移一个数据类型单元,指向a[3]
printf("pi point to %d\n", *pi); //4
pi--;//指针前移一个数据类型单元,指向a[2]
printf("pi point to %d\n", *pi); //3
return 0;
}
运行结果:
pi point to 3
pi point to 4
pi point to 3
数组名也是指针
- 数组名可以直接赋值给指针变量
- 数组名这个指针只能指向数组首元素,不能指向其他地方
- 数组名可以通过对数组名+n来访问数组元素
- 指针也可以通过[下标]的方式来访问数组元素
代码示例
#include <stdio.h>
int main(int argc, char const *argv[])
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *pi = a;//数组名可以直接赋值给指针,指针指向数组
printf("a[0] %d\n", *a); //a[0]
printf("a[4] %d\n", *(a+4)); //a[4]
printf("pi point to a[2] %d\n", pi[2]); //指针可以通过下标方式访问数组元素
//int i = 10;
//a = &i;//a不能指向其他地方
//a++;//非法
return 0;
}
运行结果:
a[0] 1
a[4] 5
pi point to a[2] 3
指针数组
即存放指针类型变量的数组
数据类型 *数组名[数组大小];
- 指针数组的数组名此时就会有个高大上的名字叫做:指向指针的指针
代码示例
#include <stdio.h>
int main(int argc, char const *argv[])
{
int *ppi[10]; //存放指针类型的数组
int a = 10;
int b = 100;
int c = 1000;
ppi[0] = &a;
ppi[1] = &b;
ppi[2] = &c;
printf("a %d\n", *(*ppi));
printf("b %d\n", *(*(ppi+1)));
printf("c %d\n", *(ppi[2]));
return 0;
}
运行结果:
a 10
b 100
c 1000
字符指针与字符串
字符指针可以指向字符串常量
- 与字符数组接收字符串常量不同的是,通过字符指针不能修改字符串中的字符
代码示例
#include <stdio.h>
int main(int argc, char const *argv[])
{
char *pc = "hello";
printf("string is : %s\n", pc);
printf("the seccond char is %c\n", *(pc+1));
printf("the third char is %c\n", pc[2]);
pc[4] = 'a';//会有问题,结果不确定,不要通过字符指针修改字符串常量
return 0;
}
运行结果:
string is : hello
the seccond char is e
the third char is l
zsh: bus error ./a.out //您的结果可能和我的不同
指针与结构体
指向结构体的指针
struct 结构体类型 *指向结构体的指针名;
- 通过指向结构体的指针访问结构体时,可以使用->操作符
代码示例
#include <stdio.h>
int main(int argc, char const *argv[])
{
struct point{
int x;
int y;
} p1;
struct point *ps = &p1;
(*ps).x = 1;
ps -> y = 3; //可以使用->操作符访问结构体成员
printf("point is (%d, %d)\n", ps -> x, ps -> y);
return 0;
}
运行结果:
point is (1, 3)
指针与函数参数
- 指针类型可以作为函数参数类型
- 指针类型形参和普通类型形参的区别
- 普通类型形参,函数接收的是参数的副本,在函数中修改的也只是参数副本,对参数本身没有任何影响
- 指针类型形参,接收的是参数的地址,在函数中对指针内容的修改,将直接反应到参数本身上
代码示例
#include <stdio.h>
void swap(int a, int b);
void swap2(int *a, int *b);
int main(int argc, char const *argv[])
{
int a = 10;
int b = 20;
swap(a, b);
printf("after-swap a is: %d\n", a);
printf("after-swap b is: %d\n", b);
swap2(&a, &b);
printf("after-swap2 a is: %d\n", a);
printf("after-swap2 b is: %d\n", b);
return 0;
}
void swap(int a, int b){ //只是修改参数副本,不影响参数本身
int temp = 0;
temp = a;
a = b;
b = temp;
printf("in-swap a is: %d\n", a);
printf("in-swap b is: %d\n", b);
}
void swap2(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
printf("in-swap2 a is: %d\n", *a);
printf("in-swap2 b is: %d\n", *b);
}
运行结果:
in-swap a is: 20
in-swap b is: 10
after-swap a is: 10
after-swap b is: 20
in-swap2 a is: 20
in-swap2 b is: 10
after-swap2 a is: 20
after-swap2 b is: 10
指向函数的指针
- 可以通过指向函数的指针访问函数
- 这种类型的指针和其他指针变量一样,可以被修改赋值,可以放在数组中,可以当作函数参数,可以当作函数返回值
函数返回值类型 (*函数指针名)(参数列表);//声明指向函数的指针
(*函数指针名)(传参列表); //通过指向函数的指针访问函数
代码示例
#include <stdio.h>
void swap2(int *a, int *b);
int main(int argc, char const *argv[])
{
int a = 10;
int b = 20;
void (*swap)(int *, int *) = swap2;//定义swap指向swap2函数
(*swap)(&a, &b); //通过函数指针访问函数
printf("after-swap a is: %d\n", a);
printf("after-swap b is: %d\n", b);
return 0;
}
void swap2(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
printf("in-swap2 a is: %d\n", *a);
printf("in-swap2 b is: %d\n", *b);
}
运行结果:
in-swap2 a is: 20
in-swap2 b is: 10
after-swap a is: 20
after-swap b is: 10