Ok,那接下来呢,我们再来看一下,指向结构体变量的 指针。 看这个例子,在这个例子里头仍然沿用了student 的定义, 在主函数里头呢,定义了一个结构体类型的变量mike并且对它进行了初始化。接下来呢,我定义了, 一个变量,one,它呢,是一个指针类型的变量。并且呢,它的基类型是student, 这个结构体。也就是说,one是一个可以指向student 类型的结构体变量的指针。并且呢, 接下来我把mike的地址赋给变量one。 这跟普通变量是一样的。 那么接下来呢,我写了这样一行程序。cout<<(*one).id_num, 然后cout<<(*one).name。好理解吗? 非常好理解。这跟普通变量的引用方法是一样的。 one是一个指针,*one呢, 就应该是这个指针所指向的存储单元的内容。 也就是那一个 结构体。那么,在这个结构体的后面使用.id_num当然引用的就是结构体变量里面的 学号。同理,.name就是结构体变量里面的支付数组。 所以这个程序的执行结果也很容易想象。啊,它是这样的。打印出123 然后mike。 那么在这儿我需要特别说明的是, 在这个地方,也就是 引用 .id_num 和引用 .name的这个地方, 除了这种写法以外,我们还可以把它写成这个样子。 one,写一个 ‘-’ 号再写一个 ‘>’ 号,构成一个箭头,在后面呢,直接写出 id_num。这也是引用结构体变量mike里面的第一个元素的办法。 啊,也是可以的。那么跟刚才我们给出的那个写法呢,是完全等价的。由于用这一 种方法写起来更加的简便明了,所以人们更倾向于使用这样一种方法。 那么一个‘-’ 号再加一个‘>’ 号所构成的这个符号啊, 这是一个运算符,我们把它称作指向运算符, 指向运算符。那么在接下来的程序里头呢,当我们使用指针指向一个结构体 变量的时候,我们就可以用这个符号,来对这个指针所指向的结构体,变量的,成员变量进行访问了。 Ok, 这是指向结构体变量的指针。 那么做一个附加的讨论呢,我们稍微来讨论一下,当我们把一 个指向结构体变量的指针用作函数参数的时候,是一种什么样的情况? 看这个例子,在这个例子里头啊,仍然沿用了student。 主函数里头呢,定义了一个变量mike并且进行了初始化。 那么程序执行到这儿呢,我们得到的状况就是这样的。这主函数里面,有一个mike,并且呢,进行了初始化。 那么接下来呢,主函数里面调用了一个函数叫renew,并且呢, 把mike的地址当作参数传递给renew。 啊,我们定一个形式参数one来接纳这个指针。 当接收到这个指针之后呢,我就利用形式参数one,采用指向运算符 去修改这个指针one所指向的存储单元里面的内容。 那么main函数里面呢调用完renew以后啊,紧接着把变量mike的内容啊, 打印出来。那么这个程序的执行结果呢,是这样的。那么通过这个执行结果我们可以看得出来 renew这个函数有没有去修改主函数里面的mike这个变量啊? 修改了没有啊?修改了,啊,修改了。也就是说在这个过程里头是这样的,当main函数调用 renew函数并且把mike这个变量的地址当作参数传递给renew的时候, 那么这个renew这个函数就拿到了这片存储区域的 地址。 啊,于是呢我就可以对这片存储区域里面的内容,进行修改了。 也就是相当于renew这个函数要伸出一只手来 到main函数的里面去修改mike的值。所以说最后mike的值才会发生变化。 那么这种情况呢,跟当我们把指向普通变量的指针当做函数的参数传递给另外一个函数的时候,是 完全一样的情况。 那么说到这儿,我们就可以看出结构体变量的很多特性跟普通变量的特性实际上是一样的。 那么除了这一些关于结构体变量的使用,我们来看最后的一点,利用结构体来定义数组。 看这个程序,在这个程序里头呢,我就利用结构体类型student来定义一个数组, myclass。在myclass里头呢,有3个数据成员, 分别是123 mike,133 tom,143 jack。接下来呢我定义了 一个指针,one,我利用数组的名字,myclass 对 one 进行赋值, 可以吗?当然可以。啊,因为这是一个普通的数组, 数组名就相当于指向数组首元素的指针,所以说这个赋值完全没有问题。 那么接下来呢,我就利用one这个指针去打印 它所指向的结构体变量的id_num 和 name。 打印完之后呢,我对one做一个++的操作。 其实这个地方我们是想怎么你知道吗?我们是想印证一下这个++会跨过多大的范围。对吧? 那么++以后呢我再去打印one所指向的结构体变量的id_num 和 name。我们来看一下这个程序的执行结果。 那么第一次呢,打印出了123 mike,这跟我们所想像的是完全一样的。那么第二次呢,在++之后 打印出了133 tom,这说明什么问题啊?这说明在最开始的时候, one这个指针是指向了数组的第一个元素,也就是指向了这个元素。那么经过++以后呢,one这个指针 指向了哪里啦?指向了这里了。这是数组的第二个元素。所以我们才得到刚才的结果。 也就是说总结一下的话,其实利用结构体类型来定义数组跟普通的变量 来定义的数组是一样的。啊,数组名呢仍然是相当于指向数组第一个元素的指针。 而且呢,当我们对这个指针进行++操作的时候,实际上是跨过了 一整个结构体。啊,这跟普通变量,也是一样的。 所以,那总结一下的话我们就可以得到,结构体数据类型的 特性实际上与普通数据类型的特性,是一致的。 所以结构体这个东西对我们来说是既陌生,又熟悉。 那么结构体数据类型具有那一些用途呢?其实啊,在写程序的过程中, 结构体数据类型还是用得非常非常多的。那只是呢我们这个课并不对结构体类型作出 很高的要求,所以呢我们并没有设计很多的例题让大家去感受这一点。 那么接下来呢,我就举一个小例子,来说明一下结构体类型的作用。 看这个例子, 那这是一道OpenJudge 上面的题目。 那我把这道题的所有信息呢,都copy过来了。这个题目是这样的, 在一个有100 个人的大班级里头啊,存在 多个人具有相同的生日。 啊,就是说月日相同,这个概率还是非常大的。 那么现在呢,系统会给你每个学生的学号,以及他的出生的 月和日,要求你写个程序,列出所有生日相同的 同学。啊,输入格式是这样的,先输入一个n代表学生的数量。那么接下来呢,是n行, 每一行呢,都先给出学生的学号,然后呢再给出出生的月 和日。啊,学号和月日之间呢都用一个空格隔开。需要特别注意的是,这道程序 所约定的输出。它要求啊,对每一组生日相同的同学都输出到一行里面。 其中呢,前两个数字表示月和日,后面呢,跟着所有在这一天出生的 所有同学的学号。那么学号之间呢都用空格来隔开,这是一个格式的要求。 还有一个顺序的要求,就是对所有的输出要求按日期从前到后的顺序 输出。也就是说,先排一月一号的,再排一月二号的,然后再排二月份的,再排三月份的等等等等。 而且呢,对于生日相同的那一些学号,要按照输入的这个顺序来进行输出。 其实作这样一个输出的约定啊,是为了让你有更多的办法可以来解这道题。 那么其实呢,解这道题目的方法非常非常地多。啊,当我们看到这道题目的时候 恐怕很多的同学都会想到,哎,这是一道统计题,所以说呢,那么我可以利用数组来作统计。 Ok,这是一个不错的想法,但是这道题呢,可能有点麻烦,因为需要判定相同的那个量啊,有两个, 一个是月份,一个是日期,所以说有可能你需要定义一个用来统计月份,一个用来统计日期。 有的同学说,哎呀,我不用这样啊,我可以把它们两个合在一起, 定义一个二维数组。哎,好办法。我以前呢,也见到过有的同学, 定义一个二维数组来解决这个问题。啊,也是一个办法,只不过啊,稍微麻烦了一点。其实啊,对于这样一道题目啊, 我们非常适合利用结构体类型来解决。我完全啊,可以定义这样一个数组, 啊,这是一个结构体数组。 它的每一个元素呢,都是这样一个结构体。比如说第一个成员是它的学号,第二个是月, 第三个是日。数组里的每一个成员都是一个这样的结构体。 于是呢, 我完全就可以利用这样一个数据结构把所有输入的数据啊,全部都读入进来。 然后呢,我再利用一个这样的结构体数组来进行统计。比方说,有的同学啊就 写出了这样一个程序。啊,这是我从历届有的同学题用的程序里面直接采用过来的。 它呢,就定义了一个这样的结构体,并且呢 利用这个结构体定义了一个数组,stu[100]。 然后呢,利用一个for循环把所有的数据啊读入到这样一个结构体数组里头来。 然后呢,再利用这个结构体进行统计分析,比方说它就可以穷举所有的 月和日,然后呢去检查有没有在这一天出生的同学。 如果有的话我就把这个同学的信息写入到count这个数组里面。 最后呢,我只要把count这个数组里面所存的学号信息全部都打印出来,就可以满足题目的要求了。 啊,这是一个不错的办法。那么感兴趣的同学呢,在听完以后啊,可以把这个程序copy下来,自己 运行一下。Ok,那么关于结构体的使用啊,我们暂时就先讲这么多。