C/C++ 类型内存占用详解

最近做一些面试题目碰到了很多次考察C/C++类型内存占用的题目,主要考察队C/C++的指针、类型等的熟悉程度。

本blog为了方面大家参考,总结了常见的类型内存占用的情况,能力所限,若有问题,请指出!

1. 基本类型

C/C++的基本类型包括int/long等等,这些基本类型在内存中的字节数一般是固定的(当然根据不同bit的系统有所调整),下表是基本类型的占用字节数。

PS: 1byte=8bit, byte通常写成大写B, bit一般写为小写b

下表单位均为Byte

System char short int long long long float dobule void *
(任意类型指针)
32bit 1 2 4 4 8 4 8 4
64bit 1 2 4 8 8 4 8 8

不信?我们以代码说话:

#include <iostream>

using namespace std;

int main()
{

    cout<<"sizeof(char)="<<sizeof(char)<<endl;
    cout<<"sizeof(short)="<<sizeof(short)<<endl;
    cout<<"sizeof(int)="<<sizeof(int)<<endl;
    cout<<"sizeof(unsigned int)="<<sizeof(unsigned int)<<endl;
    cout<<"sizeof(long)="<<sizeof(long)<<endl;
    cout<<"sizeof(long long)="<<sizeof(long long)<<endl;
    cout<<"sizeof(float)="<<sizeof(float)<<endl;
    cout<<"sizeof(double)="<<sizeof(double)<<endl;

    //Poiter type
    cout<<endl;
    cout<<"sizeof(void *)="<<sizeof(void *)<<endl;
    cout<<"sizeof(char *)="<<sizeof(char *)<<endl;
    cout<<"sizeof(int *)="<<sizeof(int *)<<endl;
    cout<<"sizeof(float *)="<<sizeof(float *)<<endl;
    cout<<"sizeof(double *)="<<sizeof(double *)<<endl;

    return 0;
}

结果如下(我的系统是64bit的):

可以看到,任意类型的指针的位数皆为8byte,即与系统位数保持一致,因此,判断系统的位数我可以直接用sizeof(void *).

2. 复杂类型

编程时,有时我们会碰到如下情况:

  • int *p[n]
  • int (*p)[n]

以上两者到底有什么区别呢?

下面我们先看一下代码:

#include <iostream>

using namespace std;

struct A
{
    int a;
    int b;
    long c;
    long d;
};

int main()
{
    //Complex type
    cout<<endl;

    int p1[5] = {1,2,3,4,5};    //①.P1相关
    //int *p1 = &p1+1;      //It‘s warning in c but error in C++
    cout<<"sizeof(p1)="<<sizeof(p1)<<endl;
    cout<<"sizeof(&p1)="<<sizeof(&p1)<<endl;
    cout<<"*(p1+1) = "<<*(p1+1)<<endl;

    cout<<endl;
    int *p2[3];             //②.P2相关
    int a[10] = {0};
    int b[10] = {0};
    int c[10] = {0};
    p2[0] = a;
    p2[1] = b;
    p2[2] = c;

    cout<<"int *p2[3], sizeof(p2)="<<sizeof(p2)<<endl;
    cout<<"int *p2[3], sizeof(&p2)="<<sizeof(&p2)<<endl;

    cout<<endl;
    int (*p3)[4];       //③.P3相关
    int d[3][4]={0};
    p3=d;
    cout<<"sizeof(p3)="<<sizeof(p3)<<endl;
    cout<<"sizeof(p3[0])="<<sizeof(p3[0])<<endl;

    return 0;
}

①. P1 : 数组

  • p1为一维数组的数组名,包含五个int型元素
  • p1虽然数值上与&p1[0]相等,但是两者不是一个东西(&p1[0]是第一个元素的地址)
  • p1+1 其实就是 &p1[1]

②. P2 : 数组指针 (int *p2[n])

[]的优先级高于*,因此先p2[3],即p2先是一个数组,然后与*结合,*p2[n]即成了数组指针(数组内部存放的内容皆为指针)

③. P3 : 指针数组(int(*p3)[n])

int (p3)[n],由于()优先级大于[],所以先(p3),后为数组,即p3所指向的对象是有n个int型元素的数组,即p3是指向一维数组的指针;p3的值即为该一维数组的地址。

以上,相当于二维数组。

结果:

根据以上讲解,你是否已经得出答案?

3. 函数相关

有的时候,我们还会遇到以下的情况:

  • int *p() : 返回指针的函数
  • int (*p)() : 指向函数的指针

①. int *p() 指针函数

实际上,它就是一个函数,只不过返回类型为指针而已,和普通函数没什么区别的。

#include <iostream>
#include <cstring>

using namespace std;

char *array()
{
    auto ptr = new char(10);
    ptr="hello";
    return ptr;
}

int main()
{
    char *pt = array();
    cout<<pt<<endl;

    return 0;
}

②. int (*p)(): 函数指针

指向函数的指针变量,其本质是一个指针。

int (*fptr)(int x); /*声明一个函数指针*/

fptr = func; /*将func函数的首地址赋给该指针*/

每个函数都有一个入口地址,将该入口地址赋值给一个指针,通过该指针即可以调用这个函数。

#include <stdio.h>

void (*ptr)(char *str);

