上節課我們學習到了結構體的定義和初始化,我們在定義學生這個人的時候,姓名最好給char *,學號最好也用char *,因為我們用int表示學號有局限性,因為無法表示帶字符的編號啦!因為有些學號不一定是純數字的啊!成績呢!就用float型,郵政編碼呢!通訊地址呢!char *吧!因為通訊地址有的好長好長,有的又很短呀!呵呵!是不是感覺和以前的知識點都是串起來的呀!以前我們還專門學習過char *呢!
結構體是不允許遞歸定義的
我們來看這個例子:
struct person{ char name[16]; char sex; int age; float height; struct person per;}
大家看這個,我們是無法算出其大小的,這樣可不行哦,所以不能結構體遞歸嵌套定義哦!關於遞歸的理解,我暫時就是自己調用自己,然後必須有1個出口,不然遞歸就一直這麼遞歸下去了(看似無限遞歸,但是計算機內存的棧應該是有限的,在某個時候應該會溢出,我也不知道是不是這樣的哦,暫且這樣思考,有錯的話以後再糾正)。遞歸的最大優勢是可讀性好!在後面我會專門學學遞歸的。
結構體類型變量
當我們定義了結構體類型後,只是說明了該類型的組成情況,並沒有給它分配內存空間,當我們定義了結構體變量的時候,才會為其分配內存空間,就像int本來是不能分配內存空間的,而int a,這個a就有內存空間啦!
現在我們來看看,如何定義結構體變量。其實這裡上午的學習,已經學習過了,我們我們再回顧下:
struct person{ char name[64]; char sex; int age; float height;};struct person one;
那麼這個結構體變量在內存中才排列,我們上午也學習了,那麼我再回顧下:它是以我們定義變量的先後順序依次排列的。然後這個結構體的大小呢,是64+1+2+4.(這裡的對齊方式為模1).如果對齊方式是地址模4,那它的大小就不一樣啦!一定要注意哦!
結構體變量的另外一種定義方式
我們在定義類型的同時定義變量:
其實兩種定義的效果是一樣的。嘿嘿!我差點搞忘記啦!還有第3種定義方式:
struct person
{
char name[64];
char sex;
int age;
float height;}one;
struct{
char name[64];
char sex;
int age;
float height;
}
one;
這種方式呢!直接定義結構體類型變量,去掉了類型名!呵呵!切記!這種定義形式和前面的兩種方法都不一樣的哦,因為沒有說明這種結構體類型的名字呀,所以這種方式通常用在不需要再次定義此類型結構體變量的情況下才用。這個就像有些國家的婚姻啊,比如菲律賓,不准離婚呀!
結構體變量的引用
結構體變量的引用必須在定義結構體變量後才行。對結構體變量的引用呢可以分為對機構體變量中成員的引用和對整個結構體變量的引用。一般對結構體變量的操作是以成員為單位進行的。
引用的一般形式為:結構體變量名.成員名
.的優先級是所以運算符中優先級最高的哦,一定要記住哦!當遇到某個成員本身又是結構體變量的時候,則必須連續使用成員運算符,就是這個點啦!一直到基本數據類型的時候。結構體變量的每個成員都屬於某種數據類型,因此都可以像普通變量一樣進行其類型所允許的各種操作。
我們來看一個例子:
//這個程序呢!我們來分析下,在main函數裡定義了一個結構體person,結構體person又嵌套定義了一個結構體date.我們來一行一行的分析。
#include<stdio.h>void main(){
struct person;
//定義了一個結構體
{
char name[20];
//第一項成員是name,20個字節的數組。
char sex;//定義了性別。
struct date//嵌套定義了一個date類型的結構體,並定義了3個成員.
{
int year;
int month;
int day;
}
birthday;
//定義了date結構體變量birthday. float height;
//定義了fload類型的身高。
}
per;
//定義了person結構體類型變量per.printf("Enter the name:");
gets(per.name);
per.sex=M;
per.birthday.year=1982;
per.birthday.year++;
per.birthday.month=12;
per.birthday.day=15;
per.height=(175+176)/2;
printf("%s%3c%4d%2d%d%7.1f ",per.name, per.sex,per.birthday.month, per.birthday.day,per.birthday.year,per.height );
}
操作結構體需要注意的地方
我們看下面的程序:
#include <stdio.h>
struct stDate{
int nYear;
int nMonth;
int nDay;
};
struct stStudent{
char szName[64];
struct stDate WoW;
float fScore[3];
};
int main(){
struct stStudent stu;
stu.szName = "dodolook";
return 0;
}
這個程序是正確的嗎?!其實運行下就知道,會得到一個錯誤,這個是為什麼呢!其實原因是這樣的,stu.szName是一個數組名,是常量,所以會出現錯誤!那麼我們怎麼為字符數組賦值呢!我們可以這樣做,用1個函數,這個函數叫strcpy.如何書寫呢!strcpy(stu.szName, "dodolook");這樣的話就是正確的了。
對整個結構體變量的引用
相同類型的結構體變量之間是可以進行整體賦值的。結構體變量只允許整體賦值,其他操作如輸入,輸出等必須引用結構體變量的成員。
例如 stu2 = stu;它是把stu成員的值一個一個的抄寫過去到stu2.這個其實等價於
memcpy,內存拷貝。如何近進行的內存拷貝呢,我們來看看memcpy的幫助文檔:
void *memcpy(void *dest, const void *src, size_t count);
第一個參數是目的地址,第二個參數是源地址,第三個參數是要拷貝數據的長度,單位是字節。size_t其實就是1個int. 這個函數返回的是void類型的指針,暈,我們以前怎麼沒見到過這種類型的呀!我們仔細思考下,1個指針帶有2個信息,1個是地址信息,1個是如何對這個地址做何種解釋的信息。那麼void就表示沒有信息,這樣的話我們對void類型的指針取內容就不行啦!沒有信息也是一種信息,就像,沒有風格也是一種風格,呵呵!
為什麼這裡要用void呢?!
因為寫這個函數的人並不知道你將要拷貝的數據是什麼類型。
實例:memcpy(&stu2, &stu, sizeof(stu));
結構體數組
當我們定義了一種結構體類型以後,就相當於我們可用的變量類型又多了一種了。其實float也是一種結構體,它只是是以位為單位的。我們先來看1個結構體數組的例子:
struct person{ char name[20]; char sex; int age; float height;};struct person per[3];
哈哈!是不是特好玩!現在我們的數組元素裝了個結構體。呵呵!
這裡的per是什麼呢!per就是person類型的指針常量啦!其實這個和數組差不多了啊!
下面我們來看1個例子程序:
#include <stdio.h>
struct stDate
{
int nYear;
int nMonth;
int nDay;
};
struct stStudent{
char szName[64];
char Sex;
struct stDate WoW;
float fScore[3];
};
int main()
{
struct stStudent stu;
printf("%d", (int)stu.fScore - (int)&stu);
return 0;}
注:默認是模4地址的。
這個例子打印出多少呢?!我們一起來數數,64+4+12=80 對吧!呵呵。這個例子是不是就可以求出結構體變量的成員到結構體首地址的偏移量呀!對不對呀!很好玩吧!但是這裡有個缺點,必須要用結構體變量,那麼我們可以不用一個結構體變量也能求出1個成員的偏移量來嗎?!這個問題,到明天的筆記中再說明了。