c++中堆、栈内存分配概念示例讲解

2023-05-16

首先来看看主要有几种程序内存分配:

一个由C/C++编译程序占用内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数参数值,局部变量值等。其操作方式类似于数据结构中栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量存储是放在一块,初始化全局变量和静态变量在一块区域, 未初始化全局变量和未初始化静态变量在相邻另一块区域。 - 程序结束后由系统释放。-->分别是data区,bbs区 
4、文字常量区 —常量字符串就是放在这里。 程序结束后由系统释放-->coment区
5、程序代码区—存放函数体二进制代码。-->code区

经典实例:

复制代码

#include <string>
int a=0;    //全局初始化区
char *p1;   //全局未初始化区
void main()
{
    int b;//栈
    char s[]="abc";   //栈
    char *p2;         //栈
    char *p3="123456";   //123456\0在常量区,p3在栈上。
    static int c=0;   //全局(静态)初始化区
    p1 = (char*)malloc(10);
    p2 = (char*)malloc(20);   //分配得来的10和20字节的区域就在堆区。
    strcpy(p1,"123456");   //123456\0放在常量区,编译器可能会将它与p3所向"123456\0"优化成一个地方。
}

复制代码

 

 

一、堆和栈究竟有什么区别(堆和栈理论知识)?

2.1申请方式
stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = (char *)malloc(10);

但是注意p1、p2本身是在栈中。

 

2.2申请后系统响应
栈:只要栈剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址链表,当系统收到程序申请时,会遍历该链表,寻找第一个空间大于所申请空间堆结点,然后将该结点从空闲结点链表中删除,并将该结点空间分配给程序,另外,对于大多数系统,会在这块内存空间中首地址处记录本次分配大小,这样,代码中delete语句才能正确释放本内存空间。另外,由于找到堆结点大小不一定正好等于申请大小,系统会自动将多余那部分重新放入空闲链表中。

 

2.3申请大小限制

栈:在Windows下,栈是向低地址扩展数据结构,是一块连续内存区域。这句话意思是栈顶地址和栈最大容量是系统预先规定好,在WINDOWS下,栈大小是2M(也有说是1M,总之是一个编译时就确定常数),如果申请空间超过栈剩余空间时,将提示overflow。因此,能从栈获得空间较小。

堆:堆是向高地址扩展数据结构,是不连续内存区域。这是由于系统是用链表来存储空闲内存地址,自然是不连续,而链表遍历方向是由低地址向高地址。堆大小受限于计算机系统中有效虚拟内存。由此可见,堆获得空间比较灵活,也比较大。

 

2.4申请效率比较
栈由系统自动分配,速度较快。但程序员是无法控制。
堆是由new分配内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.

另外,在WINDOWS下,最好方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

 

2.5堆和栈中存储内容
栈: 在函数调用时,第一个进栈是主函数中后下一条指令(函数调用语句下一条可执行语句)地址,然后是函数各个参数,在大多数C编译器中,参数是由右往左入栈,然后是函数中局部变量。注意静态变量是不入栈。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存地址,也就是主函数中下一条指令,程序由该点继续运行。

堆:一般是在堆头部用一个字节存放堆大小。堆中具体内容有程序员安排。

 

2.6存取效率比较

char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";

aaaaaaaaaaa是在运行时刻赋值;

而bbbbbbbbbbb是在编译时就确定;
但是,在以后存取中,在栈上数组比指针所指向字符串(例如堆)快。
比如:

复制代码

#include
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}

复制代码

对应汇编代码

复制代码

10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al

复制代码

第一种在读取时直接就把字符串中元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。

2.7小结:
堆和栈区别可以用如下比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他好处是快捷,但自由度小。
使用堆就象是自己动手做喜欢吃菜肴,比较麻烦,但是比较符合自己口味,而且自由度大。

 

全局变量或者静态变量,它们都放在堆里
局部变量放在栈里
堆区,也叫自由存储区.
为什么说在堆上分配内存比在栈上分配内存慢?

