当前位置: 首页 > wzjs >正文

帮忙做公司网站个人做电商网站icp

帮忙做公司网站,个人做电商网站icp,徐州网站建设青州陈酿,商务网站开发的流程🔥🔥 个人主页 点击🔥🔥 每文一诗 💪🏼 往者不可谏,来者犹可追——《论语微子篇》 译文:过去的事情已经无法挽回,未来的岁月还可以迎头赶上。 目录 C内存模型 new与…

 

 

    🔥🔥 个人主页 点击🔥🔥


每文一诗  💪🏼

        往者不可谏,来者犹可追——《论语·微子篇》

        译文:过去的事情已经无法挽回,未来的岁月还可以迎头赶上。   


目录

C++内存模型

new与delete动态分配内存

动态分配单个变量(例如; int* ptr = new int(10))

动态分配数组(例如 int* arr = new int[5] )

分配内存失败的情况

一维数组与指针

使用数组名/和数组名加下标访问数组中元素及其地址

使用指针访问数组中元素及其地址

二维数组与指针

行指针

函数指针

指针用作函数参数

用函数指针来传递函数


 

C++内存模型

 

        栈区:由编译器自动管理,用于存储局部变量、函数参数和返回地址。每当调用一个函数时,会在栈上分配一块新的栈帧,函数执行完毕后,栈帧自动释放。

        堆区:也被叫做自由存储区,由程序员手动管理。通过new操作符在堆上分配内存,使用delete操作符释放内存。

        数据存储区:用于存放全局变量和静态变量。在程序启动时分配内存,程序结束时释放内存。

        代码区:用于存放程序的可执行代码。代码区是只读的,防止程序在运行过程中被意外修改。

栈区和堆区区别

  1. 管理方式不同:栈区是系统自动管理的,在离开作用域时,会自动释放
  2. 空间大小不同:栈区大小操作系统预先设定,一般只有8M。如果在栈上分配的内存超过了栈的最大容量,会导致栈溢出(Stack Overflow)错误;堆区空间仅受限与物理内存空间,所以相对较大。
  3. 效率不同:栈区内存的分配和释放速度非常快,因为它只需要移动栈指针;而堆区内存分配和释放需要操作系统复杂的操作。

new与delete动态分配内存

new:动态分配内存

delete:  释放分配的内存

在堆区动态分配内存的步骤:

  1. 声明一个指针
  2. 用new运算符向系统的堆区申请一块内存,并用指针指向这块内存
  3. 通过解引用的方式,来取出这块内存中的值
  4. 当这块内存不用时,需用delete来释放它

动态分配内存的两类:

动态分配单个变量(例如; int* ptr = new int(10))

    int* p = new int(2);std::cout<<"*p的值:"<<*p<<std::endl;//打印内存中的值delete p;

解析:

  • int* p = new int(2);

        首先在堆区new申请了一块内存,这块内存是int型,接着初始化该内存的值为2,最后返回新分配内存的地址,用一个int类型的指针来指向他。

  • delete p;

        释放这块内存

动态分配数组(例如 int* arr = new int[5] )

    int* arry = new int[8];for(int i=0;i<8;i++){*(arry+i) = i;std::cout<<"第"<<i<<"个值"<<*(arry+i)<<std::endl;}delete[] arry;

解析:

  • int* arry = new int[8];

        首先new申请了一块内存,这块内存存储的是一个含有8位int型数据的数组,最后返回新分配内存的地址,用一个int类型的指针来指向他。这里的arry代表数组的首地址。

  •  *(arry+i) = i;

        通过循环和解引用的方式为数组中每个数赋值。

  • delete[] arry;

        释放这块内存

分配内存失败的情况

        如果需要分配含有大量的数据的数组,那么栈空间上分配是远远不够的,需要在堆区分配。但是如果内存分配失败,则会导致程序崩溃,但是我们不希望这样,我们可以在内存分配失败的时候捕捉到这个错误。

使用std::nothrow

