学习c++ Part02

news2024/11/23 18:40:44

学习c++ Part02

  • 前言
    • 1.函数
      • 注意点:
      • 全局函数(默认函数)
      • 静态函数
    • 2.预处理
      • 2.1 变量
    • 3.头文件
    • 4.宏函数
    • 5.指针
      • 5.1 普通变量与指针变量建立关系:
      • 5.2 指针初始化
      • 5.3 指针变量的注意事项
        • 5.3.1 void 不能定义普通变量,void * 可以定义指针变量
        • 5.3.2 指针变量未初始化不要取* ,初始化NULL不要取 * (段错误)
        • 5.3.3 指针变量 不要越界
      • 5.4 数组元素指针
        • 定义:指针只是指向数组第一个元素的地址
        • 数组元素的指针变量和数组等价
        • 在使用中 【】就是 *()的缩写
        • 指向同一个数组元素的两个指针变量的关系
      • 5.5 字符串指针
        • 自我理解:字符串指针域数值指针的不同
        • "xxx" 可以表示字符窜 也可以表示"xxx"字符串的首元素地址
        • 因为字符串放在文字常量去不可写 不能赋值
      • 5.6 数值的指针数组
      • 5.7 字符指针数组
      • 5.8 二维字符数组
      • 5.9 指针的指针
        • n级指针变量可以保存n-1级指针变量的地址
      • 5.9 指针数组和数组指针
      • 5.10 数组与数组指针的关系
        • n维数组与n-1维数组指针是完全等价的
        • 数组在作为函数参数时会被编译器自动优化成数组指针(64平台8B),n维数组优化成n-1维数组指针
      • 5.11 多维数组在物理上 都是一维存储
    • 6.指针与函数
      • 6.1 指针变量作为函数的参数
      • 6.2 函数的返回值类型为指针
      • 6.3 函数指针
        • 函数指针变量的注意事项
        • 函数指针使用typedef定义
        • 函数指针的使用目的(函数指针作为参数,类似于“多态”实现)

前言

时间:2023年6月29日 - 7月3日(这几天懈怠了检讨下,学习语言就需要速战速决!)

1.函数

函数的定义声明调用都与Java类似。
需要注意的是:如果调用在定义函数之前那么需要对函数进行提前声明,声明的格式与java中的抽象函数书写类似。
代码示例:

#include <iostream>
using namespace std;

//提前声明函数
void getIntArray(int arr[5], int n);
void sortIntArray(int arr[5], int n);
void printIntArray(int arr[5], int n);
int main() {
   //定义数组
   int arr[5] = {0};
   int n = sizeof(arr)/sizeof(arr[0]);
   //获取键盘输入的数组
   getIntArray(arr,n);
   //对数组进行排序
   sortIntArray(arr,n);
   //打印数组
   printIntArray(arr,n);
   return 0;
}
void printIntArray(int arr[5], int n) {
   for (int i = 0; i < n; ++i) {
       cout<<arr[i]<<" ";
   }
}

void sortIntArray(int arr[5], int n) {
   //冒泡排序
   for (int i = 0; i < n - 1; ++i) {
       for (int j = 0; j < n - i - 1; ++j) {
           if(arr[j]>arr[j+1]){
               int tmp = arr[j];
               arr[j] = arr[j+1];
               arr[j+1] = tmp;
           }
       }
   }
}

void getIntArray(int arr[5], int n) {
   cout<<"intput 5 numbers:";
   for (int i = 0; i < n; ++i) {
       cin>>arr[i];
   }
}

注意点:

  • 调用在定义之前,需要对方法进行提前声明
  • 普通变量,调用函数不能对其进行修改,引用变量(如数组、对象…)可以进行修改
void test(int num){
num++; 
}
int main(){
   int num = 10;
   test(num);
   cout<<num; //结果仍然为10,不是11
}

