指针2
1、指针数组
是一个数组,里面存放了同类型指针
定义格式:指针类型 数组名[元素个数]
2、对比指针数组和二维数组存字符串
指针数组:
Char *names[5]={"lili","tom","haha","xiaoming","xiaobai"};
空间大小:20
访问形式:printf(“%s”,names[i]);
字符串存储位置:常量区
Char names[5][20] = {"lili","tom","haha","xiaoming","xiaobai"};
空间大小:100
访问形式:printf(“%s”,names[i]);
字符串存储位置:全局数据区或栈区
3、函数指针
是指针,指向对象是函数(指向对象的类型是函数类型),函数指针保存函数的地址
3.1、函数类型和函数地址
函数类型:除了函数名和{函数体}剩下的就是函数的类型
函数地址:函数名
函数的存放位置:代码区
3.2、定义函数指针
指向函数的返回值类型(*指针名)(形参列表)
3.3、使用场景
一般用于设计回调函数或者接口函数进行使用
回调函数或者接口函数:实质是将一个函数传递到另一个函数中进行调用(传递的是函数的地址,形参类型是函数指针)
4、拓展qsort排序函数
函数声明:
void qsort(void * base,size_t nmemb,size_t size ,int(*compar)(const void *,const void *));
返回值类型:void
函数名:qsort
形参列表:4个
Void *base : 要排序的数组首元素的地址
Size_t nmemb :数组中元素的个数
Size_t size :一个元素所占的字节数
Int(*compar)(const void *,const void *) :是函数指针,指向排序规则函数
函数指针指向的函数:
返回值类型:int
形参列表:2个都是const void *,接收每一次对比的数据地址
例:
int compare(const void *e1,const void *e2)
{
return *(int *)e1 - *(int *)e2; // 升序
}
int main()
{
int a[] = {4,-1,0,9,7,5,2,8,5};
int len = sizeof(a) / sizeof(a[0]);
qsort(a,len,sizeof(a[0]),compare);
int i;
for(i=0;i<len;i++)
{
printf("%d\n",a[i]);
}
}
5、指针函数
是一个函数,返回一个指针(地址)
指针函数返回的地址:外部空间的地址或者动态内存申请的地址,不可以是局部变量的地址
定义格式:
指针类型 函数名(形参列表)
{
函数体
return 地址
}
6、二级指针
指向指针的指针
指针是变量,有自己的空间就有自己的地址。
定义格式:指针类型 *指针名
一般二级指针用于改变一级指针的指向
例:
void test(int **q)
{
*q = malloc(100);
}
int main()
{
int *p = NULL;
test(&p); // 在test函数内部改变p指针的指向
printf("%p",p);
return 0;
}
7、NULL和void *
NULL是宏名,地址编号为0;
一般指针定义暂时不知道指向,或者指向指针指向被销毁的时候,要将指针指向NULL;
Void *是无类型的指针,这种类型的指针可以接收一个地址编号,一般需要强转;
8、const和指针
const是空间只读,对于只读的空间在定义的时候就要给值,否则后面不能进行写操作;
const可以修饰指针指向的空间,也可以修饰指针本身的空间;
const修饰指针时规律:
const在*的前面就是修饰指针指向的空间,指针指向的空间是只读,不能通过*指针名去操作它
const在*的后面是修饰指针本身的空间,指针空间是只读,指针不能改变指向,指针名不能写操作
例:
const int *p; // *p是只读
int const * // *p是只读
int *const p = &a // p是只读
const int *const p = &a; // p 和 *p都是只读的
9、动态内存申请
空间在堆区,人为申请,人为释放
不是所有的设备都可以进行动态内存申请(如:单片机就必须有MMU)有内存申请功能才能用。
申请空间的函数malloc :
函数声明:void *malloc(size_t size)
释放空间的函数free;
注:当动态内存申请的空间没有指针指向的时候,就不能释放,会造成内存泄漏