C语言-指针

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


算数优先级

请添加图片描述

内存映像图

在这里插入图片描述

指针

指针常用的有:指针常量和常量指针,指针数组,数组指针,指针函数,函数指针 ,结构指针和联合指针,枚举指针

空指针 VS 野指针

空指针
NULL,定义在stdlib.h中定义,相当于0;地址为0,

int* p = NULL;
*P = 100;	//违法

野指针
表示没有赋值的指针,其指针存放的地址为随机值,垃圾内容,会出现段错误:访问了不能访问的内存(可能是不一定存在的内存或系统保护的内存),

合法的使用内存(堆内存)

  1. 使用系统分配的内存 如:int a; int* p = &a;
  2. 申请内存
    申请内存使用malloc函数 定义在stdlib.h
    使用方法:void* malloc(需要的字节数)
    比如:
    char* str = (char*)malloc(32); 申请32字节空间,str指向了一块32字节的空间地址
    使用后 free(str);释放内存 并str=NULL避免出现野指针

指针运算

int a;
int* p = &a;

表示把指针变量p存放a的地址

	int x = 5, y = 0;
	int* p = &x;
	//下面三条 不是同时运行 
	y = *p + 5; //输出10 
	y = ++ *p;	//输出 6
	y = *p++;	//违法 p为野指针 

y = *p + 5; 等价于 y = (*p)+ 5; 等价于 y = x + 5;
y = ++ *p; 等价于 y = ++ (*p); 等价于 y = ++ x;
y = *p++; 等价于 y = *(p++); 等价于没有赋值的指针
*p++ 等价于 *(p++); 指针加一后解引用
(*p)++等价于 (*p)++; 先解引用后指针加一

常量指针 VS 指针常量

const 修饰指针

常量指针

const int* p=&a; //常量指针
(*p)++	//违法 	等价于 a++
p++		//可以	等价于p=&b	

const 修饰 *p ,指针p指向的值(即a的值)不可以修改,指针p的指向(即指向的地址)可以修改

指针指向可以修改,指向的值不能修改
即 p=&b可以,*p=20不可以

指针常量

int* const p=&a; //指针常量
(*p)++	//可以 	等价于 a++
p++		//违法	等价于p=&b

const 修饰 p ,指针p的指向(即指向的地址)不可以修改,指针p指向的值(即a的值)可以修改

指针指向不可以修改,指向的值可以修改
即 p=&b不可以,*p=20可以

另外一种

const int* const p=&a; 
(*p)++	//违法 
p++		//违法	

指针的指向和指针指向的数据都不能修改

指针和数组

指针和数组在使用上基本没区别
	int a[5] = { 1,2,3,4,5 };
	int* p = a;
	a[i]等价于* (p + i)
	a[i]等价于* (a + i)

	char* str = "hello";
	*str 等价于 str[0] 等于h
	/*******************************/
	需要注意的时
	char str[5] = "hello";	初始化数组内容
	char* p = "hello";		字符串常量(有实际的地址)

	str[0] = 'x';	可以 str存在栈空间 可读可改
	p[0] = 'x';		违法  char* p = "hello";为字符串常量,存放在只读数据区
char* p = "hello";		字符串常量(有实际的地址)
指针p指向了字符串常量hello

指针数组 VS 数组指针

指针数组
存放同类型指针的数组,本质是数组

类型 *数组名[数组长度]
char* arr[4] = {"hello", "world", "shannxi", "xian"};
arr为数组,有四个字符串常量元素,arr[0]中存放这hello的地址
相当于char *p = “hello”,char *p1 = “world”,char *p3 = “shannxi”, char *p4 = “xian”四个指针,
每个指针存放着一个字符串的首地址,arr[4]这个数组分别存放这四个指针,就形成了指针数组

数组指针
数组指针本质为一个指针 ,这个指针指向数组