全局函数(默认函数)

  • 其他源文件都可以使用
  • 谁用谁extern声明

静态函数

  • 只能在当前源文件使用
    在这里插入图片描述

2.预处理

进程:可执行文件 从运行到结束 整个动态过程 叫作进程
32位平台。每个进程分配4G的虚拟空间,64 8G?
内存:

(只读)文字常量区:数值常量、字符常量、字符窜常量、符号常量
(只读)代码区:代码的二进制指令
(&可读可写)栈区:局部变量、函数的形参、返回值<48
(&可读可写)全局区:普通全局变量、静态局部变量、静态全局变量
(可读可写)堆区:使用malloc、calloc、realloc、free动态申请

2.1 变量

  • 普通局部变量(栈区)
    • 作用范围和生命周期在{ }有效
    • 不初始化 内容随机 ;局部同名 就近原则
  • 普通全局变量(全局区)
    • 当前和其他源文件都有效 生命周期整个进程
    • 不初始化 内容为0;与局部变量同名优先选择局部变量
    • 其他文件使用全局变量时,需要extern声明(谁使用谁声明
  • 静态局部变量(全局区)
  • 作用范围:所在的{}复合语句之间有效 ;生命周期:整个进程有效
  • 不初始化内容为0;整个进程都存在(第一次定义有效)
void fun04()
{
   static int num=10;
   num++;
   cout<<"num = "<<num<<endl;
}
int main() {
   fun04();//num = 11
   fun04();//num = 12
   fun04();//num = 13
   fun04();//num = 14
}
  • 静态全局变量(全局区)
    • 作用范围:只能在当前源文件中进行使用 生命周期:整个进程
    • 不初始化内容为0

3.头文件

#include <head.h> //建议使用此形式 从系统目录中寻找
#include "head.h" //不建议使用此形式 优先从当前目录中寻找,找不到再从系统目录中寻找

4.宏函数

  • 编译四阶段:预处理、编译、汇编、链接
  • 不带参数的宏定义
#define PI 3.14  
#define MY_STR "hello world" 
#define N 100
  • 带参数的宏定义
#define MY_MUL(a, b)  a*b //宏不能有数据类型
cout<<MY_MUL(10,20);//10*20
  • 结束宏的作用域
    • 使用#undef
  • 注意事项:
    • 宏不能有参数类型
    • 宏不能保证参数的完整性,可以通过()来保证参数完整性
    • 宏的作用范围:从定义开始到当前文件结束都有效
    • 宏不能构成结构体、类的成员
  • 宏函数与普通函数的区别:
    • 宏函数不需要进栈出栈,调用多少次就会展开多少次,用空间换时间
    • 带参函数调用的时候需要进栈出栈,所以说节省了空间浪费了时间

5.指针

在32位平台,系统为每一个字节分配32的地址编号,编号称为地址,指针变量也是4字节大小

5.1 普通变量与指针变量建立关系:

int num = 10;
int *p = &num;  //&num 表示的num地址
cout<<*p; // 10(指向地址的内容)
cout<<p // 32位地址
// *p等价于num; p等价于&num

说法:

✅ 指针p指向了num
✅ 指针p保存了num地址
❎ 指针p指向了num地址

5.2 指针初始化

  • 如果不初始化 立即操作 会出现错误
    建议初始化为NULL
int *p = NULL;
  • 要学会判断指针变量的类型
//将指针名字去掉就是指针类型
//知道如何判断指针类型,可用于赋值判断语句
int num = 10 ;
int *p = &num;
//num 为 int ; &num 为 int * --> 对变量名取地址->整体加*
//p 为 int * ; *p 为 int --> 指针变量取* -> 整体减*
*&p == p
  • 指针变量指向类型
    将*和指针名去掉就是指向类型 int *p = &num 指向的就是int类型
  • 指针变量的指向类型决定了指针的指向宽度
  • 指针变量的指向类型决定了+1的跨度
int *p1 = &num; //宽度为4字节 +1的跨度为4字节
short *p2 = &num; //宽度为2字节 +1的跨度为2字节
char *p3 = &num; //宽度为1字节 +1的跨度为1字节

案例了练习:
在这里插入图片描述

int num = 0x01020304;
//案例1 :取出0x0102的值
short *p1 = (short *)&num;
*(p+1);
//案例2:取出0x02的值
char * p2 = (char *)&num;
*(p+2);
//案例3:取出0x0203的值
char * p3 = (char *)&num;
*(short *)(p+1);

5.3 指针变量的注意事项

5.3.1 void 不能定义普通变量,void * 可以定义指针变量

// void num: ❎
void *p ; //✅
  • p是万能的一级指针,如果用于函数形参可以达到操作多种数据类型的目的
  • 不要对void类型指针不能取※操作
int num = 10;
void *p = &num;
*p;//err p指向的类型为void 无法确定p的取值宽度 所以不能*p

5.3.2 指针变量未初始化不要取* ,初始化NULL不要取 * (段错误)

5.3.3 指针变量 不要越界

char ch = 'a';
int *p = &ch;
*p;//error 越界访问非法内存

5.4 数组元素指针

定义:指针只是指向数组第一个元素的地址

int arr[4] = {10,20,30,40}; 
int *p = &arr[0]
int *p = arr // arr = &arr[0]
// 也可以单独指向某个位置的元素
int *p = arr[2]; 

数组元素的指针变量和数组等价

*(p+1) = arr[1];

int arr[4] = {10,20,30,40};
int *p = arr;
*(p+1) = arr[1]; 

在使用中 【】就是 *()的缩写

int arr[5] = {10, 20, 30, 40, 50};
arr[1] = *(arr+1) = 1[arr] //20
  • 为啥arr = &arr[0]
&arr[0] == &*(arr+0) == arr+0 == arr

指向同一个数组元素的两个指针变量的关系

在这里插入图片描述

5.5 字符串指针

自我理解:字符串指针域数值指针的不同

字符串指针,指向的是字符串首元素的地址,而整个字符串放在了文字常量区(只读)可以通过首地址取到全部,这也就是为什么不需要加*也能取到整个字符串的原因
数值指针,则需要通过加* 来获取到指向地址的内容数值

图示:
在这里插入图片描述

“xxx” 可以表示字符窜 也可以表示"xxx"字符串的首元素地址

int *str = "hello world";
cout<<str; // hello world
cout<<*str; //h

因为字符串放在文字常量去不可写 不能赋值

int *str = "hello world";
str[6] = 'W' // 错误 权限冲突不可写

5.6 数值的指针数组

代码示例:

int num1 = 10;
int num2 = 20;
int num3 = 30;
int num4 = 40;
int *arr[4] = {&num1, &num2, &num3, &num4};
int n = sizeof(arr)/sizeof(arr[0]);
for(int i=0;i<n;i++)
{
    cout<<*arr[i]<<" ";//10 20 30 40
}
cout<<endl;

5.7 字符指针数组

在这里插入图片描述
代码示例:

char *arr[4] = {"hahaha","hehehe","lalala","xixixi"};
int n = sizeof(arr)/sizeof(arr[0]);
for(int i = 0 ; i < n ; i++){
	cout<<arr[i]<<" ";
}

5.8 二维字符数组

char *arr1[4]={"hehehehe", "xixixixixi", "lalalalala", "hahahahaha"};
char  arr2[4][128]={"hehehehe", "xixixixixi", "lalalalala", "hahahahaha"};

arr1是在指针数组 存放的是每个字符串的首元素的地址
arr2是二维字符数组 存放的是每个字符串

5.9 指针的指针

n级指针变量可以保存n-1级指针变量的地址

int num = 10;
int *p = &num;
int **q = &p;
cout<<*p //10
cout<<**q // 10

5.9 指针数组和数组指针

指针数组与数组指针:

int *arr[5];//指针数组 本质是数组 每个元素为int *
int (*arr)[5];//数组指针 本质是指针变量 保存的是数组的首地址(概数组必须5个元素每个元素为 int)

数组指针的定义方式:

int arr[5] = {10,20,30,40,50};
int (*p)[5] = &arr;
  • &arr == p 代表的是数组首地址
  • *p == *&arr == arr 代表的是 数组的首元素地址(即第一行的首元素地址)
  • *p+1 == *&arr+1 == arr + 1 代表的是第一行1号位元素的地址
  • *(p+1) 代表第二行首元素的地址
  • *(* (p+1)) 代表第二行首元素的地址中的内容

5.10 数组与数组指针的关系

n维数组与n-1维数组指针是完全等价的

int arr[n];    		int *p;
int arr[n][m]; 		int (*p)[m]
int arr[n][m][k]; 	int (*p)[m][k]
n维数组 和n-1维的数组指针 等价

数组在作为函数参数时会被编译器自动优化成数组指针(64平台8B),n维数组优化成n-1维数组指针

5.11 多维数组在物理上 都是一维存储

int arr[3][4]={{1,2,3,4}, {5,6,7,8},{9,10,11,12}};
int row = sizeof(arr)/sizeof(arr[0]);
int col = sizeof(arr[0])/sizeof(arr[0][0]);
int *p = &arr[0][0];
int i=0;
for(i=0;i<row*col;i++)
{
    cout<<p[i]<<" ";
}
cout<<endl;
//输出结果:1-12

6.指针与函数

6.1 指针变量作为函数的参数

函数内部不能修改外部变量的值,但是当将外部变量的地址作为参数传入函数,函数则可以对该变量进行修改

void setNum02(int *p)//int *p=&num;
{
	//*p == num
	*p = 100; 
}
void test01()
{
	int num =0;
	setNum02(&num);//单向传递之 传地址
	cout<<"num = "<<num<<endl;//100 修改成功 
}

6.2 函数的返回值类型为指针

将函数内部参数的合法地址,作为返回值,给外部使用。
注意:函数返回的是static修饰的静态局部变量的地址
为什么:如果是普通局部变量,在{}函数调用完毕后会进行释放,那么返回的指针指向的是一个非法地址

int* getAddr(void)
{
	//int data = 100;//不要返回普通局部变量的地址 
	static int data = 100;
	return &data;
}
void test04()
{
    int *p = NULL;
    p = getAddr();
    cout<<"*p = "<<*p<<endl;//100
}

6.3 函数指针

函数指针,本质是指针变量,保存的是函数的入口地址,64位平台占用8B
定义&调用示例:

int myAdd(int x,int y){ return x+y;}
//方式1:
//int  (*p)(int,int) = NULL; //指针尽量初始化
//p = myadd;
//方式2:
int (*p)(int,int) = myadd;
//调用(传入实参)
cout<<p(10,20) <<endl;// 30

函数指针变量的注意事项

  • 函数指针变量 不要+1 无意义
  • 不要对函数指针变量取* 无意义(*p会被编译器优化成p)
  • 函数指针变量 判断大小 > < 无意义
  • 函数指针变量 可以赋值 p2=p1
  • 函数指针变量 可以判断相等 p2 ==p1

函数指针使用typedef定义

int myAdd(int x,int y){ return x+y;}
typedef int (*FUN_TYPE)(int,int);
FUN_TYPE p = myAdd;

函数指针的使用目的(函数指针作为参数,类似于“多态”实现)

目的:让函数功能多样化(相当于参入不同的函数指针,调用不同的方法)
案例:设计一个算法实现 加减乘除

int myAdd(int x,int y) {return x+y; }
int mySub(int x,int y) { return x-y;}
int myMul(int x,int y) {return x*y;}
int myDiv(int x,int y) {return x/y; }
//设计算法 操作上面的函数
int myCalc(int x,int y, int (*func)(int,int) )  
{return func(x,y);}
void test()
{
	//int (*func)(int,int) = myAdd;
    cout<<myCalc(10,20, myAdd)<<endl;//30
    cout<<myCalc(10,20, mySub)<<endl;//-10
    cout<<myCalc(10,20, myMul)<<endl;//200
    cout<<myCalc(10,20, myDiv)<<endl;//0
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/714872.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot源码解析

1.Spring Boot介绍,源码阅读环境搭建,插件安装 2.spring boot 源码解析2-SpringApplication初始化 3.spring boot 源码解析3-SpringApplication#run 4.spring boot 源码解析4-SpringApplication#run第4步 5.spring boot 源码解析5-SpringApplication#run第5步 6.spring boot 源…

springboot医院挂号小程序

医院挂号系统 springboot医院挂号系统小程序 java医院挂号小程序 技术&#xff1a; 基于springbootvue小程序医院挂号系统的设计与实现 运行环境&#xff1a; JAVA版本&#xff1a;JDK1.8 IDE类型&#xff1a;IDEA、Eclipse都可运行 数据库类型&#xff1a;MySql&#xff08;…

在线教育场景下客户端实践与优化——RTC服务在线教育

在线教育场景下对提供稳定、高质量的音视频服务提出了非常高的要求。而不断推陈出新的课堂形式以及新技术的应用&#xff0c;使得好未来自研音视频SDK面临更多的挑战。 LiveVideoStackCon 2022北京站邀请到好未来音视频开发高级专家郭晓明介绍好未来自研SDK在工程化上所做出的努…

【编译、链接、装载十五】系统调用与API——printf源码分析

【编译、链接、装载十五】系统调用与API——printf源码分析 一、系统调用介绍1、什么是系统调用2、Linux系统调用3、系统调用的弊端 二、系统调用原理1、中断 三、linux下系统调用实现1、 strace 查看可知&#xff0c;printf调用了系统函数write2、gdb调试查看——printf3、gdb…

实践|随机森林中缺失值的处理方法

动动发财的小手&#xff0c;点个赞吧&#xff01; 除了在网上找到的一些过度清理的数据集之外&#xff0c;缺失值无处不在。事实上&#xff0c;数据集越复杂、越大&#xff0c;出现缺失值的可能性就越大。缺失值是统计研究的一个令人着迷的领域&#xff0c;但在实践中它们往往很…

并查集的讲解

什么是并查集&#xff1f; --是一个森林&#xff1b;&#xff08;由多颗树构成的&#xff09; 并查集原理 在一些应用问题中&#xff0c;需要 将 n 个不同的元素划分成一些不相交的集合 。 开始时&#xff0c;每个元素自成一个 单元素集合&#xff0c;然后按一定的规律将归于…

springboot开启热部署

第一步引入spring-boot-devtools依赖 <!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><!--默认false改依赖是否可以传递&…

【Servlet】如何使用 Servlet 编写第一个 helloword 程序

文章目录 前言一、创建 Maven 项目二、引入依赖三、创建目录四、编写代码五、打包项目六、部署程序七、运行程序总结 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习…

transforms数据增强

在AI领域的模型训练中通常会遇到模型过拟合问题&#xff0c;通常采取的办法就是数据增强处理&#xff0c;例如在图像处理中&#xff0c;数据增强是指对原始图像进行旋转、缩放、剪切、翻转等操作&#xff0c;以扩大训练数据集的规模&#xff0c;提高模型泛化能力&#xff0c;降…

Gradio HTML组件详解

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

【23-07-03:HTTP协议的结构学习】

目录 HTTP 请求的结构HTTP 请求的整体架构请求方法&#xff08;Method&#xff09;请求路径&#xff08;URI&#xff09;GET 参数&#xff08;Parameters for GET)协议说明&#xff08;Protocol&#xff09;头部字段&#xff08;Headers&#xff09;请求体&#xff08;Body&…

论文与专利查找和下载

例如我想查找和下载视频理解(video understanding)相关论文 路线大纲如下&#xff1a; 一、最主要方式&#xff1a; 大纲&#xff0c;蓝色都是有超级链接的可以直接打开: 第一步 谷歌搜索(英文) 学校的知网(中文)第二步 下载论文(谷歌学术--英文 学校的知网--中文)下载不了…

CMA

文章目录 前言概念功能启用CMA 内存的创建方式一、使用 cmdline方式二、使用 dts CMA 内存分配和释放实例&#xff08;dts 方式&#xff09; 前言 在嵌入式设备中&#xff0c;很多外设&#xff08;如摄像机、硬件视频解码器等&#xff09;需要较大的内存缓冲区&#xff0c;kma…

clickhouse日志表占用大量磁盘空间

clickhouse日志表占用大量磁盘空间 sql&#xff1a; SELECT sum(rows) AS 总行数, formatReadableSize(sum(data_uncompressed_bytes)) AS 原始大小, formatReadableSize(sum(data_compressed_bytes)) AS 压缩大小, round((sum(data_compressed_bytes) / sum(data_uncompresse…

<DB2> 《IBM DB2 备份恢复实用文档》(第一部分)

[TOC](《IBM DB2 备份恢复实用文档》(第一部分)) 1 理论 1.1 关于备份恢复说明 a、DB2数据库备份和恢复的数据都是已经提交落地在磁盘的数据 。 b、DB2数据库备份和恢复使用的日志都是归档日志。 c、只有开启归档日志&#xff0c;才能进行在线全备、在线增备。否则只能进行离…

基于单片机智能手环心率老人防跌倒心率体温 步数里程

功能介绍 以STM32单片机作为主控系统&#xff1b; OLED液晶显示心率体温步数等信息&#xff1b;通过按键设置心率、体温上限设置&#xff1b;当心率或者体温超过按键设置上限蜂鸣器进行声光报警提醒&#xff1b;通过wifi模块esp8266把数据发送到手机端进行显整个电路以5v供电&a…

Three.js卡通材质实现简明教程

继 Harry Alisavakis 令人惊叹的汤着色器之后&#xff0c;我想使用 Three.js 重新创建类似的卡通着色效果。 我从 Roystan 的卡通着色器教程开始&#xff0c;它是为 Unity 编写的。 在这篇文章中&#xff0c;我将把 Roystan 教程中概述的原则翻译成 Three.js。 下面描述的着色器…

mysql索引之Hash

在存储引擎中Memory引擎是支持Hash索引的&#xff0c;Hash索引跟java中的HashMap很像&#xff0c;有很多槽&#xff0c;存的也是键值对&#xff0c;键值为索引列&#xff0c;值为这条数据的行指针&#xff0c;通过指针就可以找到数据。 但是Hash索引应用的并不多&#xff0c;原…

一篇文章解释清楚IOC和DI

背景 众所周知我们要学习Spring&#xff0c;必不可少的就是IOC和AOP&#xff0c;那就让我们了解一下什么是IOC&#xff0c;开启下面的学习吧。 过程 什么是IOC&#xff1f; Ioc—Inversion of Control&#xff0c;即“控制反转”&#xff0c;不是什么技术&#xff0c;而是一…

VSCode 2019 “对COM组件的调用返回了错误HRESULT E_FAIL” 的解决

问题&#xff1a; VSCode使用 “MFC应用”模板创建项目时&#xff0c;出现&#xff1a;文件夹打不开&#xff0c;并弹出 “对COM组件的调用返回了错误HRESULT E_FAIL” 错误 解决方案&#xff1a; 1. 以管理员身份打开Developer Command Prompt for VS 2019&#xff08;vs2…