总结了一些指针易出错的常见问题(四)

指针与结构体

简介:我们可以使用C的结构体来表示数据结构元素,比如链表或树的节点,指针是把这些元素联系到一起的纽带。

typedef struct _person{
    char* firstName;
    char* lastName;
    char* title;
    unsigned int age;
} Person;
/*用点表示法初始化*/

为结构体分配内存,分配的内存大小至少是各个字段的长度之和。不过,实际长度会大于这个和,结构体的各字段之间可能会有填充。结构体数组各元素之间会有填充。

结构体释放问题:

 用结构体变量和指向结构体的指针函数参数

1.用结构体变量的成员作参数。(用法和普通变量相同)

  2.用结构体变量作实参。形参也必须是同类型的结构体变量。调用期间形参也要占用内存。(空间和时间上开销较大),较少使用该方法。

  3.用指向结构体变量(或数组)的指针作实参,将结构体变量(数组)的地址传给形参。

用指针处理链表

链表是一种动态地进行存储分配的一种数据结构。 链表是C语言编程中常用的数据结构,比如我们要建一个整数链表,一般可能这么定义:

struct int_node {
        int val;
        struct int_node *next;
};

  假设有五个学生某一门功课的成绩分别为A、B、C、D和E,这五个数据在内存中的存储单元地址分别为1248、1488、1366、1022和1520,其链表结构如图所示。

链表有一个“头指针”变量,图中以 head表示,它存放一个地址,该地址指向链表中第一个结点,第一个结点又指向第二个结点……直到最后一个结点。该结点不再指向其他结点,它称为“表尾”,它的地址部分存放一个“NULL”(表示“空地址”),链表到此结束。链表中每个结点都包括两个部分:用户需要用的实际数据和下一个结点的地址。

 链表每个结点中只有一个指向后继结点的指针,该链表称为单链表。其实结点中可以有不止一个用于链接其他结点的指针。如果每个结点中有两个用于链接其他结点的指针,一个指向前趋结点(称前趋指针),另一个指向后继结点(称后继指针),则构成双向链表。双向链表如图所示。

/*单链表的例子(静态链表:因为所有节点在程序中定义的,不是临时开辟的,也不能用完后释放)*/
#include<stdio.h>
//#define NULL 0

 struct student
 {
     int num;
     int score;
     struct student *Next;
 };
     int main()
     {
         struct student a,b,*head,*p;
         a.num=10012; a.score=99;
         b.num=10013; b.score=81;
         head=&a;
         a.Next=&b;
         b.Next=NULL;
         p=head;
         do
         {
             printf("%5d  %ld\n",p->num,p->score);
             p=p->Next;
         }while(p!=NULL);
     }

问题:结构体的变量名可以当做地址赋给指针吗?没有头指针head行不行?p起了什么作用?没它可以吗?

处理动态链表用到的函数  calloc/malloc/free

malloc函数原型:  void *malloc(unsigned int size);其作用是在内存的动态存储区分配一个长度为size的连续空间。此函数的值(返回值)是一个分配域的起始地址(void类型);若函数未成功执行,则返回空指针(NULL)。

  calloc函数原型:  void *calloc(unsigned n,unsigned size);其作用是在内存的动态存储区分配n个长度为size的连续空间。函数返回一个指向分配域起始位置的指针;否则,返回NULL。

  free  函数原型:  void free(void *p);释放由p指向的动态存储区。free无返回值。

建立动态链表(知难而进)

/*写一函数建立一个有3名学生数据的单向动态链表*/
 #include<stdio.h>
 #include<malloc.h>
 //#define NULL 0
 #define LEN sizeof(struct student)
 
 struct student
 {
     long num;
     float score;
     struct student *next;
  };
  int n;
  struct student *creat(void)
  {
      struct student *head;
      struct student *p1,*p2;
      n=0;
      p1=p2=(struct student*)malloc(LEN);
      scanf("%ld,%f",&p1->num,&p1->score);
      head=NULL;
      while(p1->num!=0)
      {
          n=n+1;
          if(n==1) head=p1;
          else
          p2->next=p1;
          p2=p1;
          p1=(struct student*)malloc(LEN);
          scanf("%ld,%f",&p1->num,&p1->score);
       } 
       p2->next=NULL;
       return(head);
  }
 
 int main()
 {
     creat();
 }

