学习笔记——结构体

1. 几个问题

1.1 结构体类型定义的位置

看下面这段代码代码:

#include<stdio.h>

int fun(struct a y)
{
    return 0;
}

int fun1(int a)
{
    return 0;
}

int main()
{
    int g;
    struct a 
    {
        int b;
        int c;
        int d;
    };
    fun1(g);
    fun(xx);
    struct a xx;
    return 0;
}

这段代码编译的话会出现报错:
warning: ‘struct a’ declared inside parameter list will not be visible outside of this definition or declaration
error: parameter 1 (‘y’) has incomplete type

报错原因是未声明结构体。于是我有了下面的疑问:

为什么fun1的形参int不用提前声明,而fun的结构体形参必须提前声明?

我暂时得到了一个不是很满意的答案:因为int为基本数据类型,能被编译器自动识别,而结构体为构造数据类型。只有提前声明结构体类型,做函数形参时才能被编译器识别。

1.2 编译器对构造数据类型的识别

那么,数组也为构造数据类型,它做函数形参是为何不用提前声明?

同样,我也有一个不是很满意的答案:因为数组的类型是确定的,它包含的元素都为基本数据类型。

1.3 编译器对源文件的编译过程

既然全局函数在main函数中调用的时候才会开辟相应的空间,那为什么在编译阶段,就要对传入的形参进行识别呢?

同样暂时有个不满意的答案:编译器解析源码的过程涉及到词法分析、语法分析、语义分析,是个十分复杂的过程。在处理过程中,编译器需要“看到”所有相关的定义和声明。

2. 静态链表

看下面这段代码:

#include<stdio.h>

struct student
{
	long num;
	struct student *next;
};

int main(void)
{
	struct student a,b,c,*h,*p;
	
	h=&a;
	a.num=10101;
	a.next=&b;
	b.num=10103;
	b.next=&c;
	c.num=10107;
	c.next=NULL;
	p=h;

	while(p!=NULL)
	{
		printf("%ld\n",p->num);
		p=p->next;
	}

	return 0;
}

在此例中,链表的每个结点都是在程序中定义的,由系统在内存中分配固定的存储单元。每个结点不是临时开辟的,也不能用完后释放,而是在程序结束后释放。

从这一点来讲,这种链表被称为“静态链表”。

实际应用中使用更广泛的是“动态链表”。

3. 动态链表

3.2 库函数

先介能够动态申请和释放内存的库函数。

1. malloc
原型为:

void *malloc(unsigned int a);

作用是在内存的堆区中申请 a 字节的连续空间,并返回此空间的起始地址。

由于返回的地址的类型为 void,所以将其赋值给其他类型的指针变量时,需要进行强制类型转换,如:

p=(long *)malloc(8);

2. free
用法如下:

free(p);

3.2 内存空间分类

见下图:
在这里插入图片描述
栈区空间由计算机分配,而堆区空间由程序员手动管理。

静态链表的内存空间由计算机从栈区分配。而 malloc 从堆区申请存储空间。

4. 链表的基本操作

链表的基本操作包含建立链表、插入链表、删除链表、输出链表、查找链表。

4.1 建立链表

看下面这段代码:

#include<stdio.h>
#include<stdlib.h>
struct student
{
	long num;
	struct student *next;
};
int main()
{
    struct student *h,*p;
    h=(struct student *)malloc(sizeof(struct student));
    h->next=NULL;
    h->num=1;

    p=(struct student *)malloc(sizeof(struct student));

    p->next=h;
    h=p;

    return 0;
}

这段代码先创建了一个结构体,指针 h 指向整个结构体的首地址,这个结构体的尾部指向空地址NULL。

然后又创建了了一个同类型的结构体,指针 p 指向新创建的结构体。新创建的结构体的尾部指向之前创建的结构体。指针 h 指向新创建的结构体。

可以将这个过程封装为函数,重复调用以达到不断扩充链表的效果。

4.2 输出链表

将链表中各节点的值依次输出,需要对链表进行遍历。核心代码如下:

whlie(p!=NULL)
{
	printf("%d\n",p->num);
	p=p->next;
}

4.3 插入链表

要找到链表的插入点,可以使用循环。

4.4 链表的删除

修改前一个共用体的尾部指针,然后释放掉该结构体的内存空间。

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值