int main(int argc, char const *argv[])
{int* arry = new(std::nothrow)int[100000];if(arry == nullptr)std::cout<<"分配内存失败"<<std::endl;else{std::cout<<"分配内存成功"<<std::endl;arry[99999] = 0;delete[] arry;}return 0;
}

 

一维数组与指针

使用数组名/和数组名加下标访问数组中元素及其地址

int arry[3] = {2,4,6};
std::cout<<"数组"<<std::endl;
std::cout<<arry<<std::endl;
std::cout<<&arry[0]<<std::endl;
std::cout<<arry+1<<std::endl;
std::cout<<arry+2<<std::endl;
std::cout<<arry[0]<<std::endl;
std::cout<<arry[1]<<std::endl;
std::cout<<arry[2]<<std::endl;

解析:

  • 数组的名称/数组第一个元素的地址 是同一个地址
  • 数组名+n:数组第n个元素的地址
  • 数组名[n]:数组第n个元素的内容

使用指针访问数组中元素及其地址

int* p = arry;
std::cout<<"指针"<<std::endl;
std::cout<<p<<std::endl;
std::cout<<p+1<<std::endl;
std::cout<<p+2<<std::endl;
std::cout<<*(p)<<std::endl;
std::cout<<*(p+1)<<std::endl;
std::cout<<*(p+2)<<std::endl;

解析:

        如果将数组名称赋给一个指针变量,实际上是将数组的首地址赋给了指针。

  • 指针+n:数组第n个元素的地址
  • *(指针+n):数组第n个元素的内容

对于C++而言

数组名[下标] 解释为 *(数组名首地址+下标)

地址[下标] 解释为 *(地址+下标)

输出

两者是一样的

二维数组与指针

在讲二维数组之前,有必要去介绍对一个一维数组名取地址

void func2()
{int a[3] = {6,7,8};std::cout<<"数组第一个元素的地址:"<<a<<std::endl;std::cout<<"数组第一个元素的地址+1:"<<a+1<<std::endl;std::cout<<"数组的地址:"<<&a<<std::endl;//即为地址的地址,是一个行指针std::cout<<"数组的地址+1:"<<&a+1<<std::endl;int (*p)[3] = &a;//正确// int *p2 = &a;//错误S
}

解析:

       我们都知道数组名a是代表数组第一个元素的地址,但是&a是数组的地址,虽然a和&a的地址是相同的,但是二者有着不同的类型。

        a的类型是 int*

        &a的类型是 int(*p)[],即行指针。

为了证明a和&a有着不同的含义,我们同时对两个地址加1测试

输出

  •  可见数组第一个元素的地址+1后,实际上是加了4,对于16进制,c后是d,e,f,0然后进位a变为b,所以是ac变b0
  • 而数组的地址+1后,发现并没有+4,而是+12,12是3*4得来的,因为数组有3个int型数据,每个数据占4个字节。
  • 这也是行指针的作用,行指针+1后,实际上加上的是这一行数组组成的数组的总长度。

行指针

对于二维数组而言。

行指针格式: 数据类型 (*p)[列大小]

例如

int arry[2][3] = {{1,2,3},{4,5,6}};

int (*p)[3] = arry;

#include<iostream>int main(int argc, char const *argv[])
{int arry[2][3] = {{1,2,3},{4,5,6}};int (*p)[3] = arry;// 这种方式是一个行指针,也就是说该指针p指向的是二维数组中第一个包含三个int型数据的数组的地址// 对该地址进行解引用,就会得到该数组的首地址,再次解引用就会得到数组中具体的值。std::cout<<**p<<std::endl;//p为二维数组中每一行数组的地址,*p得到数组第一个元素的地址,**p得到数组元素的值std::cout<<*(*(p+1))<<std::endl;//p为二维数组中第0行数组的地址,再加1得到第1行数组的地址,解引用为第一行数组的第一个元素的地址,再解引用位第一个元素的值。std::cout<<*(*(p+1)+1)<<std::endl;//*(p+1)为第一行数组的第一个元素的地址,*(p+1)+1:再加1为第一行数组的第二个元素的地址,再解引用为第二个元素的值。std::cout<<*(p[1]+1)<<std::endl;//p[1]在c++中被解释为*(p+1)// 个人理解:// 地址 + n:// 应看这个地址的类型,即这个指针的类型,如果这个指针是行指针,那么加1就是加上这一行数组的总共的字节数//例如p+1,p是行指针,存储的是每一行数组的地址,加1其实是加上了4*3=12个字节//如果这个指针是普通指针,那么加1就是加上这个数组的单个元素的字节数//例如*(p+1)+1,*(p+1)是普通指针,存储的是数组第一个元素的地址,加1其实是加上了4个字节return 0;
}