void prt1(char *str)
{
    printf("ptr1 string=%s\n", str);
    return ;
}

void prt2(char *str)
{
    printf("ptr2 string=%s\n", str);
    return ;
}

int main()
{
    ptr = prt1;
    (*ptr)("hello");

    ptr = prt2;
    (*ptr)("world");

    return 0;
}

特别类似于C++的多态是不是?

③. 函数的形式参数

有时候,我们函数的形参需要为指针,这个时候,其实我们可以有多重写法

  • void *func(char *str)
  • void *func(char str[])
  • void *func(char str[n])

以上三种写法一个意思,即使n小于实参的字节数也无妨,此处的n只是一个提示作用而已。

原文地址:https://www.cnblogs.com/Jimmy1988/p/8338131.html

时间: 2024-10-16 10:06:04

C/C++ 类型内存占用详解的相关文章

20150222 IO端口映射和IO内存映射(详解S3C24XX_GPIO驱动)

20150222 IO端口映射和IO内存映射(详解S3C24XX_GPIO驱动) 2015-02-22 李海沿 刚刚我们实现了linux系统内存的分配,读写,释放功能,下面,我们一鼓作气将IO端口映射及IO内存映射搞定,加油! (一)地址的概念 1)物理地址:CPU地址总线传来的地址,由硬件电路控制其具体含义.物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上(如显存.BIOS等).在程序指令中的虚拟地址经过段映射和页面映射后,就生成了物理地址,这个物理地址被放到CPU的地址

java内存泄露详解

很多人有疑问,java有很好的垃圾回收机制,怎么会有内存泄露?其实是有的,那么何为内存泄露?在Java中所谓内存泄露就是指在程序运行的过程中产生了一些对象,当不需要这些对象时,他们却没有被垃圾回收掉,而且程序运行中很难发现这个对象,它始终占据着内存却没有发挥作用. 我举这样一个例子,在现实开发中我们需要自定义一个先进后出的栈集合,代码如下: 这个代码看起来和运行起来都没问题,但是,这里有个很隐晦的问题,就是在pop()方法里面,我们首先找到集合最后一个元素的下标,然后按照下标从集合中取出,但是这

【转载】图说C++对象模型:对象内存布局详解

原文: 图说C++对象模型:对象内存布局详解 正文 回到顶部 0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看.本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有所不同.文章如果有解释不清.解释不通或疏漏的地方,恳请指出. 回到顶部 1.何为C++对象模型? 引用<深度探索C++对象模型>这本书中的话: 有两个概念可以解释C++对象模型: 语言中直接支持面向对象程序设计的部分. 对于各种支持的底层

Tomcat内存设置详解

Java内存溢出详解 一.常见的Java内存溢出有以下三种: 1. java.lang.OutOfMemoryError: Java heap space ----JVM Heap(堆)溢出JVM在启动的时候会自动设置JVM Heap的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)不可超过物理内存. 可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置.Heap的大小是Young Generation 和Tenured Generaion 之和. 在JVM中如

Java-Tomcat内存溢出详解

Java内存溢出详解 一.常见的Java内存溢出有以下三种: 1. java.lang.OutOfMemoryError: Java heap space ----JVM Heap(堆)溢出JVM在启动的时候会自动设置JVM Heap的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)不可超过物理内存. 可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置.Heap的大小是Young Generation 和Tenured Generaion 之和. 在JVM中如

C语言的代码内存布局详解

一个程序本质上都是由 BSS 段.data段.text段三个组成的.这样的概念在当前的计算机程序设计中是很重要的一个基本概念,而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分配,存储单元占用空间大小的问题. BSS段:在采用段式内存管理的架构中,BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS段属于静态内存分配. 数据段:在采用段式内存管理的架构中,数据段(da

Java虚拟机(JVM)中的内存设置详解

在一些规模稍大的应用中,Java虚拟机(JVM)的内存设置尤为重要,想在项目中取得好的效率,GC(垃圾回收)的设置是第一步. PermGen space:全称是Permanent Generation space.就是说是永久保存的区域,用于存放Class和Meta信息,Class在被Load的时候被放入该区域Heap space:存放Instance. GC(Garbage Collection)应该不会对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS的话,就很

[转]Java内存溢出详解及解决方案

原文地址:http://blog.csdn.net/xianmiao2009/article/details/49254391 内存溢出与数据库锁表的问题,可以说是开发人员的噩梦,一般的程序异常,总是可以知道在什么时候或是在什么操作步骤上出现了异常,而且根据堆栈信息也很容易定位到程序中是某处出现了问题.内存溢出与锁表则不然,一般现象是操作一般时间后系统越来越慢,直到死机,但并不能明确是在什么操作上出现的,发生的时间点也没有规律,查看日志或查看数据库也不能定位出问题的代码. 更严重的是内存溢出与数

Apache Spark 内存管理详解

Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色.理解 Spark 内存管理的基本原理,有助于更好地开发 Spark 应用程序和进行性能调优.本文旨在梳理出 Spark 内存管理的脉络,抛砖引玉,引出读者对这个话题的深入探讨.本文中阐述的原理基于 Spark 2.1 版本,阅读本文需要读者有一定的 Spark 和 Java 基础,了解 RDD.Shuffle.JVM 等相关概念. 在执行 Spark 的应用程序时,Spark 集群会启动 Driver