类型 (*指针名)[数组长度]
int(*p)[5] ; //p为一个指针,指向一个数组,该数组有5个int类型的元素
p为一个指针,指向数组,数组有四个int类型元素占4*5=20个字节,所以p++,应该是加20个字节
	int a[5] = {1, 2, 3, 4, 5};
	int (*p)[5] = &a;		//数组指针p指向整个数组的首地址

	for(int i = 0; i < 5; i++)
	{
		printf("%d ", *(*p + i));
		//printf("%d\n", (*p)[i]);

int (*p)[5] = &a; 这里a数组第一个元素的地址,而&a是整个数组的首地址(二维数组尤为重要)
*(*p + i)中p指向数组a的地址,*p+i 是第i个元素的地址, *(*p + i) 表示第i个元素的值

二维数组

int a[3][5] 是一个三行五列的二维数组 ,其中
a[0]表示首行首元素地址 4字节
a表示数组首行地址 4×5=20字节
&a表示数组的地址 3×(4×5)=60字节
不理解可以参考下面代码

	int a[3][4] = { {1,2,3,4},{2,3,4,5},{4,5,6,7} };
	int* p = NULL;
	int(*q)[4] = a;		//数组指针指向第一行

	printf("a[0]   %p\n", a[0]);	//首行首元素地址
	printf("a      %p\n", a);		//首行地址
	printf("a[1][] %p\n", ++q);		//第二行地址
	printf("&a     %p\n", &a);		//整个数组地址

在这里插入图片描述
a[0]表示首行首元素地址,当a[0]加一时地址为首行元素的第二个地址
a表示数组首行地址 ,当a加一时为第二行的地址
&a表示数组的地址 ,当&a加一时地址为加整个数组元素的字节数
q为数组指针,q加一相当于指向了第二行 用3E8减3D8为十六进制的10正好是十进制的16

指针函数 VS 函数指针

指针函数  int* p() 	函数指针 int(*p)()
区别:
		指针函数中p是函数,返回的是int* 整形指针
		函数指针中p是指针,指向的是一个函数地址,返回值是int

指针函数 本质是一个函数,返回值是一个指针。通俗讲:返回值是指针的函数
注意:不能返回局部变量的地址! 函数运行结束局部变量会被释放

char* func(args, ...);
	char* init()		//指针函数
	{
		char* str = (char*)maslloc(128);	//申请128字节的内存
		return str;
	}
	char* s = init();	
	strcpy(s,"hello");	
	free(s);			//释放内存


int* max(int* p1, int* p2)	
{
	if (*p1 > *p2)
		return p1;
	else
		return p2;
}
int main(int argc, char* argv[])
{
	int* p, a, b;
	a = 1; b = 2;
	p = max(&a, &b);
	printf("%d\n", *p);
	return 0;
}

函数指针 本质是一个指针,指向了一个函数,是指向函数的指针

void(*p)(args, ...);	//函数指针

例如:
	void func(){}; 	定义一个无参无返回值的函数
	void (*p)();	定义一个无参无返回值的函数指针
	p = func;		p指针指向函数func的地址
	p(); 			等价于func();

	int add(int x,int y){};		定义一个返回int和形参为int的函数
	int	(*p)(int,int) = add; 	定义一个返回int和形参为int的函数指针并指向add函数的地址
	p(1,2);						等价于add(1,2);
	
	可以使用typedef 简化代码,比如:
	typedef int (*T)(int,int);
	T p = add; 		等价于int(*p)(int,int) = add;

回调函数
回调函数中常用函数指针
回调函数:把函数名作为另一个函数的参数,从而达到修改函数的功能

//函数功能:实现累加求和
int func_sum(int num)
{
        return sum;
}

//这个函数是回调函数,其中第二个参数为一个函数指针,通过该函数指针来调用求和函数,并把结果返回给主调函数
int callback(int num, int (*p)(int))
{
        return p(num);
}

int main(void)
{
        int num = 0;
        printf("please input number:");
        scanf("%d", &num);
        printf("the sum from 0 to %d is %d\n", num, callback(num, func_sum));       //此处直接调用回调函数,而不是直接调func_sum函数
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值