总结指针的 5个运算
- = 赋值运算 建立指向关系
- * 取指向对象 *p
- +/- n 地址移动
- p-q 指针相减
- p>q 关系运算
指针占用的内存大小:
- 指针变量指向的类型 不影响其 占用的内存大小
- 若 是32位机器 地址大小为 4字节
- 若 是64位机器 地址大小为 8字节
指针数组 与 二级指针
指针数组: 就是一个数组其元素是 指针
如图所示 :
ps 是一个 常量字符串指针数组
定义:
存储类型 元素类型 数组名[元素个数] = {};
auto cosnt char * ps[6] = {"Beijing", "Moscow", "New York", "","", NULL};
遍历指针数组:
for(int i= 0; i<5; i++)
printf("%s ",ps[i]);
指针方式遍历:
- //二级指针
- const char ** pps = ps;
//遍历指针数组:
for( int i = 0; i<5; i++)
printf("%s ",*pps++);
printf("\n");
练习:
char *a[3] = {"hello","world","ok"};
char **p = a;
- 假设每个表达式中p=a;求表达式代表含义或值?
- a[0] == "hello" == char* == %s
- *p == a[0]
- **p == *a[0] == 'h'
- *a == a[0]
- **a == *a[0] == 'h'
- *p++ == a[0] 然后 p=p+1
- *(p++) == *p++
- **(p+1)) == *"world" == 'w'
- *(*(p+1)+1) == *(a[1]+1) == 'o'
- (*p)++ 考虑p能否进行该操作? 可以操作
- 先*p == a[0] 然后 a[0] = a[0]+1; a[0] ---> "ello"
数组指针 与 二维数组:
- 二维数组:
- int arr[2][3] = {1,2,3,4,5,6};
- 数组指针: 含义: 一个指针 指向一个一维数组
- int (*p)[3] = arr; // p = &arr[0];
- &arr[0]=0x7ffc4307c1a0 // 数组指针类型
- arr =0x7ffc4307c1a0 // 数组指针类型
- arr[0]=0x7ffc4307c1a0 // 常量int类型指针
- &arr[0][0] =0x7ffc4307c1a0 // 常量int类型指针
- 问p+1是什么? p+1 == arr[1]
- 练习:
- int a[2][3];
- int (*p)[3] = a;
- 假设每个表达式中p=a;求表达式代表含义?
- a[0] 0号元素是一个一维数组
- *p == a[0]
- **p == a[0][0]
- *a == a[0]
- **a == a[0][0]
- *p++ == 先*p == a[0] 然后 p = p+1; p----> a[1]
- *(p++) == *p++
- **(p+1) == *a[1] == a[1][0]
- *(*(p+i)+j)
- == *(a[i]+j) == a[i][j]
- (*p)++ 考虑p能否进行该操作? 不能
- 先*p == a[0] 然后 然后 a[0] = a[0]+1; 数组名不能赋值
指针与函数:
- 指针函数:
- 本质是一个函数, 返回值是一个指针
- 函数指针:
- 本质是一个指针, 指向一个函数
- 代码段:
- 存储代码
- 函数名:
- 1. 代指这个函数本身
- 2. 代指这个函数的首地址
函数类型:
除去函数名 以及形参名等 名字 剩下的就是函数的类型
函数指针定义:
指向的函数返回值类型 (*函数指针名)(函数形参类型列表) = 对应类型的函数;
函数指针应用: 回调函数 多用于写接口
接口: API 写接口时,该接口的有些内容还没有确定, 因此通过函数指针的方式 来传递参数
回调函数: 一个函数 其参数 有函数指针类型
案例: 要求写一个函数, 参数传入一个数组, 要求输出 满足调用者条件的数? 参考funcp.c文件
void func1(int arr,int len, 函数指针 )
#include <stdio.h>
//函数指针
int func(char a)// 函数类型 int (char)
{
printf("hello func\n");
}
//定义一个函数指针 存放函数的地址
int (*fp)(char) = &func;
//要求写一个函数, 参数传入一
//个数组, 要求输出 满足调用者条件的数?
//条件通过函数指针传入,
//int condition(int num); 函数类型
//将num 确定 否是为你需要的数 是 返回值为真
void funcf(int *arr, int len, int (*fp)(int))
{
printf("满足条件的数有:");
//遍历数组
for(int i=0;i<len;i++)
{
if ( fp(arr[i])) printf("%d ",arr[i]);
}
}
int arr[10] = {1,2,3,4,5,6,7,8};
//用户A的条件
int conditionA(int num)
{
if(num % 2 == 0) return 1;
else return 0;
}
//用户B的条件
int conditionB(int num)
{
if(num > 5) return 1;
else return 0;
}
int main()
{
(&func)('A');
printf("func=%p\n",func);
printf("&func=%p\n",&func);
printf("fp =%p\n",fp);
printf("main=%p\n",main);
//通过函数指针 调用指向的函数
(*fp)('B');
fp('B');
//调用接口
funcf(arr, 10, conditionA);
funcf(arr, 10, conditionB);
return 0;
}
创建线程的函数: 了解
- int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
- void *(*start_routine) (void *), void *arg);
- void *(*start_routine) (void *):
- start_routine 是一个指针 指向一个函数 该函数类型 为 void * (void *)
- void * (void *) 是 一个函数类型 这个类型的函数 有一个 void*类型的返回值
- 有一个 void * 的形参
函数指针数组:
本质是一个数组 数组中元素是 函数指针
递归函数:
- 函数中 存在 自己调用自己 (递推关系)
- 每次自己调用自己 问题规模在逐渐减小 , 向临界条件趋近
- 临界条件: 退出自己调用自己 的条件
- 示例: 递归求解 1+2+3+..+ n = ??
- 求第n项的前n项和 S(n) = n + S(n-1); 递推式
- 临界条件 n == 1 S(n) == 1;
递归的特性:
- 本质就是 对栈区空间的 利用
- 递推过于 深入 可能导致栈区溢出 段错误
- 效率不高
- 在一些特定情况下, 使用递归可以 简化代码量
- 斐波那契数列
- 1 1 2 3 5 8 13 21 34 55....
- A(n) = A(n-1) + A(n-2);
- n == 1 || n == 2 A(n) ==1;
作业:
(1)杨辉三角
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
.....
#include <stdio.h>
/*
int yanghui(int i,int j)
{
return(j == 1 || j== i) ? 1: yanghui(i - 1,j - 1) + yanghui(i - 1,j);
}
int main()
{
int n;//杨辉三角的前n行
int i,j;
printf("%d",yanghui(10,7));
return 0;
}
*/
int YangHui(int r, int c)//实参i代表形参r,实参j代表形参c,即行与列
{
return(c == 1 || c == r) ? 1 : YangHui(r - 1, c - 1) + YangHui(r - 1, c);
}
int main()
{
int n;//杨辉三角的前n行
int i, j;
printf("需要输出几行杨辉三角(0~20):");
scanf("%d", &n);
for (i = 1; i <= n; i++)//控制每行
{
for (j = 0; j < n - i; j++)//每行的前n-i个位置输出空格
printf(" ");//每次输出3个空格
for (j = 1; j <= i; j++)//当前的第i行有j个元素,也就是:当前行是第i行,当前行一共有j列
printf("%6d", YangHui(i, j));
printf("\n");
}
return 0;
}
求 第10行 第7列的值
(2) 递归方式 实现选择排序