指针进阶(1)

指针的概念:

1.指针就是变量,用来存放地址,地址唯一标识一块内存空间

2.指针得大小是固定的4/8个字节(32位平台/64位平台)

3.指针是有类型,指针得类型决定了指针+-整数得步长,指针解引用操作的时候的权限

4.指针的运算

1.字符指针

 但是这么写有一些不安全,调试能看到错误

修改

 此时const修饰指针*p,限制了*p,此时*p不能更改,有效的保护了字符串

面试题:

#include<stdio.h>
int main()
{
	char str1[] = "hello bit";
	char str2[] = "hello bit";
	const char* str3 = "hello bit";
	const char* str4 = "hello bit";
	
	if (str1 == str2)
		printf("str1 and str2 are the same\n");
	else
		printf("str1 and str2 are not the same\n");

	if (str3 == str4)
		printf("str3 and str4 are the same\n");
	else
		printf("str3 and atr4 are not the same\n");

	return 0;
}

 str3和str4相等意味着指向同一块空间的,hello bit是一个常量字符串,只要有一块空间存放即可,所以str3和str4是指向同一块空间的

str1和str2是两个独立的数组,数组名是首元素的地址,所以起始地址是不相同的

2.指针数组

指针数组是一个存放指针的数组

 int* arr1[ 10 ] ;//整形指针的数组

char* arr2[ 4 ] ;//一级字符指针的数组

char **arr[ 5 ] ;//二级字符指针的数组

 3.数组指针

3.1指针数组的定义

数组指针是指针

整形指针:int* p;能够指向整型数据的指针

浮点型指针:float* p;能够指向浮点型数组的指针

所以数组指针是能够指向数组的指针

int* p1[ 10 ];//指针数组

int (*p2)[ 10 ];//数组指针,p2可以指向一个数组,该数组有10个元素,每个元素是整型类型

解释:

int (*p)[ 10 ];

//p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针

//这里要注意:[ ]的优先级要高于*号的,所以必须加上()来保证p先和*结合

3.2&数组名VS数组名

数组名是数组首元素的地址

 这里就不能认为数组名就是数组首元素的地址

数组名通常都是数组首元素的地址,但是有两个例外

1.sizeof(数组名),sizeof内部单独放一个数组名的时候,这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节

2.&数组名,这里的数组名表示的依然是整个数组,所以&数组名取的是整个数组的地址

 

 数组指针的应用

int (*p)[ 5 ];

p的类型是:int (*)[ 5 ];

p是指向一个整型数组的,数组5个元素 int [ 5 ]

p+1 ——>跳过一个5个int 元素的数组

int arr[ 10 ];

int (*p)[ 10 ]=&arr;

&arr+1-->40(跳过40个字节)

int arr[ 5 ];                arr是整型数组

int *parr1[ 10 ];        parr1是整型指针数组

int (*parr2)[ 10 ];      parr2是数组指针

int (*parr3[ 10 ])[ 5 ];parr3应该是存放数组指针的数组

4.数组参数、指针参数

4.1一维数组传参

 4.2二维数组传参

 总结:

二维数组传参,函数形参的设计只能省略第一个[ ]的数字

因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素

这样才方便运算

4.3一级指针传参

 如果是函数的参数部分是指针

void print(int* p)

{}

int a=10;

int* ptr = &a;

int arr[ 10 ];

print (&a);

print(ptr);

print(arr);

4.4二级指针传参

 如果函数的形式参数是二级指针,调用函数的时候可以传什么实参呢?

test(int** p)

{}

int *p1;

int **p2;

int* arr[10];//指针数组

test(&p1);

test(p2);

test(arr);

5.函数指针

函数指针与数组指针类比

数组指针:指向数组的指针就是数组指针

函数指针:指向函数的指针就是函数指针

对于函数来说,&函数名和函数名都是函数的地址

存函数的地址:

 

阅读两端有趣的代码

//代码1

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

void(*p)(); p是函数指针

void(*)() 函数指针类型

以上代码是一次函数调用,调用的是0作为地址处的函数

1.把0强制类型转换为无参,返回类型是void的函数的地址

2.调用0地址处的这个函数

//代码2

void (*signal(int,void(*)(int)))(int);

signal是函数名,以上代码是一次函数声明

声明的signal函数的第一个参数的类型是int,第二参数的类型是函数指针,该函数指针指向的函数参数是int,返回类型是void,signal函数的返回类型也是一个函数指针,该函数指针指向的函数参数是int,返回类型是void

代码2太复杂,如何简化:

 函数指针的用途

6.函数指针数组

数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组

比如:

int *arr[10];

//数组的每个元素是int*

函数指针也是指针

把函数指针放在数组中,其实就是函数指针的数组

7.指向函数指针数组的指针

指向函数指针数组的指针是一个指针

指针指向一个数组,数组的元素都是函数指针

8.回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应

 冒泡排序的优化:

qsort函数的使用:

qsort - 这个函数可以排序任意类型的数据

 使用快速排序的思想实现的一个排序函数

_cdecl - 函数调用规定

void* base - 要排序的数据的起始位置

size_t num - 待排序的数据元素的个数

size_t width - 待排序的数据元素的大小(单位是字节)

int(*compare)(const void *elem1,const void *elem2) - 函数指针 - 比较函数,elem1和elem2是两个要比较元素的地址

void* 是无具体类型的指针,可以接受任意类型的地址,void*是无具体类型的指针,也不能+-整数

升序

 降序

 

 将冒泡排序的函数写成qsort形式

9.指针和数组笔试题解析

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值