1.堆空间开辟需要用系统函数,栈上直接修改指针.
2. 堆空间管理需要系统记帐,栈上空间可以由编译器管理或是保存在某个处理器寄存器中。
3. 堆空间释放需要系统管理,栈上释放可以直接丢弃。堆空间需要通过栈上指针间接引用,所以访问会慢
记得在apue2上面看到关于线程中有这样一段话,大致意思是,一个线程有自己堆栈,可以在堆栈上分配内存,比如说一个结构体,如果这个线程调用了pthread_exit()返回这个结构体指针时候之后要特别小心,因为很有可能这个结构体里面成员值发生改变,这个可以理解,因为同一个进程所有线程资源是共享,当这个线程退出之后那部分以前用过堆栈很可能被其它线程占用,但同时又说如果malloc就不会出现这样问题,
比如,在栈上分一个int,只要esp-4就可以了,
在堆上系统要记录被分配内存信息,以便释放
BTW:
栈有序
堆无序
----------------------------------
内存分配方式有三种:   
   
   1.从静态存储区域分配。内存在程序编译时候就已经分配好,这块内存在程序整个运行期间都存在。例如全局变量,static变量。   
   
   2.在栈上创建。在执行函数时,函数内局部变量存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器指令集中,效率很高,但是分配内存容量有限。   
   
   3.从堆上分配,亦称动态内存分配。程序在运行时候用malloc或new申请任意多少内存,程序员自己负责在何时用free或delete释放内存。动态内存生存期由我们决定,使用非常灵活,但问题也最多。
----------------------------------------
一般所说堆栈(stack)往往是指栈,先进后出,它是一块内存区。用以存放程序局部变量,临时变量,函数参数,返回地址等。在这块区域中变量分配和释放由系统自动进行。不需要用户参与。   

   而在堆(heap,先进先出)上空间则是由用户进行分配,并由用户负责释放。

二、 函数调用与堆栈

1)编译器一般使用栈来存放函数的参数,局部变量等来实现函数调用。有时候函数有嵌套调用,这个时候栈中会有多个函数的信息,每个函数占用一个连续的区域。一个函数占用的区域被称作帧()。同时栈是线程独立的,每个线程都有自己的栈。例如下面简单的函数调用:

堆栈与函数调用(高手) - 毛狼 - maolang0 的博客

另外函数堆栈的清理方式决定了当函数调用结束时由调用函数或被调用函数来清理函数帧,在VC中对函数栈的清理方式由两种:

 参数传递顺序谁负责清理参数占用的堆栈
__stdcall从右到左被调函数
__cdecl从右到左调用者

 

2) 有了上面的知识为铺垫,我们下面细看一个函数的调用时堆栈的变化:

代码如下:

 

复制代码

int Add(int x, int y)
{
    return x + y;
}
void main()
{
    int *pi = new int(10);
    int *pj = new int(20);
    int result = 0;
    result = Add(*pi,*pj);
    delete pi;
    delete pj;
}

复制代码

 

对上面的代码,我们分为四步,当然我们只画出了我们的代码对堆栈的影响,其他的我们假设它们不存在,哈哈!

第一,int *pi = new int(10);   int *pj = new int(20);   int result = 0; 堆栈变化如下:

堆栈与函数调用(高手) - 毛狼 - maolang0 的博客

第二,Add(*pi,*pj);堆栈如下(函数参数入栈:从右向左):

堆栈与函数调用(高手) - 毛狼 - maolang0 的博客

第三,将Add的结果给result,堆栈如下:

堆栈与函数调用(高手) - 毛狼 - maolang0 的博客

第四,delete pi;    delete pj; 堆栈如下:

堆栈与函数调用(高手) - 毛狼 - maolang0 的博客

第五,当main()退出后,堆栈如下,等同于main执行前,哈哈!

堆栈与函数调用(高手) - 毛狼 - maolang0 的博客

 

 

 例子1 ----------------------------------------------------------------------------

复制代码

【参见】http://blog.csdn.net/wudaijun/article/details/8135205
#include<iostream>
using namespace std;
int main()
{
    char p[] ="123456";
    // char s[10];     //  正常复制: 123456  -- 123456
    char s[4];     //  栈溢出(目标栈空间不够大), output: 56  -- 123456
    char *ptr = p + 3;
    strcpy(s, p);
    cout<< p << "  --  " << s << "  ---  " << ptr << endl;
    return 0;
}

// 栈 内存分配方式 (地址:高(左)->低(右); 数据写入方向:低(右)->高(左))
// '/0' '6' '5' '4'(ptr) '3' '2' '1'(p) '' '' '' ''(s)     // char p[] ="123456";//char s[4];
// '/0' '6' '5' '4'(ptr) '/0' '6' '5'(p) '4' '3' '2' '1'(s)            //strcpy(s, p);
// output : 56  --  123456  ---  456
// 解析:在这里我们可以知道p=s+4;  然后我们对s进行写入"123456"  s所在的四个字节不够用  所以"56"(包括后面的/0)均被写入了p地址 因此输出p将输出56

