C++学习(二十三)(C语言部分)之 指针4
指针
指针 存放地址 只能存放地址
使用
&取地址运算符 *取值 解引用运算符
malloc 申请堆内存 free释放堆内存
1.1 指针 存放的地址(变量地址 常量区的地址 堆区内存首地址 数组首地址 指针变量的地址 函数地址)
1.指针 也是变量 指针也有类型
int *p; //定义的时候 去掉变量名 剩下的就是类型
int * 类型
存放什么类型的变量地址 int (去掉*p之后 剩下的就是存放的地址中变量的类型)
二级指针
int **pp;
pp的类型 int**
pp指向的数据类型 存放int*类型的 变量地址
int(*)[5];//数组指针
int(*)[5]//指针l类型
int[5] //指向的数组的地址
定义是定义 使用是使用 是分开的
pArr[i][j] *(*(pArr+i)+j) 使用的时候这是等价的 但定义的时候不一样
重点
1.指针类型
2.指针指向数据的类型
3.指针指向什么数据
1.2 指针加减
1.指针+int 指针-int类型
p+1 让指针指向下一个元素
2.p++ p--
3.指针和指针相减 的道到的值距离
//指针相加、相乘、相除 没有意义
如果不清楚指针移动之后 指向什么区域 就不要对指针++或者--
特别是申请内存的时候(不要随便移动这个指向堆内存首地址的指针)
*(p+i) p[i] 两个内部实现是一样的
1.3 常用的指针
1.指针常量
2.常量指针
3.指针数组
4.数组指针
5.指针函数
6.函数指针
XX指针 XX是修饰 常量指针 是指:指向常量的指针
指针XX 指针是修饰 指针常量 是指:类型是指针的常量
指针函数 函数类型(返回值类型)是指针的函数
指针常量
int *const p; //*表示指针 const表示常量
定义的时候是什么类型就一直是什么类型
指针数组+二维数组 (都需要解引用两次 但是不一样)
数组指针 可以指向二维数组 怎么定义数组指针 怎么赋值
用法 正确赋值之后 和二维数组是一样的
一行有多少个元素 存的什么类型的元素
代码笔记:
#include<stdio.h>
#include<stdlib.h>
/*--01
int max(int a, int b)
{
return a > b;//返回比较的结果 1或者0
} int fun(int x, int y, int z,int(*pMax)(int,int))//最后一个参数 函数指针 (形参函数指针)
{
return pMax(x, y);//用函数指针调用函数
}
*/ //排序 冒泡 选择 插入 桶排序 快速 希尔 堆排序 归并排序 //冒泡排序 思路 循环比较相邻的元素 大小关系和排序方向不和 交换两个元素
//从小到大排序 从左到右开始比较 如果第一个比第二个小 顺序不变 始终保持 左边小又变大
//每轮可以使得一个数字沉底 n个元素 只要循环n-1轮 int max(int a, int b)
{
return a > b;
}
int min(int a, int b)
{
return a < b;
} #if 0
void bull_sort(int arr[],int n) //冒牌排序 arr是存放数据的数组 n是数组中元素个数
{
int temp;//中间变量
for (int i = ; i < n - ; ++i) //循环n-1轮 每轮沉底一个数字 控制循环次数
{
//排序过程
for (int j = ; j < n-; ++j) //j<n&&j+1<n 防止越界 控制循环
{
if (arr[j] > arr[j + ]) //从小到大排序 前面元素比后面元素大 交换
{//从大到小的排序 前面的元素比后面的元素小 交换
temp = arr[j];
arr[j] = arr[j+];
arr[j+] = temp;//temp中间变量 用来交换
}
}
printf("第[%d]轮排序:", i);//第i轮排序
for (int k = ; k < ; ++k)
{
printf("%d\t", arr[k]);
}
printf("\n\n");
}
}
#endif //优化后的代码 运用函数指针
void bull_sort(int arr[], int n, int(*p)(int,int)) //函数指针 用来控制从小到大还是从大到小 冒牌排序 arr是存放数据的数组 n是数组中元素个数
{
int temp;//中间变量
for (int i = ; i < n - ; ++i) //循环n-1轮 每轮沉底一个数字 控制循环次数
{
//排序过程
//for (int j = 0; j < n-1; ++j) //j<n&&j+1<n 防止越界 控制循环
for (int j = ; j<n - -i;++j)//优化之后的算法 j<n - 1-i 可以减少比较次数
{
if (p(arr[j],arr[j + ])) //从小到大排序 前面元素比后面元素大 交换
{//从大到小的排序 前面的元素比后面的元素小 交换
temp = arr[j];
arr[j] = arr[j+];
arr[j+] = temp;//temp中间变量 用来交换
}
}
printf("第[%d]轮排序:", i);//第i轮排序
for (int k = ; k < ; ++k)
{
printf("%d\t", arr[k]);
}
printf("\n\n");
}
}
int main()
{
#if 0
double x;
int *p = &x;//如果定义一个double型的x 那么赋值给int*型p 就会报错
//int* 是指针的类型 int(*pArr)[] = &x;//这是一个数组指针类型 与定义的double型的是不相附的 所以会报错 //可以如下方式定义
int arr[];
int(*pArr)[] = &arr;//取一位数组的地址
//使用如下
(*pArr)[];//arr[0]的地址 pArr相当于&arr地址 --->*pArr 相当于arr arr[0] 相当于 (*pArr)[0]
//取变量地址 不会取数组地址--->很麻烦
#endif #if 0
//常用的方式
int *p;
p = arr;//常规定义方法 保存的是数组首元素的地址
*p = ;//相当于arr[0]=1;
p += ;//指针加减法是地址的加减 指针加一 地址加多少 要看指针指向变量的类型而定 指向下一个元素的地址 不是下标 指针加减之后还是指针
#endif #if 0
p = (int*)malloc(sizeof(int)* );//申请内存
p++;//p++之后不再指向原来的地址
free(p);//释放内存 运行后会报出一个错误 出现一个断点
#endif #if 0
int x;//const 常属性 不能修改
int *const p=&x; //指针常量 *表示指针 const表示常量 定义的时候必须赋值
//const修饰的p p不可以修改 *p可以修改 *p = ;//赋值 scanf也可以赋值
p++;//不能修改指向
scanf("%d", p);//scanf要用地址 用指针也可以 int const*q;//*在const后面 常量指针(指向常量 不能修改常量)
//*q不能修改 q可以修改 *q不能作为左值 q没有修改内容的权限 q = &x;
*q = ;//不能修改内容 *q不能作为左值
#endif #if 0
//指针数组 数组
//类型 数组名[数组大小]
int* arr[];//指针数组 表示数组中存放的是int*类型的变量
//存放指针的数组
//总共10个int* //数组指针
int(*parr)[];//数组指针 表示parr指针 指向数组的指针
//只有一个指针int(*)[10] //上面两个用法相近 但是意义不一样
//指针数组
for (int i = ; i < ; i++)
{
arr[i] = (int*)malloc(sizeof(int)* );//给10个指针元素赋值 sizeof求大小 malloc要申请的堆内存的大小 意思是申请20个字节的大小的空间
//注意下越界问题
}
int**pp = arr;//二级指针和指针数组对应
//赋值之后使用和指针数组是一样的 //占用的总内存 指针数组 10个int* 一个指针4字节 10*4+10*5*4=240字节 指针大小+堆区大小
//int brr[10][5] 10*5*4=200个字节
for (int i = ; i < ; i++)free(arr[i]);//循环释放内存
//数组存放在连续内存中
//申请堆内存的时候 单次申请的内存连续 多次申请的不一定连续
//申请堆内存后记得要释放
int dArr[][];//二维数组
int(*pdArr)[] = dArr;//赋值数组名 数组指针
//用法和二维数组一样的 都是解引用两次 //二级指针 和数组指针
//int **pp 可以用来对应一个指针数组名
//总结 指针数组名 二维数组名 二级指针 数组指针 都需要解引用两次 使用的时候比较相似 但是是有区别的
//malloc 返回指针的函数 指针函数
//函数指针 传参的时候用函数指针接收
//传参 调用函数 实参(函数名) 形参(函数指针) #endif //--01--fun(1, 2, 3, max);//z直接实参是函数名
#if 0
int test[] = {,,,,,,,,,};
printf("排序前:\n");
for (int i = ; i < ; ++i)
{
printf("%d\t", test[i]);//排序前
}
printf("\n\n"); printf("排序后:\n");
bull_sort(test, );
for (int i = ; i < ; ++i)
{
printf("%d\t",test[i]);//排序后
}
printf("\n\n"); getchar();
return ;
#endif int test[] = { , , , , , , , , , };
printf("测试一:\n");
printf("排序前:\n");
for (int i = ; i < ; ++i)
{
printf("%d\t", test[i]);//排序前
}
printf("\n\n"); printf("排序后:\n");
bull_sort(test, ,max);
for (int i = ; i < ; ++i)
{
printf("%d\t", test[i]);//排序后
}
printf("\n\n"); printf("测试二:\n");
printf("排序后:\n");
bull_sort(test, , min);
for (int i = ; i < ; ++i)
{
printf("%d\t", test[i]);//排序后
}
printf("\n\n"); getchar();
return ;
}
其中涉及到冒泡排序:
优化前的代码:
#include<stdio.h>
#include<stdlib.h> void bull_sort(int arr[],int n) //冒牌排序 arr是存放数据的数组 n是数组中元素个数
{
int temp;//中间变量
for (int i = ; i < n - ; ++i) //循环n-1轮 每轮沉底一个数字 控制循环次数
{
//排序过程
for (int j = ; j < n-; ++j) //j<n&&j+1<n 防止越界 控制循环
{
if (arr[j] > arr[j + ]) //从小到大排序 前面元素比后面元素大 交换
{//从大到小的排序 前面的元素比后面的元素小 交换
temp = arr[j];
arr[j] = arr[j+];
arr[j+] = temp;//temp中间变量 用来交换
}
}
printf("第[%d]轮排序:", i);//第i轮排序
for (int k = ; k < ; ++k)
{
printf("%d\t", arr[k]);
}
printf("\n\n");
}
} int main()
{
int test[] = {,,,,,,,,,};
printf("排序前:\n");
for (int i = ; i < ; ++i)
{
printf("%d\t", test[i]);//排序前
}
printf("\n\n"); printf("排序后:\n");
bull_sort(test, );
for (int i = ; i < ; ++i)
{
printf("%d\t",test[i]);//排序后
}
printf("\n\n"); getchar();
return ;
}
优化后的代码:
#include<stdio.h>
#include<stdlib.h> int max(int a, int b)
{
return a > b;
}
int min(int a, int b)
{
return a < b;
} void bull_sort(int arr[], int n, int(*p)(int,int)) //函数指针 用来控制从小到大还是从大到小 冒牌排序 arr是存放数据的数组 n是数组中元素个数
{
int temp;//中间变量
for (int i = ; i < n - ; ++i) //循环n-1轮 每轮沉底一个数字 控制循环次数
{
//排序过程
//for (int j = 0; j < n-1; ++j) //j<n&&j+1<n 防止越界 控制循环
for (int j = ; j<n - -i;++j)//优化之后的算法 j<n - 1-i 可以减少比较次数
{
if (p(arr[j],arr[j + ])) //从小到大排序 前面元素比后面元素大 交换
{//从大到小的排序 前面的元素比后面的元素小 交换
temp = arr[j];
arr[j] = arr[j+];
arr[j+] = temp;//temp中间变量 用来交换
}
}
printf("第[%d]轮排序:", i);//第i轮排序
for (int k = ; k < ; ++k)
{
printf("%d\t", arr[k]);
}
printf("\n\n");
}
} int main()
{
int test[] = { , , , , , , , , , };
printf("测试一:\n");
printf("排序前:\n");
for (int i = ; i < ; ++i)
{
printf("%d\t", test[i]);//排序前
}
printf("\n\n"); printf("排序后:\n");
bull_sort(test, ,max);
for (int i = ; i < ; ++i)
{
printf("%d\t", test[i]);//排序后
}
printf("\n\n"); printf("测试二:\n");
printf("排序后:\n");
bull_sort(test, , min);
for (int i = ; i < ; ++i)
{
printf("%d\t", test[i]);//排序后
}
printf("\n\n"); getchar();
return ;
}
2019-03-20 18:02:32
C++学习(二十三)(C语言部分)之 指针4的更多相关文章
- Salesforce LWC学习(二十三) Lightning Message Service 浅谈
本篇参考: https://trailhead.salesforce.com/content/learn/superbadges/superbadge_lwc_specialist https://d ...
- Flutter学习二之Dart语言介绍
上次我记录了Flutter的环境搭建,这次来简单记录一下Drat语言,Flutter是 Google推出并开源的移动应用开发框架,开发语言是Dart,那么Dart语言和其他的语言在语法上有上面区别呢, ...
- 前端学习(二十三)DOM操作,事件(笔记)
javascript 组成部分 1.ECMAScript javascript的核心解释器 2.DOM Document Object Modle 文 ...
- ElasticSearch7.3学习(二十三)----RestHighLevelClient Java api实现match_all、ids、match、term、multi_match、bool、filter、sort等不同的搜索方式
1.数据准备 首先创建book索引 PUT /book/ { "settings": { "number_of_shards": 1, "number ...
- Java开发学习(二十三)----SpringMVC入门案例、工作流程解析及设置bean加载控制
一.SpringMVC概述 SpringMVC是隶属于Spring框架的一部分,主要是用来进行Web开发,是对Servlet进行了封装.SpringMVC是处于Web层的框架,所以其主要的作用就是用来 ...
- ballerina 学习二十三 扩展ballerina
扩展ballerina 目前有三种方式: 扩展client connector的包 (数据库访问,基础设施,api) 扩展server listenner 绑定为不同的协议 添加新的注解到baller ...
- 渗透测试学习 二十三、常见cms拿shell
常见cms 良精.科讯.动易.aspcms.dz 米拓cms.phpcms2008.帝国cms.phpv9 phpweb.dedecms 良精 方法: 1.数据库备份拿shell 上传图片——点击数据 ...
- python学习二十三天函数的定义
在计算机编程中,函数就是可以重复调用,可以传递参数,减少代码的量,可以高效写出好的代码,提高软件的运行质量,下面简单讲述python函数的定义方式 1,函数的定义 函数的定义用关键词def 函数名跟 ...
- C++(二十三) — 内存泄漏及指针悬挂
1.内存泄漏 动态申请的内存空间没有正常释放,但也不能继续使用. ; pch1 = new char('A'); // 此处申请的空间未被释放. char *pch2 = new char; pch1 ...
- Java开发学习(二十四)----SpringMVC设置请求映射路径
一.环境准备 创建一个Web的Maven项目 参考Java开发学习(二十三)----SpringMVC入门案例.工作流程解析及设置bean加载控制中环境准备 pom.xml添加Spring依赖 < ...
随机推荐
- 【内存泄漏】 C/C++内存泄漏及其检测工具
对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如 Smart Pointer,Garbage Collection等.Smart Po ...
- 逆袭之旅DAY20.XIA.选择结构
2018-07-16 18:50:49 本章目标: 基本if选择结构 逻辑运算符 多重if选择结构 嵌套if选择结构 什么是if选择结构: if选择结构是根据条件判断之后再做处理 import ja ...
- 线性回归之决定系数(coefficient of determination)
1. Sum Of Squares Due To Error 对于第i个观察点, 真实数据的Yi与估算出来的Yi-head的之间的差称为第i个residual, SSE 就是所有观察点的residua ...
- UVa 11825 - Hackers' Crackdown DP, 枚举子集substa = (substa - 1)&sta 难度: 2
题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&a ...
- DeepLearning4J
http://blog.csdn.net/nysyxxg/article/details/52554734
- day33 线程的创建 验证线程之间共享数据 守护线程 线程进程效率对比 锁 死锁 递归锁
今日内容: 1.线程理论 2.锁: 牺牲了效率,保证了数据的安全(重点) 3.守护线程 4.GIL锁:(重点) 5.计算密集型和IO密集型 6.信号量,事件(了解) 7.补充. 子进程中不能input ...
- day16 初识面向对象
今天主要学习内容: 1.初始面向对象 2 .类 ,对象 3,面向对象和面向过程的对比 4.面向对象的三大特征 1,初始面向对象 面向过程 : 一切以实物的发展流程为中心 面向对象: 一切以对象为中心, ...
- 5.7 C++函数调用操作符重载
参考:http://www.weixueyuan.net/view/6385.html 总结: 需要以类成员函数的形式对函数调用操作符“()”进行重载. 只有常成员函数才能处理常对象,故我们依然在类中 ...
- SQL--数据--基本操作
数据操作 新增数据 有两种方案方案1:给全表字段插入数据,不需要指定字段列表:要求数据的值出现的顺序必须与表中设计的字段出现的顺序一致:凡是非数值数据,都需要使用引号(建议是单引号)包裹 insert ...
- C点滴成海------Ubuntu怎么运行C语言
Ubuntu怎么运行C语言 一.安装相关软件 安装vim:输入 sudo apt-get install vim: 安装gcc:输入 sudo apt-get install g++. 二.编写代码 ...