定义一个结构体指针需要分配存储空间?

 

 

前言

问题的来源于在学数据结构的时候,C++的语法和C语言的语法竟然不一样。

1.首先函数的参数有两种传递方式,一个是值传递,一个是地址传递。当指针作为参数传递的时候,即为地址传递,但C++写的时候需要加&引用符号,而C语言却不用。

2.本文谈的是这个问题,即为当声明一个结构体指针时,为什么还有new(C++)或者malloc()这种语句,一直搞不清楚,后台问bb,然后百度了一下,才明白

正文

看到一篇文章是这么写的
问题描述:
主题:定义结构体指针时,有没有同时分配存储空间
定义结构体指针时,有没有同时分配存储空间啊?
看到结构体的数组定义好以后就直接可以用了。
但是结构体指针在链表中还要malloc()申请空间。
这是为什么啊?
1楼
定义结构体指针时并没有分配存储空间,所以要用malloc()申请空间。
2楼
很明显,你还没有搞清楚什么是指针,至于结构体变量和结构体指针,更是很混淆,所以这里不是因为数组的问题。
举个例子:
 
//下面仅仅是定义一个类型,不会产生变量,所以不存在分配空间的问题
struct data
{
    int i;
    int j;
};

void main(void)
{
    struct data dat1; //定义一个struct data类型的变量,和int i同理。
    printf("%d\n", sizeof(struct data)); //8个字节
    printf("%d\n", sizeof(dat1));        //8个字节

    struct data* pdat1;//定义一个struct data类型的指针,和int *pi 同理。
    printf("%d\n", sizeof(pdat1));        //4个字节,就是一个指针的空间,pdat1并没有结构体变量的信息。

    pdat1 = (struct data*)malloc(sizeof(struct data)); //申请一个空间,把该空间地址给pdat1.
    printf("%d\n", sizeof(*pdat1));      //8个字节

    struct data dats1[2]; 
    printf("%d\n", sizeof(dats1));     //16个字节,两个data变量,不是data指针。
    dats1[0].i = 20;  //可以直接使用数组里面的结构体变量
    dats1[0].j = 30;
    
    struct data* dats2[2]; //指针数组,包含两个指针,而不是结构体变量
    printf("%d\n", sizeof(dats2));  //8个字节,两个指针的大小
    dats2[0]->i = 20; //错误!还没有给dats2[0] 指针分配空间
    dats2[0]->i = 20; //错误!还没有给dats2[0] 指针分配空间
    dats2[0] = (struct data*)malloc(sizeof(struct data)); //分配空间
    dats2[0]->i = 20; //ok
    dats2[0]->i = 20; //ok
}

 

3楼
声明任何对象并定义变量,包括指针都会开辟空间,除了静态成员在一个特别的区,其他的在栈上开辟空间,不用了自动清理,用malloc, realloc, calloc, new new[]开辟空间是动态分配空间,在堆上进行。值得说明的是,栈空间很小(相对于堆而言),很"昂贵",但是通常执行更快。


在Windows下,一个进程的栈在最高端,向下增长,堆在栈下面,向栈的方向增长,下面是数据和代码。Linux下内存布局由开发工具和操作系统合作负责,这四个部分相对位置布局不确定。


Windows下一个进程的线性地址空间布局:


--------------------
                   |
                   |
栈                 V
                   V
                   V
--------------------
                   ^
                   ^
堆                 |
                   |
                   |
--------------------


其他
4楼
windows默认栈大小是1M
栈和堆是共享一内存的,可以调节它们的比例。来设置栈和堆的大小。
不过一般情况下,还是用不着的。。
5楼
[quote]
有人告诉我:
A a[3];  a是A型的,有3个,当然分配A乘3大小的空间
A* a;    a是A*型的,当然只分配A*大小的空间,而不会分配A大小的空间


好像跟你说的不太一样,结构体数组的话,我在课本里看到的确不用再次申请空间了啊[/quote]


结构体变量分配结构体本身大小的空间,结构体指针分配4个字节,其实任何类型的指针都是分配四个字节的指针空间。
所以:
A a[3]; //a里面是三个A变量,所以分配三个结构体大小
A *a;  //a是一个指针,分配4个字节,就算A再大,a也只是4个字节,因为任何类型的指针都是4个字节。要使用a,必须先要对指针初始化,也即分配空间了。
如:
A *a;
a = (A*)malloc(sizeof(A));

我们完全可以撇开结构体,把问题简单化成int类型来说明这个指针问题:
int a1[10];
int *a2;

很容易知道,a1是包含10个int的数组,大小也就是10*sizeof(int)。我们可以直接使用a1不要在进行什么初始化或者分配空间的游戏,因为数组a1里面本身存放的就是int变量本身了。

然后a2,是一个int*的东西,也就是整型指针,a2不能存放int变量,它只能存放地址,一个int变量的地址。如果要使用a2,必须首先对a2初始化,即将它指向一个int变量的地址,如:
a2 = (int*)malloc(sizeof(int));
或者
int i = 10;
a2 = &i;
所以,malloc函数的作用是首先声明一个变量,然后返回该变量的地址。
所以:a2 = (int*)malloc(sizeof(int)) 的含义就是把该变量的地址赋值给a2,和a = &i 本质上并没有什么不同,只是一个变量是栈上,一个是堆上,都是一个地址赋值。