复制代码

 结果讨论:

     关于栈:三个特性:

     1. 函数栈内存以一个地址即四个字节对齐。

     2. 地址从高地址到低地址分配。

     3. 数据从低位地址到高位地址写入。

 例子2 ----------------------------------------------------------------------------

复制代码

#include<iostream>
using namespace std;

int main()
{
     char p[] ="123456";
     int c=0;
     char s[4];
     strcpy(s, p);
     cout<<p<<endl;
     cout<<c<<endl;
     return 0;
}

// output : 

  123456
  13877
  请按任意键继续. . .

 

复制代码

内存跟踪:

               strcpy前:

               

               

               strcpy后:

               

               

结果讨论:

               这里和前面不同的地方是在p和s之间插入了一个c  它们的地址大小顺序为: s<c<p 因此对s的写入将覆盖c而不会影响到p

               那么c的值是怎么得到的  跟踪地址可以知道 c原本表示为: 00 00 00 00 在对s写入"123456"后可以得到c值表为:35 36 00 00

               由于操作系统的小端表示 ,在c的四个字节里 高地址(右边)存放数值的高位 低地址(左边)存放地址的低位  所以c实际的数值摆放为

               00 00 36 35 转换成十进制 得到13877

 

例子3 ----------------------------------------------------------------------------

堆的分配规则和栈不一样  堆的地址是从小到大分配的 并且连续分配的两个内存块的起始地址是肯定不同的。

     

     写在前面: 关于内存所谓的空闲区值:

                    经常写代码忘了初始化的人可能会注意到,每次定义一个整形变量没有初始化直接使用  往往每次都得到一个很大的负数  不是说没有分配的内存都是随机的么?看这个示例:

复制代码

    int main()
     {
          int a;
          int* pb = new int;

          cout<<"a is from stack, b is from heap"<<endl;
          cout<<"(int)a= "<<a<<endl;
          cout<<"(int)b= "<<*pb<<endl;
    
          cout<<"(hex)a= "<<hex<<a<<endl;
          cout<<"(hex)b= "<<hex<<*pb<<endl;
          char* pa = (char*)&a;
          cout<<"(char)a= "<<pa<<endl;
          cout<<"(char)b= "<<(char*)pb<<endl;
    
          delete pb;
          return 0;
     }

复制代码

 

     vc++6.0输出结果:

     

     我相信这里面出现的这两个字大家都很熟悉了,就连上面的两个负整数应该都是异常眼熟吧  接下来  揭开谜底:

     对于栈和堆的空闲区(未被覆盖前) 是会被默认初始化的, 栈内存初始化为CC,堆初始化为CD。  初看起来了解这个意义不大  但这是下面所说的一些东西的基础。

     示例2:

复制代码

     int main()
     {
          int*a = new int;
          int*b = new int;
          int*c = new int;

          delete a;
          delete b;
          delete c;
     
          return 0;
     }

