热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

定义结构体与分配内存

这几天在学习数据结构的时候经常会出现一个问题,就是定义了节点的结构,然后定义了指向节点的指针,但是已经定义了指针为什么就不能直接用呢,后来查了一下相关资料发现原来在新建指针的时候不会一同分配

这几天在学习数据结构的时候经常会出现一个问题,就是定义了节点的结构,然后定义了指向节点的指针,但是已经定义了指针为什么就不能直接用呢,后来查了一下相关资料发现原来在新建指针的时候不会一同分配内存给他,所以会出现非常严重的错误。即为当声明一个结构体指针时,为什么还有new(C++)或者malloc()这种语句?

问题描述:
主题:定义结构体指针时,有没有同时分配存储空间定义结构体指针时,有没有同时分配存储空间啊?
看到结构体的数组定义好以后就直接可以用了。但是结构体指针在链表中还要malloc()申请空间。这是为什么啊?

主要针对的就是这两个问题

下面来看一个例子

#include   
#include

struct data
{
int i;
int j;
};

int 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
return 0;
}
这里用gcc-32位编译器。如果是64位编译器则会出现不同。。这我还得研究下

运行的结果是这样的

如果把注释的两句话删去就会发现是错误的,原因就是没有给指针分配内存;

如果把结构体改为

 struct data
{
int i;
int j;
int x;
int y;
};
相对应的执行结果是


从这两个地方确实可以看得出来

结构体变量分配结构体本身大小的空间,结构体指针分配4个字节,其实任何类型的指针都是分配四个字节的指针空间。


#include   
#include

struct data
{
int i;
int j;
double x;
};

int main()
{
int a;
int *aa;
int a1[3];
int *a11[3];

double b;
double *bb;
double b1[3];
double *b11[3];

struct data p;
struct data *pp;
struct data p1[3];
struct data *p11[3];


printf("int:\t%d\n",sizeof(a));
printf("*int:\t%d\n",sizeof(aa));
printf("*int所指:\t%d\n",sizeof(*aa));
printf("int[3]:\t%d\n",sizeof(a1));
printf("*int[3]:\t%d\n",sizeof(a11));
printf("double:\t%d\n",sizeof(b));
printf("*double:\t%d\n",sizeof(bb));
printf("*double所指:\t%d\n",sizeof(*bb));
printf("double[3]:\t%d\n",sizeof(b1));
printf("*double[3]:\t%d\n",sizeof(b11));
printf("data:\t%d\n",sizeof(p));
printf("*data:\t%d\n",sizeof(pp));
printf("*data所指:\t%d\n",sizeof(*pp));
printf("data[3]:\t%d\n",sizeof(p1));
printf("*data[3]:\t%d\n",sizeof(p11));

printf("分配了内存空间\n");

//*aa=1;
//*bb=1;
//pp->i=0;
//pp->j=1;
//pp->x=2;


aa = (int*)malloc(sizeof(int)); //申请一个空间,把该空间地址给pdat1.
printf("*intmalloc:\t%d\n",sizeof(*aa));
bb = (double*)malloc(sizeof(double)); //申请一个空间,把该空间地址给pdat1.
printf("*doublemalloc:\t%d\n",sizeof(*bb));
pp = (struct data*)malloc(sizeof(struct data)); //申请一个空间,把该空间地址给pdat1.
printf("*datamalloc:\t%d\n",sizeof(*pp));

*aa=1;
*bb=1;
pp->i=0;
pp->j=1;
pp->x=2;
getchar();

return 0;
}
执行的结果是


虽然用malloc之前和之后两者指向的内存空间大小是相同的,但是

定义指针的时候确实会分配,但是是随机分配的,而且这个时候指针是不能使用的,因为你不知道分配的内存在哪,有没有内容,起码需要初始化下才能用。
        而malloc后指针会指向heap上的可用空间,这样就算函数被回收,指针还是指向正确的内容,因为指针指向堆上的内容,如果没有那一句malloc,程序会报错uninitialized local variable 'p' used。

指针被声明出来是会分配内存的,但是这块内存是不能用的,你需要把指针初始化,或者用malloc在内存上声明一块可用的空间。具体到这个程序,就是先声明一个指针类型的变量,然后给他在内存上分配一块可用的空间。如果没有malloc,编译器会认为你没有把指针初始化,也没有给他分配可用空间,就会报错