所以,所谓的分配空间,就是对指针赋值,把一个变量的地址赋值给一个指针。
 
----------我是萌萌哒分割线----------
 
很明显三楼和四楼讲的有点底层了,不过其他楼层说的很明白,首先只是分配了指针本身的存储空间,指针指针还没有被赋值,通过new或者malloc()语句是为了给结构体变量分配内存空间,即为指针赋值,即指针指向的内容的信息,便有了指针指向的数据内容和空间。
 
----------我是萌萌哒分割线---------- 
 
原文地址:http://bbs.pfan.cn/post-284115.html
  • 60
    点赞
  • 139
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
C语言各种常用关键字详细解释学习,都是总结面试,都是比较好的笔试题。 1 变量 3 1.1 全局变量,局部变量,,常量分别保存在内存中的什么地方? 3 1.2 不同类型的变量,你是否知道其作用域? 3 1.3 全局变量和局部变量是否可以重名?你是否在这样做? 3 1.4 局部变量在函数退出后是否有效,为什么? 3 1.5 全局变量为什么不允许定义在头文件中?有何危害? 3 2 Static 4 2.1 static的三个主要作用是什么? 4 2.2 static的修饰的局部变量是保存在什么地方的?全局变量哪? 5 2.3 static修饰的全局变量和函数,在其他的文件中是否可以访问?如何访问? 5 2.4 你知道static是c语言中实现封装和隐藏的利器吗?你是否经常使用? 5 2.5 定义在不同源文件中的static全局变量,编译器是否允许他们的变量名称相同? 5 2.6 你是否知道auto、extern、register、volatile、restrict、inline的用法? 6 3 const 6 3.1 你是否经常使用const来表明不能够被更改的变量? 6 3.2 你是否经常使用const常量来代替宏? 6 3.3 下面四种情况,你知道是各表示什么意思吗? 6 3.4 你知道const常量如何初始化吗? 7 4 enum枚举 7 4.1 到底enum所定义出来的类型是一个什么样的类型呢? 7 4.2 作为一个用户自定义的类型其所占用的内存空间是多少呢? 8 4.3 是否可以指定枚举中各项的值? 8 4.4 如果不指定值,枚举的第一个值是多少? 8 4.5 枚举的值是否可以是负数? 8 4.6 定义枚举的候,你是否专门定义了枚举的最小值和最大值? 9 5 switch 9 5.1 switch(c)中的c的数据类型有哪些? 9 5.2 你是否在所有的switch中都加了default语句? 9 5.3 是否在所有的case中都加了break语句(一般情况的做法)?如果你不加break,将发生什么? 9 6 sizeof 9 6.1 对于字符数组,strlen和sizeof的值是否相同? 9 6.2 Sizeof本质上是什么?函数?宏?其他? 9 6.3 Sizeof的返回值是什么类型? 10 7 动态分配内存 10 7.1 动态分配的内存是保存在什么地方的? 10 7.2 什么情况下使用动态分配内存? 10 7.3 动态申请内存一定要释放,否则内存泄露。你是否使用过内存检测工具? 10 8 字符串 10 8.1 strlen()函数的返回值是什么类型的? 10 8.2 字符串strlen() 的值,是否和他占据的内存空间相同? 10 8.3 你是否知道strcpy 函数存在的潜在风险?如何避免? 11 8.4 如果一个字符串没有字符串结束符,而调用str 开头的库函数,发生什么? ?? 11 8.5 Strcpy(),strcat(),strcmp(),strncpy(),strncat(),strncmp()内部到底是如何运行的?这些函数到底对源字符串和目标字符串做了些什么?你是否观察过它们运行两个字符串内存的变化? 11 8.6 上面这些函数使用,各有哪些需要注意的地方? 11 8.7 你几种字符串查找操作? 11 8.8 C语言中有字符串这个数据类型吗? 11 8.9 对字符串进行操作的候,是否为字符串结尾符预留存储位置?不然的话容易造成非常访问内存。 11 9 数组 12 9.1 你肯定知道,定义“int a[10]; ”, a[10] 这个元素是无效的。 12 9.2 你知道几种数组初始化的方法? 12 9.3 数组和指针有千丝万缕的联系而又不同,你是否对他们在不同情况下的使用进行过详细的总结? 12 9.4 “int calendar[10][20]; ”,这是一个什么样的数组?它拥有 10 数组类型的元素,还是 20 个? 12 9.5 “int a[10]; ”,数组名 a 在本质上是一个什么?你是否打印过 a 的值? 12 9.6 你知道几种获取数组某元素的方法? 12 9.7 指针和数组相同吗?什么候相同?什么候不同? 12 9.8 用指针和下标访问数组元素,那种方式更快? 16 10 结构体 16 10.1 你知道什么是位域结构体吗?如何定义它?如何使用它? 16 10.2 你知道字节对齐对结构体占用内存空间大小的影响吗?如何计算结构体占用内存的小? 17 11 宏 19 11.1 你知道宏的本质是什么吗?函数?语句?类型定义?或者其他? 19 11.2 你知道语言设计者为什么设计宏吗?这些原因目前是否仍然成立? 19 11.3 你设计带有参数的宏吗? 19 11.4 你知道使用宏的参数的的候的注意事项吗? 19 11.5 你设计带有可变参数的宏吗? 19 11.6 你知道使用宏有什么劣势吗? 20 11.7 你有没有更好的替代方案? 20 11.8 为什么说宏定义不好? 21 12 如何避免对同一头文件的多次include? 22 13 什么是声明,什么是定义? 22 14 你是否运用c语言声明的优先级规则? 23 15 什么是预编译,何需要预编译? 23 Total time: 90 minutes 23 16 指针数组和数组指针的区别? 30 16.1 指针的声明 30 16.1.1 一维数组 31 16.1.2 多维数组 32 16.1.3 指针数组 33 16.1.4 指针的指针 33
C++智能指针详解 1、概述 我们知道除了静态内存和栈内存外,每个程序还有⼀个内存池,这部分内存被称为⾃由空间或者堆。程序⽤堆来存储动态分配的对象即那些 在程序运⾏分配的对象,当动态对象不再使⽤,我们的代码必须显式的销毁它们。 在C++中,动态内存的管理是⽤⼀对运算符完成的:new和delete。 new:在动态内存中为对象分配⼀块空间并返回⼀个指向该对象的指针; delete:指向⼀个动态独享的指针,销毁对象,并释放与之关联的内存。 动态内存管理经常出现两种问题: (1)⼀种是忘记释放内存,造成内存泄漏; (2)⼀种是尚有指针引⽤内存的情况下就释放了它,就产⽣引⽤⾮法内存的指针。 为了更加容易(更加安全)的使⽤动态内存,引⼊了智能指针的概念。智能指针的⾏为类似常规指针,重要的区别是它负责⾃动释放所指向 的对象。 标准库提供的两种智能指针的区别在于管理底层指针的⽅法不同:shared_ptr和unique_ptr。 (1)shared_ptr允许多个指针指向同⼀个对象; (2)unique_ptr则"独占"所指向的对象。 标准库还定义了⼀种名为weak_ptr的伴随类,它是⼀种弱引⽤,指向shared_ptr所管理的对象,这三种智能指针都定义在memory头⽂件 中。 2、auto_ptr (不要使⽤的指针) (1)内部⼤概实现:做成⼀个auto_ptr类,包含原始指针成员。 当auto_ptr类型的对象被释放,利⽤析构函数,将拥有的原始指针delete掉。 //⼤概长这个样⼦(简化版) template<class T> class auto_ptr {   T* ptr; }; (2)⽰例⽤法: void runGame() { std::auto_ptr<Monster> monster1(new Monster());//monster1 指向 ⼀个怪物 monster1->doSomething();//怪物做某种事 }//runGame函数执⾏完,monster1被释放,然后它的析构函数也把指向的⼀个怪物释放了 复制auto_ptr对象,把指针指传给复制出来的对象,原有对象的指针成员随后重置为nullptr。 这说明auto_ptr是独占性的,不允许多个auto_ptr指向同⼀个资源。 void runGame() { std::auto_ptr<Monster> monster1(new Monster());//monster1 指向 ⼀个怪物 monster1->doSomething(); //怪物做某种事 std::auto_ptr<Monster> monster2 = monster1; //转移指针 monster2->doSomething(); //怪物做某种事 monster1->doSomething(); //Oops!monster1智能指针指向了nullptr,运⾏期崩溃。 } 注意: 虽然本⽂简单介绍了auto_ptr。 但是不要⽤auto_ptr! 不要⽤auto_ptr! 虽然它是c++11以前的最原始的智能指针,但是在c++11中已经被弃⽤(使⽤的话被警告)了。 它的替代品,也就是c++11新智能指针unique_ptr,shared_ptr,weak_ptr。 3、shared_ptr(⼀种强引⽤指针) 多个shared_ptr指向同⼀处资源,当所有shared_ptr都全部释放,该处资源才释放。 (有某个对象的所有权(访问权,⽣命控制权) 即是 强引⽤,所以shared_ptr是⼀种强引⽤型指针) (1)内部⼤概实现:每次复制,多⼀个共享同处资源的shared_ptr,计数+1。每次释放shared_ptr,计数-1。 当shared计数为0,则证明所有指向同⼀处资源的shared_ptr们全都释放了,则随即释放该资源(哦,还释放new出来的 SharedPtrControlBlock)。 //shared计数放在这个结构体⾥⾯,实际上结构体⾥还应该有另⼀个weak计数。下⽂介绍weak_ptr解释。 struct SharedPtrControlBlock {   int shared_count; }; //⼤概长这个样⼦(简化版) template<class T> class shared_ptr {   T* ptr;   SharedPtrControlBlock* count; }; (2)⽰例⽤法: void runGame() {   std::shared_ptr<Monster> monster1(new Monster());  //计数加到1  do{ std::shared_ptr<Monster> monster

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值