***************************************************

更多精彩,欢迎进入:http://shop115376623.taobao.com

***************************************************

记得上周在饭桌上和同事讨论C语言的崛起时,讲到了内存管理方面
我说所有指针使用前都必须初始化,结构体中的成员指针也是一样
有人反驳说,不是吧,以前做二叉树算法时,他的左右孩子指针使用时难道有初始化吗
那时我不知怎么的想不出理由,虽然我还是坚信要初始化的

过了几天这位同事说他试了一下,结构体中的成员指针不经过初始化是可以用(左子树和右子树指针)
那时在忙着整理文档,没在意
今天抽空调了一下,结论是,还是需要初始化的。
而且,不写代码你是不知道原因的(也许是对着电脑久了IQ和记性严重下跌吧)
测试代码如下

  1. #include
  2. #include
  3. #include
  4. struct student{
  5. char *name;
  6. int score;
  7. struct student* next;
  8. }stu,*stu1;
  9. int main(){
  10. stu.name = (char*)malloc(sizeof(char)); /*1.结构体成员指针需要初始化*/
  11. strcpy(stu.name,"Jimy");
  12. stu.score = 99;
  13. stu1 = (struct student*)malloc(sizeof(struct student));/*2.结构体指针需要初始化*/
  14. stu1->name = (char*)malloc(sizeof(char));/*3.结构体指针的成员指针同样需要初始化*/
  15. stu.next  = stu1;
  16. strcpy(stu1->name,"Lucy");
  17. stu1->score = 98;
  18. stu1->next = NULL;
  19. printf("name %s, score %d \n ",stu.name, stu.score);
  20. printf("name %s, score %d \n ",stu1->name, stu1->score);
  21. free(stu1);
  22. return 0;
  23. }
#include
#include
#include struct student{char *name;int score;struct student* next;
}stu,*stu1; int main(){     stu.name = (char*)malloc(sizeof(char)); /*1.结构体成员指针需要初始化*/strcpy(stu.name,"Jimy");stu.score = 99;stu1 = (struct student*)malloc(sizeof(struct
student));/*2.结构体指针需要初始化*/stu1->name =
(char*)malloc(sizeof(char));/*3.结构体指针的成员指针同样需要初始化*/stu.next  = stu1;strcpy(stu1->name,"Lucy");stu1->score = 98;stu1->next = NULL;printf("name %s, score %d \n ",stu.name, stu.score);printf("name %s, score %d \n ",stu1->name, stu1->score);free(stu1);return 0;
}

写测试代码的过程中我明白了,同事所说的二叉树遍历算法中所用的左子树和右子树指针不需要初始化,其实是这样的,左子树和右子树指向的必须是二叉树节点类型的结构体指针(你填一个长度相同的指针也可以),而该结构体指针是需要初始化的(见注释2),也就是并没有通过malloc来分配内存,而是将另一个指针的值赋给它

顿时觉得挺无语的,确实,看了很多大学里的教材,对于二叉树的遍历等算法定义的结构体无非是以下形式

  1. struct node{
  2. int data;
  3. struct node* lchild, rchild;
  4. };
struct node{int data;struct node* lchild, rchild;
};

使用时都直接的

  1. struct node* root;
  2. root = (struct node*)malloc(sizeof(struct node));
  3. root->data = 3;
  4. struct node* nlchild;
  5. nlchild = (struct node*)malloc(sizeof(struct node));
  6. root->lchild = nlchild;
  7. nlchild->data = 2;
  8. struct node* nrchild;
  9. nlrchild = (struct node*)malloc(sizeof(struct node));
  10. root->rchild = nrchild;
  11. nrchild->data = 4;
 struct node* root;root = (struct node*)malloc(sizeof(struct node));root->data = 3;struct node* nlchild;nlchild = (struct node*)malloc(sizeof(struct node));root->lchild = nlchild;nlchild->data = 2; struct node* nrchild;nlrchild = (struct node*)malloc(sizeof(struct node));root->rchild = nrchild;nrchild->data = 4;

这样子给人造成一种错觉好像结构体成员指针是不用初始化的。

可是,只要是指针,要使用它前就必须保证指针变量的值是一个有效的值;否则,它指向的内存一定是垃圾数据!
C语言的内存管理很重要,集魄力和麻烦于一身,看你自己的心态如何了。如果你积极的面对,你正在控制一切;如果你觉得烦躁,你正不得不控制一切。C仍旧是博大精深的语言,信C哥!

/*附加:仍旧是指针*/

  1. stu1 = (struct student*)malloc(sizeof(struct student));/*2.结构体指针需要初始化*/
  stu1 = (struct student*)malloc(sizeof(struct
student));/*2.结构体指针需要初始化*/

