引入
前面,我们已经学习了三种声明结构体变量的方式,今天我们来学习如何给结构体变量赋初始值
和输出该结构体成员的值
。
例子
把一个学生信息放在一个结构体变量中,然后输出这个学生的信息。
1 |
|
输出结果:
No.1
姓名:Bliner
性别:M
年龄26
家庭住址:China,Beijing
高树靡阴,独木不林。
前面,我们已经学习了三种声明结构体变量的方式,今天我们来学习如何给结构体变量赋初始值
和输出该结构体成员的值
。
把一个学生信息放在一个结构体变量中,然后输出这个学生的信息。
1 | #include <stdio.h> |
输出结果:
No.1
姓名:Bliner
性别:M
年龄26
家庭住址:China,Beijing
前面,我们讲了如何建立一个结构体类型,但是并没有定义变量,系统也不分配具体的内存单元。我们可以采用以下3种方法定义结构体类型变量。
没有这个类型,就声明这个类型,然后再定义这个类型的变量。这种声明方式最常用和简单,声明和定义分离,声明后可以随时定义变量,比较灵活。
1 | #include <stdio.h> |
前面我们所见到的程序中,变量都是独立存在的,我们定义 a、b、c,那他们就只是单独存在的变量而已,在内存中的地址也是互不相干的~但是~~
实际生活中,有些数据是有内在联系的,成组出现的。
例如,一个学生,可能包含:
学号、姓名、性别、年龄、成绩、家庭地址等
这些信息往往是成组的出现。
所以,我们希望把这些数据合并在一起,成为一个组合数据,例如组成数据 student_1 的变量,这个变量中就包含了学号为1的学生的上述信息,这样我们写入和调用时就方便多了!
一个变量名,包含多重信息,咦,这不是跟数组很像吗?为什么不用数组来解决这个问题呢?因为:
数组的每个元素的数据类型是相同的,我们需要的显然是不同类型的数据,例如 姓名 和 学号。
所以,为了解决这个问题,C 语言就允许用户自己建立由不同类型数据组成的组合型数据结构
,它称为结构体
。
在其它的高级语言中,称为记录
。
我们根据上面学生的例子,亲手建立一个结构体。
1 | struct Student |
指针的概念比较多,抽象并且复杂,我们再把这一部分的内容回顾一下。
记住一句话,指针就是地址
。
凡事指针出现的地方,都是用地址代替
的。
变量的指针:变量的地址
指针变量:地址变量
1 | int a; //定义整型变量 a |
还记得我们之前讲过的全局变量和局部变量吗?全局变量是分配在内存中的静态存储区的,非静态的局部变量(包括形参)都是分配在内存的动态存储区的。我们称上面的存储区为 栈 (stack)
。
除此之外,C 语言还允许建立内存动态分配区域,存放一些临时用的数据,这些数据:
这些数据是临时存放在一个特别的自由存储区,称之为堆 ( haap)
。
我们可以根据需要,随时向系统申请所需大小的空间,但是我们没有声明
他们是变量还是数组,也没有名字
,所以我们只能通过指针来引用这些数据
。
清楚了什么是动态分配之后呢,我们来看看如何建立这么一个叫做堆
的区域。
我们对内存的动态分配,主要是通过系统功能提供的库函数来实现的,主要有malloc , calloc , free , realloc
这4个。
函数原型:
void * malloc( unsigned int size);
前面我们学习过指针数组,即数组的元素都是由指针地址组成的数组,指针数组可以很好的存储长度不同的数组地址,从而进行调用。但是指针数组最重要的作用是作为 main 函数的形参来使用的,今天我们就来看看。
我们知道 main 函数的一般形式是
1 | int main(){ |
也就是说,main 函数的默认形参实际上是不存在的,也就是说,调用 main 函数的时候不用给出实参传递给 main 函数的形参。
在有些情况下,实际上 main 函数可以有参数的。
1 | int main(int argc, char * argv[]) |
好吧,看到这个标题我是崩溃的,指针要指向数据,现在还有一个指针指向了指向数据的指针….
我们把这种指向指针数据的指针
变量,称为指向指针的指针
。
1 | char *name[]={"Book_a","Book_b","Book_c","Book_d"}; |
这是一个指针数组,数组元素存放的是后面字符串的首元素地址
1 | char *name[]={"Book_a","Book_b","Book_c","Book_d"}; |
name+i
是一个指针,指向的是 name[i]name[i]
这个数组元素存放的是一个指针,所以:name+i
是指向指针的指针。
一个数组,若其元素均为指针
类型数据,称为指针数组
。
也就是说,每一个数组元素,都存放的是一个地址,每个元素也相当于一个指针变量。
int * p[4]
因为 [ ]
的优先级比*
高,所以,p 先跟[ ] 结合为一个数组
,然后数组再跟* 结合,表示这个数组是一个指针类型的
。即这个数组的每个元素都相当于一个指针,可以指向一个整型变量
。
凡事没有加括号,在前面加*
号的,一般都表示这是一个指针型的 XXX。例如:
1 | int *p; // 表示一个指针 |
不要写成
1 | int (*p)[5]; //这是指向一维数组的指针变量 |
我们知道,大多数函数都有返回值,可以是整型、字符型等等,其实指针型也可以作为函数的返回值来使用,当然,返回的就是指针,也就是地址。
我们如何定义一个函数呢?
1 | int a ( int x, int y); |
上面,我们定义了一个返回值为整型的函数 a,包含两个参数,x 和 y。如果改成
1 | int *a(int x, int y); |
a 的左右有 和 ( ) ,根据符号优先级,a 先与括号组成一个函数 a,在与号组成一个指针型函数,即这个函数是一个指针函数,返回的值是一个指着你地址,前面的 int ,表示这个函数返回的地址是一个 int 型地址。所以,要定一个一个返回指针值的函数的一般形式是:
类型名 * 函数名 ( 参数列表 )
上面说的可能比较晕,我们通过一个例子来说明。
有3个学生,4门课,要求输入学生号之后,返回学生所有成绩,用指针的方式解决。
1 | #include <stdio.h> |
其实,作为指向函数的指针变量
,它最重要的作用就是把函数的地址,作为参数传递给其他的函数
。
输入三个数,将其中最大值和最小值的和输出出来。
1 | #include <stdio.h> |