目录
一.指针基础知识
1.1何为 内存/地址/指针?
内存和地址可以用一个形象的例子理解:
生活中,我们想要去一个陌生小区找一个朋友,朋友会告诉我们他住在几栋几单元几号。我们可以直接通过朋友告诉的门牌编号找到他,非常方便。否则我们只有一间一间的去询问,效率非常的低下。
而在计算机中,内存就是这一个一个的房间,地址就是门牌编号,在C语言中它也有一个新名字“指针”,通过地址(指针)的信息,我们就可以很方便的找到我么们需要寻找的内存,进而得到想要的信息啦!
总结一下,我们可以这样的简单理解:门牌编号==地址==指针
1.2指针的使用
1.2.1定义指针变量
这里举出两个例子:
int* p //整形指针变量,指针类型为int*,指针指向int
char* p //字符指针变量,指针类型为char*,指针指向char
int* p :整形指针变量,指针类型为int*,指针指向int
char* p :字符指针变量,指针类型为char*,指针指向char
总结:指向类型* 变量名
1.2.2初始化指针变量
指针变量在定义时可以赋值,即初始化。可以赋值为“NULL”或“0”。
int *p1= NULL, *p2 = 0;
1.2.3 两个指针会用到的运算符:&和*
取地址运算符&:单目运算符&可以用来取操作对象的地址。
#include <stdio.h>
int main(){
int a = 10;
&a;//取出a的地址
printf("%p\n", &a);
return 0;
}
代码结果:就可以打印出a的地址啦。
指针运算符*:* 则可以通过地址,获取内存中的内容。(地址是不能直接使用的!)
#include <stdio.h>
int main()
{
int a = 100;
int* pa = &a;
*pa = 0;
return 0;
}
通过*pa就可以直接对a进行操作,这里把a的值改成了0
1.3指针变量的大小
直接上结论:
•
32位平台下地址是32个bit位,指针变量⼤⼩是4个字节
•
64位平台下地址是64个bit位,指针变量⼤⼩是8个字节
•
注意指针变量的⼤⼩和类型是⽆关的,只要指针类型的变量,在相同的平台下,⼤⼩都是相同的。
1.4指针与整数的运算
指针+ 1 或减-1 运算,表示指针向前或向后移动一个单元(不同类型的指针,单元长度不同)。
eg.char*
类型的指针变量+1跳过1个字节
int*
类型的指针变量+1跳过了4个字节。
结论:指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)。
二、多级指针
指针变量也是变量,是变量就有地址
我们通过二级指针来了解:
#include <stdio.h>
int main()
{
int a=10;
int*pa=&a;
int ** ppa=&pa;
return 0;
}
ppa:指向指针变量的指针,指针变量pa的地址。
三.数组和指针
3.1. 数组名的理解
这⾥我们使⽤
&arr[0]
的⽅式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址,⽽且
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("&arr[0] = %p\n", &arr[0]);
printf("arr = %p\n", arr);
return 0;
}
输出结果: 地址打印出的结果⼀模⼀样
结论:数组名就是数组⾸元素(第⼀个元素)的地址。
两个例外:
•
sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节
•
&数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素 的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
3.2使用指针访问数组
我们可以使⽤arr[i]可以访问数组的元素,那p[i]是否也可 以访问数组呢?
#include <stdio.h>
int main()
{
int arr[10] = {0};
//输⼊
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
//输⼊
int* p = arr;
for(i=0; i<sz; i++)
{
scanf("%d", p+i);
//scanf("%d", arr+i);//也可以这样写
}
//输出
for(i=0; i<sz; i++)
{
printf("%d ", p[i]);
}
return 0;
}
两种不同写法的输出的结果是一致的。
结论:本质上p[i] 是等价于 *(p+i)。
3.3指针数组&数组指针
3.3.1指针数组
本质是数组,数组中存储的内容是指针变量。
3.3.2 数组指针
本质是指针,指针指向的内容是数组。
int (*p)[10];
解释:p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。所以 p是⼀个指针,指向⼀个数组,叫 数组指针。
这⾥要注意:[]的优先级要⾼于*号的,所以必须加上()来保证p先和*结合。
数组指针变量初始化
int (*p)[10]=&arr;
四、字符指针
字符指针类型
char*
;
int main()
{
const char* pstr = "hello";//这⾥不是把⼀个字符串放到pstr指针变量⾥,而是字符数组首地址
printf("%s\n", pstr);
return 0;
}
代码
const char* pstr = "hello";
本质是把字符串”
hello“
⾸字符的地址放到了pstr中。
可以把定义的指针看做是字符数组的数组名,字符串的实质是字符数组。
五、函数指针
5.1 函数指针变量的创建
函数指针变量应该是⽤来存放函数地址的,未来通过地址能够调⽤函数的。
那么函数是否有地址呢?
#include <stdio.h>
void test()
{
printf("hehe\n");
}
int main()
{
printf("test: %p\n", test);
printf("&test: %p\n", &test);
return 0;
}
输出结果如下:
test:
005913
CA
&test:
005913
C
结论:函数是有地址的,函数名就是函数的地址,也可以通过
&
函数名的⽅
式获得函数的地址。
创建函数指针变量例子
void test()
{
printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)()= test;
int Add(int x, int y)
{
return x+y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的
![](https://i-blog.csdnimg.cn/blog_migrate/62beb2872ea57dd56193c5e699636023.png)
int( * )(int,int)就是该函数指针的类型。
5.2 函数指针变量的使⽤
#include <stdio.h>
int Add(int x, int y)
{
return x+y;
}
int main()
{
int(*pf3)(int, int) = Add;
printf("%d\n", (*pf3)(2, 3));
printf("%d\n", pf3(3, 5));
return 0;
}
输出结果:
5
8
5.3函数指针数组
把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组
int (*parr1[3])();
该数组的内容就是:int (* )()类型的函数
六、void*指针
void* 指针是一种特殊类型的指针
,可以理解为⽆具体类型的指针
特点:这种类型的指针可以⽤来接受任意类型地址。
局限性:
void*
类型的指针不能直接进 ⾏指针的+-整数和解引⽤的运算。
使⽤void*类型的指针接收地址:
#include <stdio.h>
int main()
{
int a = 10;
void* pa = &a;
void* pc = &a;
*pa = 10;
*pc = 0;
return 0;
}
用处:
⼀般
void*
类型的指针是使⽤在函数参数的部分,⽤来接收不同类型数据的地址,这样的设计可以
实现泛型编程的效果。使得⼀个函数来处理多种类型的数据。