这一句可能会有人把sizeof里边也填成struct student*
可以理解这样的行为,因为stu本来就是struct student*,可是这样子你就没有为结构体分配足够的内存,使用中会因为内存错误同样报错的。
当然,仅仅为结构体指针分配内存还不够,结构体成员指针仍然需要分配内存,如下

  1. stu1->name = (char*)malloc(sizeof(char));

自己在用结构体指针的时候遇到的引用问题,网上找的一段文字觉得挺不错的,可能对大家有帮助。

在使用结构体指针变量的时候,往往容易犯一个“低级”错误。即定义一个结构体指针变量后就直接对结构体指针变量所指向的结构体成员进行操作,从而产生一些莫名其妙的错误。我们必须要给结构体指针变量赋予一个有效的结构体变量地址,才能正常操作结构体指针变量。比如:

struct UART{

int a;

uchar b;

}

main()

{

struct UART  *p;

p->a = 0xXXX;

p->b = 0xXX;

printf("%i,%c",p->b,p->a);

}

这个程序输出的值将是不可预知的,因为“在程序中只是定义了一个结构体指针变量,并没有给该结构体指针变量赋一个有效值,因此该结构体变量所指向的地址将不确定,从而不能得到预期结果”

应该改为:

struct UART{

int a;

uchar b;

}

main()

{

struct UART  *p;

struct UART dd;

p = ⅆ               //这句一定要有,否则将出现不可预知的问题

p->a = 0xXXX;

p->b = 0xXX;

printf("%i,%c",p->b,p->a);

}

C/C++中

结构体(struct)知识点强化 为了进一部的学习结构体这一重要的知识点,我们今天来学习一下链表结构。

  结构体可以看做是一种自定义的数据类型,它还有一个很重要的特性,就是结构体可以相互嵌套使用,但也是有条件的,结构体可以包含结构体指针,但绝对不能在结构体中包含结构体变量。

   struct test
   {
   char name[10];
   float socre;
   test *next;
   };//这样是正确的!
   struct test
   {
   char name[10];
   float socre;
   test next;
   };//这样是错误的!

   利用结构体的这点特殊特性,我们就可以自己生成一个环环相套的一种射线结构,一个指向另一个。

  链表的学习不像想象的那么那么容易,很多人学习到这里的时候都会碰到困难,很多人也因此而放弃了学习,在这里我说,一定不能放弃,对应它的学习我们要进行分解式学习,方法很重要,理解需要时间,不必要把自己逼迫的那么紧,学习前你也得做一些最基本的准备工作,你必须具备对堆内存的基本知识的了解,还有就是对结构体的基本认识,有了这两个重要的条件,再进行分解式学习就可以比较轻松的掌握这一节内容的难点。

  下面我们给出一个完整的创建链表的程序,不管看的懂看不懂希望读者先认真看一下,想一想,看不懂没有关系,因为我下面会有分解式的教程,但之前的基本思考一定要做,要不即使我分解了你也是无从理解的。

   代码如下,我在重要部分做了注解:

   #include
   using namespace std;

   struct test
   {
   char name[10];
   float socre;
   test *next;
   };

   test *head;//创建一个全局的引导进入链表的指针

   test *create()
   {
   test *ls;//节点指针
   test *le;//链尾指针
   ls = new test;//把ls指向动态开辟的堆内存地址
   cin>>ls->name>>ls->socre;
   head=NULL;//进入的时候先不设置head指针指向任何地址,因为不知道是否一上来就输入null跳出程序
   le=ls;//把链尾指针设置成刚刚动态开辟的堆内存地址,用于等下设置le->next,也就是下一个节点的位置

   while(strcmp(ls->name,"null")!=0)//创建循环条件为ls->name的值不是null,用于循环添加节点
   {
   if(head==NULL)//判断是否是第一次进入循环
   {
   head=ls;//如果是第一次进入循环,那么把引导进入链表的指针指向第一次动态开辟的堆内存地址
   }
   else
   {
   le->next=ls;//如果不是第一次进入那么就把上一次的链尾指针的le->next指向上一次循环结束前动态创建的堆内存地址
   }
   le=ls;//设置链尾指针为当前循环中的节点指针,用于下一次进入循环的时候把上一次的节点的next指向上一次循环结束前动态创建的堆内存地址
   ls=new test;//为下一个节点在堆内存中动态开辟空间
   cin>>ls->name>>ls->socre;
   }

   le->next=NULL;//把链尾指针的next设置为空,因为不管如何循环总是要结束的,设置为空才能够在循环显链表的时候不至于死循环
   delete ls;//当结束的时候最后一个动态开辟的内存是无效的,所以必须清除掉
   return head;//返回链首指针
   }

   void showl(test *head)
   {
   cout<<"链首指针:"< <
   while(head)//以内存指向为null为条件循环显示先前输入的内容
   {
   cout< name<<"|"< socre<
   head=head->next;
   }
   }

   void main()
   {
   showl(create());
   cin.get();
   cin.get();
   }
   上面的代码我们是要达到一个目的:就是要存储你输入的人名和他们的得分,并且以链状结构把它们组合成一个链状结构。

