目录
认识指针
在C语言中,指针是一种变量,其值为另一个变量的地址。简单来说 指针也就是内存地址,指针变量是用来存放内存地址的变量,您必须在使用指针存储其他变量地址之前,对其进行声明。
指针变量的声明
要声明一个指针变量,需要在变量名前加上星号(*)表示指针。
例,int *p;
声明了一个名为 p
的整数指针。
指针定义的格式
<存储类型> <变量类型> *变量名;
int *p; /* 一个整型的指针 */
例:
double *p; /* 一个 double 型的指针 */
float *p; /* 一个浮点型的指针 */
char *p; /* 一个字符型的指针 */
指针使用的符号
*:
取地址中的值
&:
对某个变量取地址
实例:使用指针输出变量的地址;
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 10;//定义一个整形变量a,初始化为10;
int *p; //定义一个整形指针p,
p = &a;//将p指向变量a的地址
printf("%p\n",p);//打印p指向变量a的地址;
printf("%d\n",*p);//打印p指向变量a的值;
return 0;
}
输出的结果为
0x7ffdc90be07c //a存放的地址
10 //a的值
野指针
指的是一个指针变量指向了一个它不应该访问的内存位置,或者该内存位置已经被释放,但指针仍然保留着原来的地址。野指针可能会导致程序崩溃。所以在使用指针时应避免野指针的出现;
以下是导致野指针的常见情况:
内存释放后继续使用:当使用
malloc
(或其他动态内存分配函数)分配的内存被free
释放后,如果指针没有立即设置为NULL
,它将变成一个野指针。局部变量的地址被返回:如果一个函数返回一个局部变量的地址,并且调用者试图通过这个地址访问该变量,那么它将成为野指针,因为局部变量在函数返回后会被销毁。
数组越界:当访问数组元素时超出了数组的边界,可能会得到一个指向无效内存的指针,这也可能导致野指针的情况。
指针未初始化:如果一个指针变量在使用前没有被初始化,它将包含一个随机的内存地址。
如何避免野指针
初始化指针:在声明指针变量时,最好立即将其初始化为
NULL
,以防止在分配内存之前意外使用它。设置指针为
NULL
:在释放内存后,立即将指针设置为NULL
。。避免返回局部变量的地址:确保不要从函数中返回局部变量的地址,除非这个地址指向的是动态分配的内存或全局/静态变量。
检查数组边界:在访问数组元素之前,始终检查索引是否在有效范围内。
指针占用内存大小的问题
在32位系统上:所有的指针都是占用4字节
在64位系统上:所有的指针都是占用8字节
指针加1移动大小问题
指针加1移动的大小是它指向类型的大小。如
char *p;
p+1移动1个字节
int *q;
q+1移动4个字节
二级指针
在C语言中,二级指针(也称为指向指针的指针)是一个指针变量,它存储了另一个指针变量的地址。换句话说,它是一个指针,其指向的目标是另一个指针。
二级指针的定义格式
<存储类型> <变量类型> **变量名;
例:
int **p;
char **q;
说明:二级指针是指向一级指针地址的指针,
c语言中二级指针的作用;
- 当你需要改变一个指针的值时,必须使用二级指针。
- 当你需要修改一个值时,可以通过传递指针来达到目的。
- 当你需要修改一个指针时,需要使用指针的指针(二级指针)。
- 二级指针作为函数参数的作用是在函数外部定义一个指针p,在函数内给指针赋值,函数结束后对指针p生效。
二级指针代码
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 10;//定义一个整形变量a;
int *p = &a; //定义一个指针p指向a的地址;
int **q = &p; //定义一个二级指针q,指向p的地址
printf("a=%d,*p=%d,**q=%d\n",a,*p,**q);//打印未更改的值;
printf("&a = %p,p = %p,&p = %p,q = %p,&q = %p\n", &a, p, &p, q, &q);//打印未更改的地址
**q = 20;//这里将二级指针指向的值更改为20;
printf("a=%d,*p=%d,**q=%d\n",a,*p,**q);//打印更改后的值;
printf("&a = %p,p = %p,&p = %p,q = %p,&q = %p\n", &a, p, &p, q, &q);//打印更改后的地址
return 0;
}
运行结果
指针数组
指针数组:
指针数组:指针数组就是数组,数组内部的每个成员都是指针。
指针数组存储了一组指针,每个指针可以指向不同的数据对象。
指针数组的定义格式
char *a[3];
int *b[3];
指针数组与变量之间的关系
实例:
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a=10,b=20,c=30;//定义3个整型变量;
int *ptr[3]={&a,&b,&c};//定义一个数组指针并赋初始值为a,b,c的值;
for(int i=0;i<3;i++){
printf("%d\n",*ptr[i]);
}
return 0;
}
运行结果
10 20 30
指针与一维数组
当定义一个一维数组时,系统会在内存中为改数组分配一个储存空间,其数组的变量名就是数组的首地址。若定义一个指针变量,并将数组的首地址赋值给指针变量,则我们说该指针指向了这个一维数组。
把 ptr 声明为一个数组,由 3个整数指针组成。ptr 中的每个元素,都是一个指向 int 值的指针。下面的实例用到了三个整数,它们将存储在一个指针数组中,如下所示:
#include <stdio.h>
int main(int argc, const char *argv[])
{
int arr[3]={10,20,30};//定义一个整形数组;
int *ptr[3];//定义一个指针数组;
for(int i=0;i<3;i++){
ptr[i] = &arr[i];
}
for(int i=0;i<3;i++){
printf("arr[%d]=%d\n",i,*ptr[i]);
}
return 0;
}
运行结果
arr[0]=10 arr[1]=20 arr[2]=30
数组指针
数组指针的含义
它是一个指针,指向数组;本质是指针
数组指针的定义格式
<存储类型> <变量类型> (*变量名)[成员个数];
例:
char (*a)[3];
//指向一个数组,数组有3个元素,每个元素是一个char型;
int (*b)[3];
//指向一个数组,数组有3个元素,每个元素是一个int型整数;
long (*c)[3];
//指向一个数组,数组有3个元素,每个元素是一个long型;
数组指针占用内存大小及加1问题
所有的数组指针在64位系统上都是占8字节;
指针加1移动的大小是它指向类型的大小;
char (*a)[3];
//它的类型是char (*)[3]
,这个指针加1移动的大小是3*sizeof(char)
int (*b)[3];
//它的类型是int (*)[3]
,这个指针加1移动的大小是3*sizeof(int)
代码实例
#include <stdio.h>
int main(int argc, const char *argv[])
{
int arr[5]={1,2,3,4,5};//定义一个整型数组arr
int *ptr = arr;//定义一个指针指向数组;
printf("ptr=%ld arr=%p\n",sizeof(ptr),arr);//打印ptr所占内存大小和arr的首地址;
for(int i=0;i<5;i++){
printf("arr[%d] ptr=%p\n",*ptr,ptr);//打印次数,以及数组指针加1的地址;
ptr = ptr+1;//数组指针加1;
}
return 0;
}
运算结果
ptr=8 arr=0x7ffc97b25620
arr[1] ptr=0x7ffc97b25620
arr[2] ptr=0x7ffc97b25624
arr[3] ptr=0x7ffc97b25628
arr[4] ptr=0x7ffc97b2562c
arr[5] ptr=0x7ffc97b25630
指针函数和函数指针
指针函数
指针函数实质是一个函数。
函数都有返回类型,函数的返回值类型是指针的函数就是指针函数
。
指针函数定义格式:类型名 *函数名(函数参数列表);
char *a(char *dest,const char *src)
int *func(void)
指针函数使用实例
#include <stdio.h>
int *p(){ //定义一个指针函数;
static int arr[5]={11,22,33,44,55};
return arr;
}
int main(int argc, const char *argv[])
{
int *ptr=p();//调用指针函数获取数组地址;
for(int i=0;i<5;i++){
printf("%3d",ptr[i]);//循环打印数组中的元素;
}
printf("\n");
return 0;
}
运行结果
11 22 33 44 55
函数指针
函数指针是指向函数的指针变量。
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针定义格式:类型名 (*函数名)(函数参数列表)
int (*pfun)(int, int);
函数指针使用实例
#include <stdio.h>
int add(int a,int b){
return (a+b);
}
int subtract(int a,int b){
return (a-b);
}
int main(int argc, const char *argv[])
{
int (*fp)(int,int);//声明一个函数指针变量;
fp = add;//将fp指向add函数
printf("%d+%d=%d\n",2,3,fp(2,3));//使用函数指针调用add函数;
fp = subtract;
printf("%d-%d=%d\n",5,3,fp(5,3));//使用函数指针调用subtract函数;
return 0;
}
运行结果
2+3=5
5-3=2
总结:
- 函数指针:是一个指针变量,其值为函数的地址,可以通过它来间接调用函数。
- 指针函数:是一个函数,其返回值为指针(通常是地址),这个指针可以指向任何数据类型(数组、结构体、基本数据类型等)。
- 函数指针主要用于实现回调函数、函数表等高级编程技巧。
- 指针函数主要用于返回地址或引用,例如返回数组或动态分配的内存地址。
函数指针数组
它是一个数组,数组中的成员是函数指针。
函数指针数组的定义格式
<存储类型> <返回值类型> (*数组名[成员个数])(参数列表);
例
int (*a[2])(int ,int );
函数指针数组实例
#include <stdio.h>
int add(int a,int b){
return (a+b);
}
int subtract(int a,int b){
return (a-b);
}
int main(int argc, const char *argv[])
{ int (*fa[2])(int ,int );//定义函数指针数组fa;
fa[0] = add;//将fa第1个元素指向函数add;
fa[1] = subtract;//将fa第2个元素指向函数subtract;
for(int i=0;i<2;i++){
printf("%d\n",fa[i](30,10));
}
return 0;
}
运行结果
40
20
在C语言中,函数指针数组是一种特殊类型的数组,其元素是指向函数的指针。函数指针数组允许你存储多个函数的地址,并在运行时根据需要使用这些函数。以下是函数指针数组的一些作用:
-
实现多态性:
通过函数指针数组,你可以根据不同的条件调用不同的函数,实现类似多态的行为。 -
实现回调函数机制:
函数指针数组可以作为回调函数机制的一部分。 -
简化代码结构:
使用函数指针数组可以将多个功能相似的函数组织在一起,通过数组索引来调用它们,从而简化代码结构,提高代码的可读性和可维护性。 -
实现函数表:
函数指针数组可以看作是一种函数表,其中每个元素都指向一个具有相同签名的函数。通过遍历这个数组,你可以调用不同的函数来执行不同的任务。 -
动态函数选择:
在某些情况下,你可能需要根据运行时的条件动态地选择调用哪个函数。 -
代码扩展性:
使用函数指针数组可以方便地向系统中添加新的函数,只需要将新函数的地址添加到数组中即可,而无需修改其他部分的代码。
本节完!
下一节主要为c语言部分的知识点以及C语言总结,下一节会总结c语言中的每个知识点,以及前四节未写的部分!http://t.csdnimg.cn/wncMJ
有问题或者错误反馈请联系邮箱:z1600306511@163.com