建立链表首先要定义一个包含数据域和指针域的的结构类型,然后建立指向表头节点的头指针head,最后通过malloc函数动态申请一块内存作为表头节点。

typedef struct node  
{  
int data; /*信息*/  
struct node *link; /*指针*/  
}NODE; /*定义节点*/  
NODE *head; /*定义头指针head */

定义结构类型和头节点之后,我们要建立不包含数据的表头节点,可以按下列语句进行操作。

NODE *p; /*说明一个指向节点的指针变量p */  
p=(NODE*) malloc(sizeof(NODE)); /*申请表头节点*/  
p->link = NULL; /*将表头节点的link置为NULL */  
head=p; /*head指向表头节点p*/ 

由于此时链表中只有一个表头节点,没有数据节点,所以称为空链表。

p=(NODE*) malloc(sizeof(NODE)); /*申请一个数据节点*/  为了在链表中保存数据,可以从表头位置将数据节点插入到链表中,例如,插入一个数据节点:

p=(NODE*) malloc(sizeof(NODE)); /*申请一个数据节点*/  
gets(p ->data); /*输入一个新的数据*/  
p->link=head->link; /*建立链接关系。将表头节点的link存入p 的link中*/  
head->link=p; /*将数据节点插在表头节点之后成为第一个数据节点*/ 

插入第一个数据节点后链表,然后继续插入下一个数据节点。

create(NODE *head,int n)  根据上面的链表建立过程,可以写出函数create建立有n个数据节点的链表。

create(NODE *head,int n)  
{  
NODE *p;  
for(; n>0;n--)  
{  
p=(NODE*) malloc(sizeof(NODE));  
if(p==NULL)  
exit(0);  
gets(p->data);  
p->link = head->link;  
head->link = p;  
}  
} 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

深入分析golang多值返回以及闭包的实现

一、前言 golang有很多新颖的特性,不知道大家的使用的时候,有没想过,这些特性是如何实现的?当然你可能会说,不了解这些特性好像也不影响自己使用golang,...

5196
来自专栏Java后端技术

Java Collection、Map集合总结

      依赖hashCode()和equals()两个方法进行保证元素唯一性,开发中使用开发工具自动生成就好。

902
来自专栏CDA数据分析师

Python正则表达式指南

本文介绍了Python对于正则表达式的支持,包括正则表达式基础以及Python正则表达式标准库的完整介绍及使用示例。本文的内容不包括如何编写高效的正则表达式、如...

2065
来自专栏Java3y

泛型就这么简单

1674
来自专栏用户2442861的专栏

java泛型(一)、泛型的基本介绍和使用

http://blog.csdn.net/lonelyroamer/article/details/7864531

1401
来自专栏追不上乌龟的兔子

[奇怪但有用的数据结构]线段树

线段树是一棵二叉树,他的每个节点包含了两个额外的属性start和end用于表示该节点所代表的区间。start和end都是整数,并按照如下的方式赋值:

1.3K9
来自专栏Micro_awake web

javascript(三):对象

 对象(object)是javascript中很重要的数据类型。对象是“键值对”的集合,同时也是无序的。(注意:对象结尾处有分号) 1 var ob1={ ...

20410
来自专栏梧雨北辰的开发录

Swift学习:构造器(下)

本篇主要介绍Swift中构造器的一些特殊用法 一、可失败的构造器 顾名思义,这是用于我们构造过程可能失败情况的构造器。失败的原因可能是给构造器传入无效的参数值,...

2777
来自专栏Java帮帮-微信公众号-技术文章全总结

数据结构基础(1) --Swap ; Bubble-Sort ; Select-Sort

Swap的简单实现 //C语言方式(by-pointer): template <typename Type> bool swapByPointer(T...

3578
来自专栏小樱的经验随笔

C++STL中set的使用策略(详解)

set的英文意思是“集合”, 集合都不陌生吧,集合的特点有唯一性,即:每一个元素只有一个,所以set可以用来“去重”操作,set还有默认的排序。  1、头文件...

2705

扫码关注云+社区

领取腾讯云代金券