程序种有两个组成部分
   test *create()
   和 void showl(test *head)
   这两个函数,create是用来创建链表的 ,showl是用来显示链表的。

   create函数的返回类型是一个结构体指针,在程序调用的时候我们用了showl(create());,而不用引用的目的原因是引导指针是一个全局指针变量,我们不能在showl()内改变它,因为showl()函数内有一个移动操作head=head->next;,如果是引用的话我们就破坏了head指针的位置,以至于我们再也无法找会首地址的位置了。

   下面我们来分解整个程序,以一个初学者的思想来思考整个程序,由浅入深的逐步解释。

  首先,我们写这个程序,要考虑到由于是一个链表结构,我们不可能知道它的大小到底是多大,这个问题我们可以用动态开辟堆内存来解决,因为堆内存在程序结束前始终是有效的,不受函数栈空间生命期的限制,但要注意的是我们必须有一个指针变量来存储这一链状结构的进入地址,而在函数内部来建立这一指针变量显然是不合适的,因为函数一旦退出,这个指针变量也随之失效,所以我们在程序的开始声明了一个全局指针变量。

   test *head;//创建一个全局的引导进入链表的指针
   好解决了这两个问题,我们接下去思考

  有输入就必然有输出,由于输出函数和输入函数是相对独立的,为了不断测试程序的正确性好调试我们先写好输出函数和main函数捏的调用,创建函数我们先约定好名为create。

   我们先写出如下的代码:

   #include
   using namespace std;

   struct test
   {
   char name[10];
   float socre;
   test *next;
   };

   test *head;//创建一个全局的引导进入链表的指针

   test *create()
   {

   return head;//返回链首指针
   }

   void showl(test *head)
   {
   cout<<"链首指针:"< <
   while(head)//以内存指向为null为条件循环显示先前输入的内容
   {
   cout< name<<"|"< socre<
   head=head->next;
   }
   }

   void main()
   {
   showl(create());
   cin.get();
   cin.get();
   }
   程序写到这里,基本形态已经出来,输入和调用我们已经有了。

  下面我们来解决输入问题,链表的实现我们是通过循环输入来实现的,既然是循环我们就一定得考虑终止循环的条件,避免死循环和无效循环的发生。

   在create()函数内部我们先写成这样:

   test *create()
   {
   test *ls;//节点指针
   test *le;//链尾指针
   ls = new test;//把ls指向动态开辟的堆内存地址
   cin>>ls->name>>ls->socre;
   head=NULL;//进入的时候先不设置head指针指向任何地址,因为不知道是否一上来就输入null跳出程序
   le=ls;//把链尾指针设置成刚刚动态开辟的堆内存地址,用于等下设置le->next,也就是下一个节点的位置

   le->next=NULL;//把链尾指针的next设置为空,因为不管如何循环总是要结束的,设置为空才能够在循环显链表的时候不至于死循环
   delete ls;//当结束的时候最后一个动态开辟的内存是无效的,所以必须清除掉
   return head;//返回链首指针
   }
   在循环创建之前我们必须考虑一个都不输入的情况。

  程序一单进入create函数我们首先必然要创建一个节点,我们先创建一个节点指针,后把者个节点指针指向到动态开辟的test类型的动态内存地址位置上。

   test *ls;
   ls = new test;
   程序既然是循环输入,而结构成员test *next又是用来存储下一个接点的内存地址的,每次循环我们又要动态创建一个新的内存空间,所以我们必须要有一个指针来存储上一次循环动态开辟的内存地址,于是就有了

   test *le;
   接下来在进入循环前我们要创建链表的第一个节点,第一个节点必然是在循环外创建,于是就有了

   cin>>ls->name>>ls->socre;
  程序执行者的情况是位置的,所以我们必然要考虑,一上来就不想继续运行程序的情况,所以我们一开始先把head引导指针设置为不指向任何地址也就是

   head=NULL;

  为了符合le也就是链尾指针的设计思路,我们在循环前一定要保存刚刚动态开辟的内存地址,好在下一次循环的时候设置上一个节点中的next成员指向,于是我们便有了:

   le=ls;
   为了实现循环输入我们又了下面的代码:

