-
字符指针
char *(变量名)
#include<stdio.h>
int main()
{char ch='w';
char *p=&ch;
printf("%c\n",*p);//指针类型为char型 解引用只能有1字节
return 0;
}
#include<stdio.h>
int main()
{char *p="hello world";//指针p中放的是字符串的首地址
printf("%s\n",p);//字符串在字符常量区 不能通过指针P来修改
return 0;//指针P在栈上了开辟4字节
}
#include<stdio.h>
int main()
{
char str1[]="hello bit";//str1和str2分别指向两个地址 地址不同
char str2[]="hello bit";
char *str3="hello bit";//str3和str4指向同一个字符串
char *str4="hello bit";//只开辟了一份 str3和str4指向同一字符串(地址相同)
if(str1==str2)
{printf("str1 and str2 are same\n");
}
else {printf("str1 and str2 are different\n");
}
if(str3==str4)
{printf("str3 and str4 are same\n");
}
else{printf("str3 and str4 are different\n");
}
return 0;
}
-
数组指针
数组指针是指针,是能够指向数组的指针
int (*p)[10] 整型数组指针(看优先级 先和*结合 在和数组结合)
#include<stdio.h>
int main()
{
int a[10]={1,2,3,4,5,6,7,8,9,0};
int (*p)[10]=&a;//&a为数组的地址
return 0;
}
-
数组参数和指针参数
1. 数组传参要降维降维成指向其内部元素类型的指针
一维数组传参下标可省略
二维以上数组传参时只有第一个下标可省略 其余都不可以
数组的下标也是数组类型的一部分
#include <stdio.h>
void Print_a1(int(*a)[5],int row, int col)//数组指针
{
int i = 0;//数组传参要降维 降维成指向其内部元素类型的指针
for (; i<row; i++)
{
int j = 0;
for (; j<col; j++)
{
printf("%d\n", a[i][j]);
}
}
printf("\n");
}
void Print_a(int a[3][5],int row, int col)
{
int i = 0;
for (; i < row; i++)
{
int j = 0;
for (; j < col; j++)
{
printf("%d\n", a[i][j]);
}
}
printf("\n");
}
int main()
{
int a[3][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//二维数组的首元素是一维数组的第一行
int r = 3;
int c = 5;
Print_a(a,r, c);//传递的a其实相当于第一行的地址,是一维数组的地址
Print_a1(a,r, c);
system("pause");
return 0;
}
2.一维数组传参
void test(int a[])//也可写成int a[10]或int *a(数组传参要降维 降维成指向其内部元素类型的指针) 内部元素类型为int
{}
void test1(int **a1)//数组传参要降维 内部元素为一级指针 也可写成 int *a1[20]
{}
int main()
{int a[10]={0};
int *a1[20]={0};//指针数组
test(a);
test1(a1);
}
3.二维数组传参
二维数组传参,函数形参的设计只能省略第一个[ ]的数字(对于一个二维数组,可以不知道有多少行,但必须知道一行有多少元素)
二维数组传参的三种方式:
#include<stdio.h>
void test(int a[3][5])
{}
void test(int a[][5])
{}
void test(int (*a)[5])//数组传参要降维 降维成指向其内部元素类型的指针 内部元素类型为一维数组 则降维成一维整型数组指针
{}
int main()
{int a[3][5]={0};
test(a);
return 0;
}
4.一级指针传参
#include<stdio.h>
void print(int *p,int sz)//也可写成int p[] 伪装成数组的指针
{int i=0;
for(;i<sz;i++)
{printf("%d\n",*(p+i));}//p[i]
}
int main()
{int a[10]={1,2,3,4,5,6,7,8,9,0};
int *p=a;
int sz=sizeof(a)/sizeof(a[0]);
print(p,sz);
return 0;
}
5.二级指针传参
#include<stdio.h>
void test(int **pi)
{printf("num=%d\n",**pi);//**pi=n=10
}
int main()
{ int n=10;
int *p=&n;
int **pp=&p;
int *a[10];//指针数组
test(pp);
test(&p);
test(a);
return 0;
}
-
函数指针
函数指针是保存函数的地址
函数名或取地址函数名都表示取地址
eg: void (*pfun1)() 函数指针
void(*pfun_t)(int) 函数指针
函数调用的本质:程序调转到目标函数入口地址处
#include<stdio.h>
void print()
{printf("haha\n");
}
int main()
{
printf("%p\n",print);
printf("%p\n",&print);
return 0;
}
(*(void(*)())0)();函数指针
void (*signal(int,void(*)(int)))(int);返回值为函数指针的函数声明
-
函数指针数组和转移表
把函数的地址存到一个数组中,那么这个数组就叫函数指针数组
int (*p[10])( ) 函数指针数组
函数指针数组的用途:转移表
例题:计算器
#include<stdio.h>
#include<Windows.h>
#pragma warning (disable:4996)
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a*b;
}
int Div(int a, int b)
{
return a / b;
}
int main()
{
int x, y;
int input = 1;
int ret = 0;
int(*p[5])(int x, int y) = { 0, add, sub, mul, Div };//转移表
while (input)
{
printf("******************************\n");
printf(" 1.add 2.sub \n");
printf(" 3.mul 4.div \n");
printf("******************************\n");
printf("请选择:\n");
scanf("%d", &input);
if ((input <= 4 && input >= 1))
{
printf("输入操作数:\n");
scanf("%d %d", &x, &y);
ret = ((*p[input])(x, y));
}
else{
printf("输入有误\n");
continue;
}
printf("ret=%d\n", ret);
}
system("pause");
return 0;
}
-
指向函数指针数组的指针
指向函数指针数组的指针是一个指针,指针指向一个数组,数组元素都是函数指针
#include<stdio.h>
void test(const char *str)
{printf("%s\n",str);
}
int main()
{void (*pfun)(const char *)=test;//返回值为void 参数为const char * 的函数指针 函数指针保存函数地址
void (*pfun1[5])(const char *str);//函数指针数组 数组里放函数的地址
pfun1[0]=test;
void (*(*pfun2)[10])(const char *)=&pfun1;//指向函数指针数组pfun1的指针pfun2
return 0;
}
-
回调函数
回调函数就是一个通过函数指针调用的函数
如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数
1.qsort 函数可以任意类型进行排序,但需要使用者实现一个比较函数
声明:
void qsort(void *base,size_t nitems,size_t size,int (*compar)(const void *,const void *))
base: 指向要排序的数组的第一个元素的指针
nitems:由base指向的数组中的元素个数
size:数组中每个元素的大小,以字节为单位
compar:用来比较两个元素的函数
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
int int_cmp(const void *p1, const void *p2)//回调函数
{
int *x = (int *)p1;
int *y = (int *)p2;
if (*x > *y)
{
return 1;
}
else if(*x==*y)
{
return 0;
}
else{
return -1;
}
}
int main()
{
int a[] = { 12, 3, 56, 2, 62, 4, 1, 7, 9, 21 };
qsort(a, sizeof(a) / sizeof(a[0]), sizeof(int), int_cmp);
int i = 0;
for (; i<sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", a[i]);
}
printf("\n");
system("pause");
return 0;
}
2. 模拟实现qsort(采用冒泡的方式)
#include<stdio.h>
#include<Windows.h>
int int_cmp(const void* p1, const void* p2)
{
int *x = (int*)p1;//强转类型
int *y = (int*)p2;
if (*x > *y)
{
return 1;
}
else if (*x == *y)
{
return 0;
}
else
{
return -1;
}
//或者
//return (*(int *)p1 - *(int *)p2);
}
void Swap(char* p1, char* p2,int size)
{
while (size--)//一个字节一个字节的交换
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
p1++;
p2++;
}
}
void my_qsort(void* base, size_t num, size_t size, int(*compare)(const void*,const void*))
{
char* p = (char*)base;//通过char一次操纵一个字节
//冒泡思想:从前往后,相邻两个元素之间进行比较,将大的元素依次向后排;第二次进行比较时,重复之前步骤,不对第一个元素进行重复;数组长度为n,重复上述步骤n-1次
for (unsigned int i = 0; i < num-1; i++)//冒泡的轮次
{
int flag = 0;
for (unsigned int j = 0; j < num-1-i; j++)//减i是说明此数已经交换过了,不需要再进行交换
{
if (compare(p+j*size,p+(j+1)*size)>0)
{
Swap(p+j*size,p+(j+1)*size,size);
flag = 1;
}
}
if (!flag)//控制交换完成
{
break;
}
}
}
int main()
{
int arr[] = { 7, 1, 2, 4, 5, 3, 9, 0, 6 };
int i = 0;
//void qsort(void* base,size_t num,size_t size,int(*compare)(cosnt void*,const void*))
my_qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
printf("\n");
system("pause");
return 0;
}