输出

函数详解:

  • int (*p)[3] = arry;

        这种方式是一个行指针,也就是说该指针p指向的是二维数组中第一个包含三个int型数据的数组的地址

  • std::cout<<**p<<std::endl;

        p为二维数组中每一行数组的地址,*p得到数组第一个元素的地址,**p得到数组元素的值

  • std::cout<<*(*(p+1))<<std::endl;

        p为二维数组中第0行数组的地址,再加1得到第1行数组的地址,解引用为第一行数组的第一个元素的地址,再解引用位第一个元素的值。

  • std::cout<<*(*(p+1)+1)<<std::endl;

        *(p+1)为第一行数组的第一个元素的地址,*(p+1)+1:再加1为第一行数组的第二个元素的地址,再解引用为第二个元素的值。

  • std::cout<<*(p[1]+1)<<std::endl;

        p[1]在c++中被解释为*(p+1)

个人理解:

对于 地址 + n:

  •  应看这个地址的类型,即这个指针的类型,如果这个指针是行指针,那么加1就是加上这一行数组的总共的字节数。例如p+1,p是行指针,存储的是每一行数组的地址,加1其实是加上了4*3=12个字节
  • 如果这个指针是普通指针,那么加1就是加上这个数组的单个元素的字节数。例如*(p+1)+1,*(p+1)是普通指针,存储的是数组第一个元素的地址,加1其实是加上了4个字节

函数指针

指针用作函数参数

如果参数是一个 数组的话,必须传递数组的长度

下面用代码解释原因

#include<iostream>
void func(int* arr)
{std::cout<<"数组长度2="<<sizeof(arr)<<std::endl;for(int i =0;i<sizeof(arr)/sizeof(int);i++){std::cout<<*(arr+i)<<std::endl;}}
int main(int argc, char const *argv[])
{int arry[3] = {2,4,6};func(arry);std::cout<<"数组长度1="<<sizeof(arry)<<std::endl;  return 0;
}

输出

        在函数func中,参数是一个指针变量,使用sizeof运算符的时候,会返回这个指针的大小,而指针的大小是一个常数8(在64位操作系统);而在main函数中,arry是一个数组名,在使用sizeof运算符的时候,会返回这个数组的大小。

        所以在func函数中,sizeof(arr)/sizeof(int)的值是8/4等于2,所以数组只打印了索引为0和1的值。

正确的做法是参数中加上数组长度

#include<iostream>
void func(int* arr,int len)
{std::cout<<"数组长度2="<<sizeof(arr)<<std::endl;for(int i =0;i<len;i++){std::cout<<*(arr+i)<<std::endl;}}
int main(int argc, char const *argv[])
{int arry[3] = {2,4,6};func(arry,sizeof(arry)/sizeof(int));std::cout<<"数组长度1="<<sizeof(arry)<<std::endl;  return 0;
}

输出

用函数指针来传递函数

用途:可以用一个函数来调用别的函数.

做法:将该函数的参数设置为要调用函数的指针

声明一个函数指针:

格式:返回值类型 (*函数指针名)(参数1,参数2)

通过函数指针调用函数

函数指针名(参数1,2)

在C++中,函数的名称就是函数的地址

#include<iostream>int func2(int m)
{std::cout<<"函数2"<<std::endl;return m+1;
}
int func3(int m)
{std::cout<<"函数3"<<std::endl;return m-1;
}
void func(int(*pf)(int))
{std::cout<<"准备工作"<<std::endl;int n = pf(3);std::cout<<"返回值"<<n<<std::endl;std::cout<<"收尾工作"<<std::endl;
}
int main(int argc, char const *argv[])
{func(func2);func(func3);return 0;
}