本文来自: 站长(http://www.qqcf.com) 详细出处参考:http://study.qqcf.com/web/171/19838.htm

c语言结构体指针初始化相关推荐

  1. c语言+结构体指针初始化,c语言结构体指针初始化===

    c语言结构体指针初始化 今天来讨论一下C中的内存管理. 记得上周在饭桌上和同事讨论C语言的崛起时,讲到了内存管理方面 我说所有指针使用前都必须初始化,结构体中的成员指针也是一样 有人反驳说,不是吧,以 ...

  2. C语言结构体指针初始化(转)

    reference: https://www.cnblogs.com/losesea/archive/2012/11/15/2772526.html 今天来讨论一下C中的内存管理. 记得上周在饭桌上和 ...

  3. c语言中结构体的指针初始化,c语言结构体指针初始化

    今天终于看完了C语言深度剖析这本书,对C语言有了进一步的了解与感悟,突然发觉原来自己学C语言的时候学得是那样的迷糊,缺少深入的思考,在重新看书的时候发觉C语言基本教材虽然经典,但是缺乏独到性,老师在讲 ...

  4. C 结构体指针初始化

    原文 C 结构体指针初始化,CSDN同步发布. 转载请注明出处,谢谢! 在使用指针之前,务必要将其初始化.这是我们最早学习 C 语言的时候,书上经常说的一个问题.在工作中,我们反而会经常忘记这条金科玉 ...

  5. C语言结构体指针的使用方法

    1.首先定义一个结构体,给它取别名: typedef struct node{ struct node * next://指向下一节点 int data://数据域 }pnode,*linklist; ...

  6. python 结构体指针_C语言结构体指针(指向结构体的指针)详解

    当一个指针变量指向结构体时,我们就称它为C语言结构体指针的定义形式一般为: struct 结构体名 *变量名; 下面是一个定义结构体指针的实例: //结构体 struct stu{ char *nam ...

  7. C语言结构体指针(指向结构体的指针)详解

    当一个指针变量指向结构体时,我们就称它为结构体指针.C语言结构体指针的定义形式一般为: struct 结构体名 *变量名; 下面是一个定义结构体指针的实例: //结构体 struct stu{ cha ...

  8. C语言结构体——指定初始化

    概述 C 语言结构体指定初始化(Designated Initializer)实现上有两种方式: 一种是通过点号加赋值符号实现,即.fieldname = value, 另一种是通过冒号实现,即fie ...

  9. C语言结构体指针强转

    文章目录 1.结构体指针强转 2.结构体指针强转在链表中的使用 3.结构体指针强转在链表中使用出现的问题 1.结构体指针强转 C语言中结构体无法进行强转,但是结构体指针是可以进行间接强转的 eg: 先 ...

最新文章

  1. 第四章:4.2MySQL 权限系统介绍
  2. 推箱子java下载_Java实现简单推箱子游戏
  3. I00005 打印直角三角形字符图案
  4. nginx mysql 查询系统_nginx/mysql查看内存占用
  5. Windows 怎么了?微软又停止一大版本更新
  6. Linux电源管理(1)_整体架构
  7. java 运算符的程序_【Java】运算符
  8. BOOST升压电路PCB布局布线
  9. 基于辅助功能的镜像劫持攻击原理
  10. 【君思智慧园区】物业管理系统解决方案
  11. 关系模式无损分解的测试方法
  12. 论文篇-----高速公路交通流数据质量控制及评价方法
  13. 2017-4-18 CCCC决赛总结
  14. svn执行update操作后出现:Error : Previous operation has not finished; run 'cleanup' if it was interrupted.
  15. 【压力测试 2】JMeter压力测试之Internal server error 500 问题解决思路
  16. lol大区服务器维护,LOL官宣“扩容升级”服务器,排队时间将大大减少,电一玩家喜大普奔!...
  17. DTS北洋曳舞社网站开发手记
  18. JS中删除数组中重复的元素
  19. 【思维模型】五分钟了解<乔哈里窗>,为什么学习乔哈里窗?什么是乔哈里窗?怎么应用乔哈里窗?
  20. 工作室神器:迈拓维矩键盘鼠标同步操作器

热门文章

  1. Bash常用快捷键及其作用
  2. android node
  3. 从github clone文件: Failed to receive SOCKS4 connect request ack.
  4. [LeetCode] 35. Search Insert Position
  5. 第2章 数字之魅——快速寻找满足条件的两个数
  6. 雷林鹏分享:codeigniter框架文件上传处理
  7. JavaScript实现向OL列表内动态添加LI元素的方法
  8. 时序数据合并场景加速分析和实现 - 复合索引,窗口分组查询加速,变态递归加速...
  9. 注册Tomcat服务为系统服务
  10. 在没有数据集的情况下使用数据表