简单复习
对一维数组arr[i] = p[i] = *(p + i) = *(arr + i) eg:int *p=arr----p=arr
对二维数组arr[i][j] = p[i][j] = *(*(p + i) + j) = (*(p + i))[j]
int(*parr[10])[5]:parr是一个数组该数组中包含十个元素每个元素是一个数组指针该数组指针指向的数组有五个元素,每个元素是int型;
int *parr1[10]:parr1是一个数组,数组中有十个元素,每个元素都是int*类型;
int(*parr3)[10]:parr3是指针类型,该指针指向了一个数组,数组中有十个元素,每个元素类型都是int型;
对于数组传参int arr[10]={0}传参可采用123,int *arr[10]={0}可采用4,5
1.void test(int arr[])
2.void test(int arr[10])
3.void test(int *arr)
4.void test(int *arr[20])
5.void test(int **arr)
二维数组传参
void test(int arr[3][5])对于二维数组传参,传参时行可省略列不可
{
}
void test(int (*arr)[5])
{
}
int main()
{
int arr[3][5] = { 0 };
test(arr);
}
一级指针传参
int a = 10;
int* p = &a;
此时p=&a,*p=a
传参时可用test(p);或者test(&a);
二级指针传参
#include<stdio.h>
void test(int** ptr)
{
printf("num=%d\n", **ptr);
}
int main()
{
int n = 10;
int* p = &n;
int** pp = &p;
test(&p);
test(pp);
int* arr[10]={0};
test(arr);
return 0;
}
数组指针:
int arr[10] = { 0 };
int(*parr)[10] = { 0 };
函数指针:
int (*pa)(int, int) = ADD;
printf("%d", ADD(2, 3));
printf("%d", (*p)(2, 3));
#include<stdio.h>
void Print(char*str)
{
printf("%s\n", str);
}
int main()
{
void (*p)(char*) = Print;//*p是指针类型,指向函数,函数的类型是char*,函数的返回类型是void
(*p)("hello");
return 0;
}
int(*p)[10]:*说明p是一个指针变量,指向数组,数组中有十个元素,并且每个元素都是int型,(去掉p我们可以发现p是一个int(*)[10]型),说明了p是一个数组指针类型,指向数组。
(*(void(*)())0)();
解释:void(*)()是函数指针类型,函数是无参数的,返回类型是void
(void(*)())0把0强制类型转换成函数类型,把0转换为地址
(*(void(*)())0)调用0地址处的函数
最后的()表明他返回的是无参void(*signal(int,void(*)(int)))(int);
解释:signal是函数声明,signal(int,void(*)(int)),函数的两个参数是int型和函数指针类型(参数为int型,返回类型为void,
signal函数的返回类型也是一个函数指针类型void(*)(int)
函数指针数组 :通常用于转移表
#include<stdio.h>
int ADD(int x, int y)
{
return x + y;
}
int SUB(int x, int y)
{
return x - y;
}
int main()
{
int* arr[5];
//此时为了方便我们需要一个数组来存放2个函数的地址--函数指针的数组
int(*parr[2])(int, int) = { ADD,SUB };//parr会先与[]结合,去掉parr2,返回的是函数指针类型
int i = 0;
for (i = 0; i < 2; i++)
{
printf("%d\n", parr[i](2, 3));
}
return 0;
}
1。写一个函数指针pf,能够指向my_strcpy
char*(*pf)(char*,const char*);
2.写一个函数指针数组pfarr,能够存放4个my_strcpy函数的地址
char* (*pfarr[4])(char*,const char*)
函数指针数组常用于转移表 ,简化代码。
//实现一个计算器
#include<stdio.h>
void menu()
{
printf("***********************");
printf("*****1.ADD 2.SUB******");
printf("*****3.MUL 4.DIV******");
printf("*******0.exit**********");
printf("***********************");
}
int ADD(int x, int y)
{
return x + y;
}
int SUB(int x, int y)
{
return x - y;
}
int MUL(int x, int y)
{
return x * y;
}
int DIV(int x, int y)
{
return x / y;
}
int main()
{
int input = 0;
int x = 0;
int y = 0;
//为了避免大篇幅的switch case语句引入
int (*pfarr[5])(int, int)={0,ADD,SUB,MUL,DIV};//函数指针数组;
do
{
menu();
printf("请选择:>");
scanf_s("%d", &input);
if (input > 1 && input < 4)
{
printf("输入两个数字");
scanf_s("%d %d", &x, &y);
int ret = pfarr[input](x,y);
printf("%d\n", ret);
}
else if (input = 0)
{
printf("退出");
}
} while (input);
}
回调函数就是通过函数指针调用的函数
int ADD(int x, int y)
{
return x + y;
}
int SUB(int x, int y)
{
return x - y;
}
void CALE(int (*pf)(int, int))
{
int x = 0;
int y = 0;
printf("请输入两个操作数:》");
scanf_s("%d %d", &x, &y);
printf("%d", pf(x, y));
}
int main()
{
int input = 0;
int x = 0;
int y = 0;
scanf_s("%d", &input);
while (input)
{
switch (input)
{
case 1:
CALE(ADD);
break;
case 1:
CALE(SUB);
break;
}
}
return 0;
}
int arr[4] = { 0 };
int(*parr)[4] = &arr;指向函数指针数组的指针eg:
int (*pfarr[4])(int, int);
int (*(*ppfarr)[4])(int, int);ppfarr是一个数组指针,指针指向的数组有4个元素
指向的数组的美个元素类型都是函数指针类型int(*)(int,int)函数指针
int (*padd)(int,int)=add/&add;
#include<stdio.h> int ADD(int x, int y) { return x + y; } int main() { int (*pADD)(int, int) = ADD; int sum = pADD(1, 2);//写成(*pADD) printf("sum=%d", sum); return 0; }
//冒泡排序只能排整型数组
//---qsort--C语言的库函数--适用于各种排序
// void*类型的指针,可以接受任何类型的地址
但不能进行解引用
利用qsort函数进行排序
#include<stdio.h>
#include<stdlib.h>//qsort函数的头文件
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
int main()
{
int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
指针面试题1
/结构体指针加一跳过整个结构体
已知p的值为0x100000,结构体test类型变量的大小是20字节,求下列打印值的结果
#include<stdio.h>
struct Test
{int num;
char* pcname;
short sDate;
char cha[2];
short sBa[4];
}*p;
int main()
{
p = (struct Test*)0x100000;
printf("%p\n", p + 0x1);/原地址加上20,再转为16进制即可算出来是100014
printf("%p\n", (unsigned long)p + 0x1);//也就把p强制转换为整数类型加1也就是地址向后偏一个字节(两个相邻的地址间相差一个字节)
printf("%p\n", (unsigned int*)p + 0x1);//无符号整形指针类型加个4就ok
return 0;
}答案:
以地址形式打印
0x00100014
0x00100001
0x00100004
指针面试题2(提示ptr1[-1]=*(ptr1+(-1))并且参考上一道题
int main()
{
int a[4] = { 1,2,3,4 };
int *ptr1 = (int *)(&a + 1);//ptr1跳过整个数组,强制转换为地址类型存储在指针ptr1里
int* ptr2 = (int*)((int)a + 1);//(整形)的数组名+1表示跳过一个字节进入下一个地址
printf("%x , %x", ptr1[-1], *ptr2);//4与2000000
return 0;
}答案: 0x4 , 0x02000000
解析:数组a在内存中的存储为小端存储如下:
01 00 00 00 | 02 00 00 00 | 03 00 00 00 | 04 00 00 00
ptr1指向 : |
01 00 00 00 | 02 00 00 00 | 03 00 00 00 | 04 00 00 00
|
ptr2即指向
打印出来
01 00 00 00 | 02 00 00 00 | 03 00 00 00 | 04 00 00 00
*ptr1指向 |
所以倒着读00 00 00 04 打印出4
对ptr2进行解引用,由于是整形指针解引用一次性可以访问四个字节
01 00 00 00 | 02 00 00 00 | 03 00 00 00 | 04 00 00 00
由开始的 |访问到 |
解引用读出 00 00 00 02(由于是小端存储所以倒着读出来)
所以打印出:2000000
指针面试题3
#include<stdio.h>
int main()
{
int a[2][3] = { (0,1),(2,3),(4,5) };//逗号表达式
int* p;
p = a[0];
printf("%d", p[0]);
return 0;
}
答案:1解析:数组初始化后实际为int a[2][3]={{1,3,5},{0,0,0}
a[0]实际为首元素地址,打印出来就是1
指针面试题3
提示:p[4][2] =*(*(p+4)+2) ;
小端存储 ,小位放在内存低地址 ,地址的大小由低至高 。
(大端存储是小位放在内存高地址,地址由低至高,每个地址存放一个字节)
四个1是一个 f --15
指针面试题4-----这道题比简单哦
#include<stdio.h>
int main()
{
int aa[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
int* ptr1 = (int*)(&aa + 1);//表示跳过整个二维数组
int* ptr2 = (int*)(*(aa + 1));//表示第二行首元素的地址
printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}答案:10,5
阿里指针面试题
//提示:
char *p[]="shenqiaoy"//实际上也就只把s的首元素地址存放在指针p里面了
//红红火火恍恍惚惚啊
//
char**p=a;
//*说明p是指针所指的元素是char*类型的a;
int*p
p+1;
//表示p跳过一个整型大小的。。。
char**pa=a;
pa++;
//表示pa跳过一个char*类型的大小
#include<stdio.h>
int main()
{
char* a[ ] = { "work","at" ,"alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}答案:at
解析: