C语言 指针重点 数组与指针 相关内容总结

一.基础知识

  • 指针是指内存地址-内存单元的编号,大小一般是为1个字长;
  • 指针变量是指存储内存地址的变量;
  • 指针类型不决定指针变量占几个字节;但它能决定指针在被解引用时访问多少字节;

eg:int* 解引用访问4byte,char*解引用访问1byte;

  • 指针的类型决定了对指针+-1操作时,增加的地址大小,即变化步长

易混点:int*与float*解引用都访问4字节,步长也是4字节,但不相互通用,因为不同数据类型,相同的真值对应不同的机器码,存储在计算机内2进制表示不同;相同的机器码解释方式不同得到的真值也不一样;

  • void*无具体类型,可以指向任意类型,因而不可直接解引用和加减操作(可先强制类型转换后解引用);

指针类型实际运用:某厂面试题:通过代码验证当前机器整型数在内存中存储是大端还是小端?

补充概念:大端-数据二进制位高有效字节存储在内存低地址;

                  小端-数据二进制位低有效字节存储在内存低地址;

int a=1;
//真值为1的机器数为0x00000001(16进制)
//内存中开辟4byte存储a
//&a表示a存储首地址
//思路:若为大端模式,则该地址首字节存储为0x00;若为小端模式,该地址首字节存储为0x01
//利用指针类型转换获取4个字节中首字节中内容-char*型

char* p=(char*)&a;
//则对p的解引用获得的即是首字节存储的数值

if(*p==1){//存储的0x01,即为小端}
if(*p==0){//存储的0x00,即为大端}

*也可以使用联合体判断机器大小端 

  • 野指针:指针指向的位置不可知(与void*区分,void*是指向类型不可知)
  • 1.指针定义未初始化,放随机值->解决:int* p=NULL,约定0地址(NULL)不可访问 ,使用前增加不为0地址判断条件,检查其有效性
  • 2.指针越界访问(指向数组时易出现)
  • 3.指针指向的内存空间释放-eg:返回局部变量的地址给指针,离开局部变量作用域,局部变量被释放)

指针运算:

  • 指针加减数-可实现strlen的逻辑
  • 指针与指针相减(指向同一块空间的两个指针才能相减-同一个数组)
  • 相减的绝对值是指针之间元素的个数
  • 指针关系运算:标准允许指向数组的指针与数组之后的地址进行比较,不能与数组之前的地址相比较

二级指针变量:**p存放(一级)指针变量的地址 

  • eg:int * p  其中*表示p是一个指针变量,指向的变量类型是int
  • int * * p 其中第二个*表示p是一个指针变量,指向的变量类型是int*

const修饰指针:

  • const int* p 表示p所指向的对象无法通过解引用指针变量p对其进行修改,即限定无法为*p赋值;
  • int* const p 表示p本身的内容即地址不能修改,即其指向的对象固定,但可以通过*p修改其对象的值;
  • 同时限制:const int* const p;

二.指针与数组交叉内容

  • 指针数组:存放指针(地址)的数组,区别于指向数组首元素的指针以及数组指针
  • 指针数组- int* p[10];//p先与[]运算符结合,本质是数组,存储10个int型指针
  • 数组指针- int (*p)[10];//括号使得p与*结合,本质是指针,指向10个int型元素数组

数组与指针关系密切,这里对指针和数组的交叉内容做一些补充解释:

int arr[10]={0};
//含10个元素的数组

//需要区别常用的指向数组的指针与数组指针的概念

//指向数组首元素的指针
int* p=arr;

//数组指针
int (*p)[10]=&arr;

搞明白二者的区别,需要明白数组名这一存在变化的概念:

#include <stdio.h>

int main() {
	int arr[10] = { 0 };
	int* p = arr;
	//数组名通常情况下指代的是数组首元素的地址,而非数组的地址
	//验证arr是首元素地址
	printf("%p\n", arr);
	printf("%p\n", p);
	printf("%p\n", &arr[0]);

	//验证arr非数组的地址
	//从指针运算的角度理解何为数组地址:前文提到p+1的步长为其指向数据类型的大小(单位:字节)
	//arr+1的地址增加步长仅为4字节(int型大小),并非40字节(元素个数*int型)
	//说明arr在这里代表的仅是数组首元素地址
	// 也可以说明这里的p仅是指向数组首元素的指针
	printf("%p\n", arr+1);
	printf("%p\n", p+1);
	printf("%p\n", &arr[1]);

	//特殊情况:sizeof()运算符中,单独只有arr数组名时,arr代表整个数组本身,返回结果为整个数组字节大小,而非首元素字节大小,也非数组地址
	printf("%u\n", sizeof(arr));

	//表示数组地址:&arr
	//对应数组指针-存放数组地址
	int(*p1)[10] = &arr;//p1的类型即数组指针
	//验证
	printf("%p\n", p1);
	printf("%p\n", &arr);
	printf("%p\n", p1+1);
	printf("%p\n", &arr+1);

	return 0;

}

数组指针的运用:多有关于多维数组(二维)

从上面可知int(*p)[10]=&arr;则解引用*p=*(&arr)即arr,表示数组名;

在二维数组中规定:二维数组名表示首行数组的地址-即一个一维数组的地址,需用数组指针存储

int arr1[2][3]={0};
//可看作2个含三个元素的一维数组

int (*p)[3]=arr1;

三.函数与指针

函数指针:

定义声明的函数也会放入内存中,所以函数也存在其地址

int add(int x , int y){

return x+y;

}//add,&add都可以表示函数地址

int main(){
int (*p)(int,int)=&add;
int x=1,y=2;
//通过指针调用函数
int num=(*p)(1,2);

}

由此可知函数指针也是一种类型

例子解读:

( * ( void (*) () ) 0 ) ()

//由内向外观察
1.void (*) ()-是函数指针类型,对应函数类型无形参,无返回值
2.(类型)-表示强制类型转换
3.将0转换函数指针类型,即将0视作一个(函数)地址
3.解引用表示调用该地址表示的函数,空括号表示不传参数

上例可用于表示调用0内存地址的函数;

void ( * function ( int ,void (*) (int) ) ) (int);

1.void (*) (int)表明是函数指针类型
2.与逗号相连,则function ( int ,void (*) (int) )是函数声明
3.外套的void (*) (int)表面函数返回值也为函数指针类型

函数指针典型运用:回调函数-通过函数指针调用的函数(函数指针作为参数)

例子:C提供的库函数qsort();

推广:函数指针数组-指向函数指针数组的指针

int (*p)(int);//函数指针
int (*arr[5])(int);//函数指针数组
int (*(*pp)[5])(int);//指向函数指针数组的指针

若存在错误,敬请指正!

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值