复制代码

 

     调试 得到

     a = 00382a48
     b = 00382a90
     c = 00382ad8

 

     内存跟踪:

     

     这里面包含了很多信息

     1.b指针指向的地址处(00382a90) 被默认初始化为CD(堆未被覆盖前)

     2.空闲区两头是有四个字节的界定符的 这里是FD FD FD FD

     3.继续往上看  00382a70处  有一个地址00382a28

     4.下一个地址 00382a74处 有一个地址00383ab8

     在这里我们不妨假设这两个地址就是已经被分配的内存的下一块和上一块

     接下来  我们对00382a28进行跟踪:

     

     在该地址下面不远处 我们找到了00382a48 也就是指针a指向的地址  那么到了这里我们可以看出:

     堆中每一个内存块是被连接到一个链表上的  并且每一个空闲区都被封在一个结构体中

      这个结构体至少应该包含:

      1. 该数据块的前驱和后继

      2. 该数据块大小

      3. 数据块的界定符

      4. 数据块本身

 

     在这里我们可以看出 放在数据块前面的数据区大小=00382a48-00382a28=32个字节

  (

    00382a48 - 00382a28 = 32Byte

    48(H) = 0100 1000(B) = 72(D)
    28(H) = 0010 1000(B) = 40(D)
    72 - 40 = 32

  )

      同时对其中另一部分数据进行分析 初步可以猜测:

     00382a38  分配的元素类型所占字节数 这里是sizeof(int)。

     00382a3c 分配该类型元素的个数。

 

     到这里也可以明白为什么动态分配一个数组int* p=new int[5] 只需要delete []p 就可以了 因为结构体保存了元素个数

 

     随便再说一下  对于CD,CC只针对于还未使用过的内存  比如像栈这种动态收缩的结构  同一个内存不同时刻会存放不同的变量  在使用后回收时 只改变栈顶指针  数据是还在的  所以不是CC。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++中堆、栈内存分配概念示例讲解 的相关文章

  • TCP/IP协议讲的明明白白

    从字面意义上讲 xff0c 有人可能会认为 TCP IP 是指 TCP 和 IP 两种协议 实际生活当中有时也确实就是指这两种协议 然而在很多情况下 xff0c 它只是利用 IP 进行通信时所必须用到的协议群的统称 具体来说 xff0c I
  • TCP/IP协议与Http协议的区别详解

    TPC IP协议是传输层协议 xff0c 主要解决数据如何在网络中传输 xff0c 而HTTP是应用层协议 xff0c 主要解决如何包装数据 关于TCP IP和HTTP协议的关系 xff0c 网络有一段比较容易理解的介绍 xff1a 我们在
  • C#中使用MD5对用户密码加密与解密

    C 中常涉及到对用户密码的加密于解密的算法 xff0c 其中使用MD5加密是最常见的的实现方式 本文总结了通用的算法并结合了自己的一点小经验 xff0c 分享给大家 一 使用16位 32位 64位MD5方法对用户名加密 1 xff09 16
  • C#中修改文件或文件夹的权限,为指定用户、用户组添加完全控制权限

    写在前面 在windows系统中 xff0c c盘中的目录权限比较高 xff0c 有时制作安装包的时候 xff0c 默认的安装路径就是在c盘 xff0c 但对运行可执行文件 xff0c 有时候需要为其添加完全控制权限 xff0c 或者读写权
  • C#使用SafeNet的开发狗和超级狗加密使用方法

    1 在安装光盘中选择Windows文件夹 xff0c 单击Setup exe执行安装程序 xff0c 安装过程默认选择 xff0c 单击下一步即可 2 安装完毕后插入超级狗 xff0c 在菜单栏中打开 超级狗开发商向导 xff0c 选择下载
  • Keil5 新建工程编译后Download按钮变灰

    Keil5 新建工程编译后Download按钮变灰 百度看到很多文章解决变灰方法为 这个主要目的是生成 HEX文件 xff0c 但有时候当你在线下载时点了Creat HEX File 并进行编译后 Download按钮依然呈现灰色 此时问题
  • C# SQLite 数据库操作语句与文件视图管理器

    sqlite数据库视图管理器 SQLiteSpy是一款专业的SQLite数据库管理 xff0c 主要用于读取sqlite数据库 xff0c 建立新的SQL查询 xff0c 视图 xff0c 复制和删除表 编辑单元格 xff0c 以及查看索引
  • C#JSON与XML相互转换

    using System using System Collections Generic using System Linq using System Text using System Xml using Newtonsoft Json
  • 让使用SQLite的.NET应用自适应32位/64位系统

    Windows 7 64 bit 刚扩到4G内存 果断换64位的 那速度杠杠的 Microsoft Visual Studio 2010 Ultimate 32bit 在64位系统里运行正常 sqlite netFx40 setup bun
  • WinForm 布局控件“WeifenLuo.WinFormsUI.Docking“的使用

    本篇介绍Winform程序开发中的布局界面的设计 xff0c 介绍如何在我的共享软件中使用布局控件 34 WeifenLuo WinFormsUI Docking 34 布局控件 34 WeifenLuo WinFormsUI Dockin
  • C#中JSON和对象之间互相转换功能示例

    本文实例讲述了C 实现JSON和对象之间互相转换功能 分享给大家供大家参考 xff0c 具体如下 xff1a 1 首先是声明用户信息对象 xff0c DataContract修饰类 xff0c 表示可以被解析成JSON xff0c Data
  • C#使用DataContractJsonSerializer来进行JSON解析

    在使用DataContractJsonSerializer进行解析之前 xff0c 我们首先需要将两个包引入进来 xff1a using System Runtime Serialization using System Runtime S
  • 步进电机驱动器脉冲频率确定 步进电机驱动器

    1 步进电机为什么要配步进电机驱动器才能工作 xff1f 步进电机作为一种控制精密位移及大范围调速专用的电机 它的旋转是以自身固有的步距角角 xff08 转子与定子的机械结构所决定 xff09 一步一步运行的 其特点是每旋转一步 xff0c
  • MFC添加自定义消息及重写消息过程

    由于MFC中无法通过类向导来自定义消息 xff0c 所以需要手动添加 xff0c 主要过程如下 xff1a 本文基于vs2008下通过线程实现数据实时更新的对话框运用程序 1 定义消息 xff08 Resource h文件中 xff09 x
  • C#操作注册表方法

    1 xff1a 要操作注册表 xff0c 我们必须要引入必要的命名空间 xff1a using Microsoft Win32 在这个命名空间里面包含了许多注册表相关的类 xff0c 足够我们使用了 2 xff1a 命名空间里面提供了一个类
  • 怎样测试ESP8266wifi模块?

    这里测试的方法是用USB TTL转换电路进行的测试 接线图如下所示 xff1a ESP8266引脚图如下 xff1a 因为ESP8266需要3 3V电压供电 xff0c 所以USB TTL的3 3V电压 xff0c GND分别与ESP826
  • Qt信号与槽机制

    一 简介 就我个人来理解 xff0c 信号槽机制与Windows下消息机制类似 xff0c 消息机制是基于回调函数 xff0c Qt中用信号与槽来代替函数指针 xff0c 使程序更安全简洁 信号和槽机制是 Qt 的核心机制 xff0c 可以
  • QT中手动释放堆中的对象(new 出来的)

    Qt内存自动释放有两个前提条件 xff1a 1 必须是QObject的派生类 2 必须指定了parent对象 即 xff1a Qt 中 父亲被删除的时候会自动销毁他的孩子 所以如果New出来的并且没有父亲 那么则需要手动删除它 需要 xff
  • c++指针概念回顾

    前言 复杂类型说明 要了解指针 多多少少会出现一些比较复杂的类型 所以我先介绍一下如何完全理解一个复杂类型 要理解复杂类型其实很简单 一个类型里会出现很多运算符 他们也像普通的表达式一样 有优先级 其优先级和运算优先级一样 所以我总结了一下

