一、指针的概念
指针是用来存储变量的地址的,通过指针可以间接操纵变量。
二、指针的定义
变量类型 *变量名; 如:int *p;定义了一个int类型的指针p。注意:任何类型的指针都占据8个字节的存储空间。
三、指针的初始化
先定义后初始化
int a = 10; // 定义变量a
int *p = &a; // 定义int型指针p,同时给指针p赋值,存放的是变量a的存储地址
四、指针的使用
1、取出指向变量的值
int a = 10;
intint *p = &a;
int value = *p; // 访问指针p所指向的变量a的值,并赋值个value,value = 10;
2、给指针指向的变量赋值
int a = 10;
int *p = &a;
*p = 20; // 指针p所指向的变量的值被改成20,也就是a的值被改成20
* 的含义:
int *p = &a 中的 * 用来说明 p 是一个指针类型的变量,和变量类型是一个整体。
*p 中得 * 用来访问 p 所指向的变量a
3、使用注意
在指针指向变量之前,不要对其所指的内容赋值。因为此时指针指向的地址不确定。如下是错误的:
int *p;
*p = 10;
4、输入a和b两个整数,按先大后小的顺序输出a和b。
void main()
{
int *p1,*p2,*p,a,b;
scanf("%d,%d",&a,&b);
p1=&a;p2=&b;
if(a<b)
{
p=p1;
p1=p2;
p2=p;
}
printf("\na=%d,b=%d\n",a,b);
printf("max=%d,min=%d\n",*p1, *p2);
}
五、指针与数组
1、数组名就是数组的地址,也是数组首元素的地址,既然是地址,也就可以赋值给指针变量。
int values[5] = {10, 9, 8, 67, 56};
intint *p = values;
intint *p2 = &values[0];
printf("%p\n", p);
printf("%p\n", p2);
输出:
0x7fff549f2c60
0x7fff549f2c60
2、利用指针来访问数组元素
int values[5] = {10, 9, 8, 67, 56};
intint *p = values;
// 数组方式
for (int i = 0; i < sizeof(values) / sizeof(int); i++) {
printf("values[%d] = %d\t", i, values[i]);
}
printf("\n");
// 数组访问方式1
for (int i = 0; i < sizeof(values) / sizeof(int); i++) {
printf("values[%d] = %d\t", i, p[i]);
}
printf("\n");
// 数组访问方式2
for (int i = 0; i < sizeof(values) / sizeof(int); i++) {
printf("values[%d] = %d\t", i, *(p + i));
}
输出:
values[0] = 10values[1] = 9values[2] = 8values[3] = 67values[4] = 56
values[0] = 10values[1] = 9values[2] = 8values[3] = 67values[4] = 56
values[0] = 10values[1] = 9values[2] = 8values[3] = 67values[4] = 56
注意:
*(p + 1);表示把指针指向的地址移到下一个该变量类型的地址
同理,*(p + i);表示在p指向的地址的基础上,把指针指向的地址移到第 i 个该变量类型的地址
3.数组作为参数传递给函数的本质就是把数组的地址传递给函数
void test(int v[])
{
printf("大小:%lu\n", sizeof(v));
printf("地址:%p\n", v);
}
int main()
{
int values[5] = {10, 9, 8, 67, 56};
printf("大小:%lu\n", sizeof(values));
printf("地址:%p\n", values);
test(values);
return 0;
}
输出:
大小:20
地址:0x7fff55dc6c60
大小:8
地址:0x7fff55dc6c60
六、指针与字符串
字符串的本质是字符数组,所以字符串的名字也就是第一个字符的地址,也是字符串的地址。
之前定义字符串的方式是:
char name[] = "itcast";
有了指针后,可以:
char *name = "itcast";
区别:
字符数组方式:
* 特点:字符串里面的字符是可以修改的
* 使用场合:字符串的内容需要经常修改
指针方式:
* 特点:字符串其实是一个常量字符串,里面的字符是不能修改
* 使用场合:字符串的内容不需要修改,而且这个字符串经常使用
2、指针字符串的使用
在输入的字符串中查找有无‘k’字符
void main()
{
char st[20],*ps;
int i;
printf("input a string:\n");
ps=st;
scanf("%s",ps);
for(i=0;ps[i]!='\0';i++)
if(ps[i]=='k')
{
printf("there is a 'k' in the string\n");
break;
}
if(ps[i]=='\0') printf("There is no 'k' in the string\n");
}
七、清空指针
假设p是任意的指针。清空指针的值方式如下:
p = 0;
p = NULL;
八、为什么int类型的指针只能指向int类型的变量
先看下面的程序:
int i = 2;
char c = 1;
// int类型的指针指向char类型的变量
intint *p = &c;
printf("%d", *p);
输出结果:
513
内存分析:
由于p是int类型的指针,指向的地址是 ffc1,于是就从 ffc1 取出四个字节的内容来:0000 0000 0000 0000 0000 0010 0000 0001,换算成十进制就是513,这就是int类型的指针为什么不能指向char类型的变量的原因。
总结:同种类型的指针只能指向同种类型的变量
九、函数和指针
1、返回指针的函数
数据类型 *函数名(参数列表)
{
// ...
}
如:
char char *pChar()
{
return "hello";
}
2.指向函数的指针
定义的一般形式:函数的返回值类型 (*指针变量名)(形参1, 形参2, ...);
注意:由于这类指针变量存储的是一个函数的入口地址,所以对它们作加减运算(比如p++)是无意义的
指向函数的指针变量主要有两个用途:
· 调用函数
· 将函数作为参数在函数间传递
void test()
{
printf("调用了test函数\n");
}
int sum(int a, int b)
{
return a + b;
}
int main()
{
int (*p)(int, int); // 定义
p = sum; // 初始化
int c = p(10, 11); // 调用函数,相当于sum(10, 11);
printf("c is %d\n", c);
void (*p2)() = test; // 定义的同时初始化
p2(); // 调用函数
return 0;
}