函数解析:

这段代码实现了函数传递函数,通过修改参数可以让不同的函数被执行。  

     主要看的是void func(int(*pf)(int))

这个函数func的参数是一个函数指针

  • 名称:pf
  • 返回值:int
  • 参数:int 可不加变量名

    func(func2);func(func3);

这个是将需要传递的函数的名称传递过去,函数的名称就是函数的地址

 输出

若本文对你有帮助,你的支持是我创作莫大的动力!

    🔥🔥 个人主页 点击🔥🔥

 


文章转载自:

http://YlLRms6b.Lbhck.cn
http://fWOsZlm9.Lbhck.cn
http://MXEUO9Uz.Lbhck.cn
http://vhX7ABKw.Lbhck.cn
http://odpk43Qf.Lbhck.cn
http://hoWQpfvL.Lbhck.cn
http://ohteQ1r2.Lbhck.cn
http://LjFwcXsI.Lbhck.cn
http://AfdJfgnq.Lbhck.cn
http://Mm17lltR.Lbhck.cn
http://4llxj6No.Lbhck.cn
http://lMa4XAtY.Lbhck.cn
http://H828iEkP.Lbhck.cn
http://BOKRobn3.Lbhck.cn
http://M71XDk9h.Lbhck.cn
http://Ra3fq4Np.Lbhck.cn
http://R69z2gza.Lbhck.cn
http://j8GLYZZS.Lbhck.cn
http://iX4ChxKu.Lbhck.cn
http://EwwEHas1.Lbhck.cn
http://KR4jh1ww.Lbhck.cn
http://dIAr0ZRH.Lbhck.cn
http://fo27zJVN.Lbhck.cn
http://nGMVuPvu.Lbhck.cn
http://FuafeGJU.Lbhck.cn
http://VUMlR4FP.Lbhck.cn
http://55qFUMph.Lbhck.cn
http://f9JBtcCL.Lbhck.cn
http://6m5NzLjI.Lbhck.cn
http://fbgPrzUc.Lbhck.cn
http://www.dtcms.com/wzjs/679828.html

相关文章:

  • 凉山州住房和城乡建设局网站网站内容维护更新方法
  • 湘潭市 网站建设哈尔滨的网络优化能做么
  • 网站界面分析个人网站注册什么域名
  • 网站高防服务器租用做餐饮网站建设
  • 普集网站开发站长工具的使用seo综合查询运营
  • 网站方案设计wordpress幻灯片插件怎么用
  • 无代码企业网站开发wordpress 域名绑定 方块
  • 手机端网站制作做网站维护要什么专业
  • 菠菜彩票网站怎么建设本地app开发公司电话
  • 哈尔滨网站建设方案维护前端 wordpress
  • 做餐厅logo什么网站素材多网页设计素材与效果图
  • 网页设计与网站规划怀集建设房管部门网站
  • 宝安网站推广平台建立淘宝客网站
  • 莞城网站推广如何做谷歌seo推广
  • 网站建设维保合同范本广告机免费投放
  • 做app网站的公司哪家好推广运营是什么工作
  • 设计衣服的网站专业网站优化价格
  • 2345网址导航站商城网站建设方案书
  • 雄安专业网站建设电话wordpress 模版
  • 门户网站建设方案内容网站建设seo策略
  • 网站怎么做微博认证南昌旅游网站建设方案
  • 建设网站服务器的方式有自营方式网络品牌推广策略
  • 做网站域名重要吗东莞常平邮编是多少
  • 设计师常用的素材网站404网站页面进入
  • 高考毕业做家教网站网站制作品牌公司
  • 电脑游戏网站建设河南省建设厅网站中州杯
  • 山东网站建设网络公司h5模板免费下载
  • 坂田做网站学校网站建设项目需求报告
  • 自己不会代码让别人做网站怎么管理网站图片自动轮换怎么做的
  • 网站地址查询ip济宁市建设银行网站