随机推荐

  • c语言指针详解(概念示例)

    指针是 xff23 语言中广泛使用的一种数据类型 运用指针编程是 xff23 语言最主要的风格之一 利用指针变量可以表示各种数据结构 xff1b 能很方便地使用数组和字符串 xff1b 并能象汇编语言一样处理内存地址 xff0c 从而编出精
  • C#中模态对话框释放问题

    以下实例中可以测出 xff0c 当一个模态对话框返回DialogResult的结果后 xff0c 对话框自动隐藏 xff0c 但对话框db并没有彻底释放掉 xff0c 因此 仍可以访问db中的成员 xff0c 想要彻底释放需要手动加上db
  • qt中设置窗体大小

    在我们的编程中 xff0c 我们有时候会想让我们的程序窗体固定大小 xff0c 而该大小是我们在编辑时的大小 经过我的摸索 xff0c 和查阅资料 找到了一个方法 其实也很简单 其实也就是先找到该窗体的物理大小 然后设置固定窗体的大小即可
  • c++ (QT)笔记

    1 标准情况下 xff0c c 43 43 中的类声明都在头文件中 xff0c 实现在 cpp文件中 xff0c 所以只在 cpp中实现类的函数在头文件中没有声明会报错 c 43 43 的函数实现和声明都可放在头文件中这样 cpp文件也可访
  • C语言中指针动态内存的申请和释放

    什么是动态内存的申请和释放 xff1f 当程序运行到需要一个动态变量时 xff0c 需要向系统的堆中申请一块内存 xff0c 用来存储这块变量 xff0c 这就是内存的申请 当程序不需要这个变量时 xff0c 就需要把申请的这块内存释放掉
  • Qt中线程使用汇总

    QThread类提供一种独立于平台的线程管理方式 方法1 一个QThread实例管理程序中的一个线程 QThread的执行开始于run 默认情况下 xff0c run 通过调用exec 启动事件循环 xff0c 并在线程内运行Qt事件循环
  • 对线程与进程的区别以及对多线程并发的理解

    一 线程与进程的区别 先简单说说线程与进程的概念 xff1a xff08 1 xff09 进程是指一个内存中运行的应用程序 xff0c 比如在Windows系统中 xff0c 一个运行的exe就是一个进程 xff08 2 xff09 线程是
  • 单片机学习经验总结

    单片机的学习是嵌入式中的裸机开发 xff0c 也就是不基于操作系统的开发过程 xff0c 你只要把自己学的程序下载到单片机内执行即可 xff08 这个过程有个专业术语 xff1a 烧写 xff09 在这个过程中 xff0c 你所写的程序 x
  • 三极管的工作原理(详细、通俗易懂、图文并茂)

    一 很多初学者都会认为三极管是两个 PN 结的简单凑合 xff08 如图1 xff09 这种想法是错误的 xff0c 两个二极管的组合不能形成一个三极管 我们以 NPN 型三极管为例 xff08 见图 2 xff09 xff0c 两个 PN
  • 三极管工作原理图解,快速了解三极管结构和工作原理

    了解三极管工作原理前 xff0c 先看一张三极管内部结构原理图 xff1b 从图中可以清晰的看出NPN和PNP内部结构的区别 三极管NPN型和PNP型的工作原理 xff1a NPN三极管 xff1a Vb lt Ve xff08 截止状态
  • C# 获取进程或线程的信息

    using System using System Collections Generic using System Linq using System Text using System Diagnostics namespace Con
  • C#图片保存与读取,以及图片另存操作

    照片的保存与读取 lt summary gt 图片转二进制 lt summary gt lt param name 61 34 imgPhoto 34 gt 图片对象 lt param gt lt returns gt 二进制 lt ret
  • C#异常解决:在调用OLE之前,必须将当前线程设置为单线程单单元(STA)模式。

    问题来源 xff1a 昨晚上在调试数据库大作业的时候 xff0c 我在注册界面Register里点击 34 上传头像 34 这个linklabel时 xff0c 程序出现了一个异常 xff1a 在调用OLE之前 xff0c 必须将当前线程设
  • Qt调用OpenCV汇总(1)

    1 在Qt Creator上新建一个项目 右键新项目 gt gt 添加库 gt gt 外部库 gt gt 选中库文件路径 gt gt 下一步 xff0c 完成 xff0c 添加到 pro文件中 然后再在pro文件中手动输入下面代码 xff1
  • qt调用opencv汇总(2)

    OpenCV3 4 3 43 Qt5 9 4 QtCreator 开发环境搭建 之前有过对OpenCV3 4 2 43 VS2015编译及环境搭建 xff0c 今天使用OpenCV3 4 3 43 QtCreator5 9 4编译及环境搭建
  • 关于QT下配置OpenCV3.4.0后出现 error: undefined reference to ‘cv::xxx‘的问题及解决方案,直接使用编译好的opencv库

    按照网上的办法 xff0c 在QT中pro文件末尾添加以下代码来引入OpenCV的库和头文件 xff1a INCLUDEPATH 43 61 D OpenCV3 4 opencv build mingw install x64 mingw
  • C#实现最小二乘法

    根据http zh wikipedia org wiki E6 9C 80 E5 B0 8F E4 BA 8C E4 B9 98 E6 B3 95里面的说法 xff1a 线性函数模型 典型的一类函数模型是线性函数模型 最简单的线性式是 xf
  • C++动态(显式)调用 C++ dll示例

    1 创建DLL新项目Dll1 xff0c Dll1 cpp 1 extern 34 C 34 declspec dllexport const char myfunc 2 3 return 34 hello 34 4 生成后 xff0c 将
  • 用quagga建立BGP会话

    本文将讲述使用quagga建立一个BGP会话 本次测试拓扑 假设运营商A与运营商B建立BGP对等互联来交换路由 下面是她们的AS号和IP地址范围 xff1a 运营商 A AS38372 xff0c IP段 172 16 0 0 16 xff
  • c++中堆、栈内存分配概念示例讲解

    首先来看看主要有几种程序内存分配 xff1a 一个由C C 43 43 编译程序占用内存分为以下几个部分 1 栈区 xff08 stack xff09 由编译器自动分配释放 xff0c 存放函数参数值 xff0c 局部变量值等 其操作方式类