推荐阅读
  • BZOJ4240 Gym 102082G:贪心算法与树状数组的综合应用
    BZOJ4240 Gym 102082G 题目 "有趣的家庭菜园" 结合了贪心算法和树状数组的应用,旨在解决在有限时间和内存限制下高效处理复杂数据结构的问题。通过巧妙地运用贪心策略和树状数组,该题目能够在 10 秒的时间限制和 256MB 的内存限制内,有效处理大量输入数据,实现高性能的解决方案。提交次数为 756 次,成功解决次数为 349 次,体现了该题目的挑战性和实际应用价值。 ... [详细]
  • 如何利用正则表达式(regexp)实现高效的模式匹配?本文探讨了正则表达式在编程中的应用,并分析了一个示例程序中存在的问题。通过具体的代码示例,指出该程序在定义和使用正则表达式时的不当之处,旨在帮助读者更好地理解和应用正则表达式技术。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 分享一款基于Java开发的经典贪吃蛇游戏实现
    本文介绍了一款使用Java语言开发的经典贪吃蛇游戏的实现。游戏主要由两个核心类组成:`GameFrame` 和 `GamePanel`。`GameFrame` 类负责设置游戏窗口的标题、关闭按钮以及是否允许调整窗口大小,并初始化数据模型以支持绘制操作。`GamePanel` 类则负责管理游戏中的蛇和苹果的逻辑与渲染,确保游戏的流畅运行和良好的用户体验。 ... [详细]
  • 本文对常见的字符串哈希函数进行了全面分析,涵盖了BKDRHash、APHash、DJBHash、JSHash、RSHash、SDBMHash、PJWHash和ELFHash等多种算法。这些哈希函数在不同的应用场景中表现出各异的性能特点,通过对比其算法原理、计算效率和碰撞概率,为实际应用提供了有价值的参考。 ... [详细]
  • 开发笔记:实现1353表达式中的括号匹配(栈的应用) ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • 本文探讨了如何利用Java代码获取当前本地操作系统中正在运行的进程列表及其详细信息。通过引入必要的包和类,开发者可以轻松地实现这一功能,为系统监控和管理提供有力支持。示例代码展示了具体实现方法,适用于需要了解系统进程状态的开发人员。 ... [详细]
  • QT框架中事件循环机制及事件分发类详解
    在QT框架中,QCoreApplication类作为事件循环的核心组件,为应用程序提供了基础的事件处理机制。该类继承自QObject,负责管理和调度各种事件,确保程序能够响应用户操作和其他系统事件。通过事件循环,QCoreApplication实现了高效的事件分发和处理,使得应用程序能够保持流畅的运行状态。此外,QCoreApplication还提供了多种方法和信号槽机制,方便开发者进行事件的定制和扩展。 ... [详细]
  • 本文介绍了如何利用ObjectMapper实现JSON与JavaBean之间的高效转换。ObjectMapper是Jackson库的核心组件,能够便捷地将Java对象序列化为JSON格式,并支持从JSON、XML以及文件等多种数据源反序列化为Java对象。此外,还探讨了在实际应用中如何优化转换性能,以提升系统整体效率。 ... [详细]
  • 在Linux系统中,通过使用`read`和`write`函数可以实现文件的高效复制操作。`open`函数用于打开或创建文件,其返回值为文件描述符,成功时返回一个有效的文件描述符,失败时返回-1。`path`参数指定了要操作的文件路径,而`oflag`参数则定义了文件的打开模式和属性。此外,为了确保数据的完整性和一致性,还需要合理处理文件读取和写入过程中的错误和异常情况。 ... [详细]
  • 基址获取与驱动开发:内核中提取ntoskrnl模块的基地址方法解析
    基址获取与驱动开发:内核中提取ntoskrnl模块的基地址方法解析 ... [详细]
  • 揭秘腾讯云CynosDB计算层设计优化背后的不为人知的故事与技术细节
    揭秘腾讯云CynosDB计算层设计优化背后的不为人知的故事与技术细节 ... [详细]
  • GDB 使用心得与技巧总结
    在使用 GDB 进行调试时,可以采用以下技巧提升效率:1. 通过设置 `set print pretty on` 来美化打印输出,使数据结构更加易读;2. 掌握常见数据结构的打印方法,如链表、树等;3. 利用 `info locals` 命令查看当前作用域内的所有局部变量;4. 在需要进行类型强制转换时,正确使用语法,例如 `p (Test::A *) pObj`。这些技巧能够显著提高调试的便捷性和准确性。 ... [详细]
  • 深入解析 ELF 文件格式与静态链接技术
    本文详细探讨了ELF文件格式及其在静态链接过程中的应用。在C/C++代码转化为可执行文件的过程中,需经过预处理、编译、汇编和链接等关键步骤。最终生成的可执行文件不仅包含系统可识别的机器码,还遵循了严格的文件结构规范,以确保其在操作系统中的正确加载和执行。 ... [详细]
author-avatar
我的明天谁2502931447
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有