- 共用體
1.1共用體的概念 :使幾個不同的變量共占同一段內存的結構,稱為“共用體”類型的結構。
1.2 定義共用體類型變量的一般形式為:
union 共用體名
{
成員表列
}變量表列;
其實定義共用體變量有3中方法,其方法與定義結構體變量的3種方法類似:
1) 先聲明共用體類型再定義變量名
union date
{
int year;
int month;
long day;
};
union date d1, d2;
2)在定義結構體類型的同時定義變量
union 共用體名
{
成員列表
}變量名列表;
例:
union date
{
int year;
int month;
long day;
}d1, d2;
3) 直接定義共用體類型變量
union
{
成員列表
}變量名列表;
例:
union
{
int year;
int month;
long day;
}d1, d2;
1.3 共用體與結構體的比較
結構體變量所占內存長度是各成員占的內存長度之和,因為每個成員分別占有其自己的內存單元。共用體變量所占的內存長度等于最長的成員的長度,因為所用成員共享一個公共的內存單元,所以需要滿足最長成員的長度。見例1.
例如 : 上面定義的“共用體”變量d1、d2各占8個字節(因為在GCC中一個整型變量占4個字節,一個長整形變量占8個字節),而不是各占 4 +4+8=16個字節。
1.4 共用體變量的引用方式
只有先定義了共用體變量才能引用它,而且不能引用共用體變量,而只能引用共用體變量中的成員。
例如 : 前面定義了d1, d2為共用體變量
d1.year (引用共用體變量d1中的整型變量year)
d1.month(引用共用體變量d1中的字符變量month )
d1.day(引用共用體變量d1中的長整型變量day)
1.5 共用體類型數據的特點
1)同一個內存段可以用來存放幾種不同類型的成員,但在每一瞬時只能存放其中一種,而不是同時存放幾種。
2)共用體變量中起作用的成員是最后一次存放的成員,在存入一個新的成員后原有的成員就失去作用。
3)共用體變量的地址和它的各成員的地址都是同一地址。
(這3條特點共同說明了,所用共用體成員共享一個公共的內存單元)見例1.
4)不能對共用體變量名賦值,也不能企圖引用變量名來得到一個值,又不能在定義共用體變量時對它初始化。
5)不能把共用體變量作為函數參數,也不能使函數帶回共用體變量,但可以使用指向共用體變量的指針。
6)共用體類型可以出現在結構體類型定義中,也可以定義共用體數組。反之,結構體也可以出現在共用體類型定義中,數組也可以作為共用體的成員。見例2.
//例1.
/#include<stdio.h>union date
{
int year;
int month;
long day;
}d1, d2;void main()
{
d1.year = 2018;
d1.month = 01;
d1.day = 01;printf("%d-%d-%ld\n", d1.year, d1.month, d1.day);
printf("&d1.year: %o, &d1.month: %o, &d1.day: %o\n", &d1.year, &d1.month, &d1.day);
printf("sizeof(d1): %d\n", sizeof(d1));d1.year = 2018;
d1.month = 01;
d1.day = 02;printf("%d-%d-%ld\n", d1.year, d1.month, d1.day);
printf("&d2.year: %o, &d2.month: %o, &d2.day: %o\n", &d2.year, &d2.month, &d2.day);
printf("sizeof(union date): %d\n", sizeof(union date));
}
//輸出:
1-1-1
&d1.year: 30010100, &d1.month: 30010100, &d1.day: 30010100
sizeof(d1): 82-2-2
&d2.year: 30010110, &d2.month: 30010110, &d2.day: 30010110
sizeof(union date): 8
//例2
/#include <stdio.h>struct
{
int num;
char name[10];
char sex;
char job;
union
{
int banji;
char position[10];
}category;
}person[2]; //為了方便先假設一個學生一個老師。void main()
{
int i;
for(i=0; i < 2; i++)
{
printf("Please input the num: ");
scanf("%d", &person[i].num);
printf("Please input the name: ");
scanf("%s", person[i].name);
fflush(stdin);
printf("Please input the sex(M/F): ");
scanf("%c", &person[i].sex);
fflush(stdin);
printf("Please input the job(s/t): ");
scanf("%c", &person[i].job);
fflush(stdin);
if( person[i].job == 's' )
{
printf("Please input the class: ");
scanf("%d", &person[i].category.banji);
fflush(stdin);
}
else if( person[i].job == 't' )
{
printf("Please input the position: ");
scanf("%s", person[i].category.position);
fflush(stdin);
}
else
{
printf("Input Error!!\n");
}
printf("\n");
}
printf("No. name sex job class/position\n");
for( i=0; i < 2; i++ )
{
if( person[i].job == 's')
{
printf("%-6d%-10s%-3c%-3c%10d\n", person[i].num,
person[i].name, person[i].sex, person[i].job,
person[i].category.banji);
}
else
{
printf("%-6d%-10s%-3c%-3c%10s\n", person[i].num,
person[i].name, person[i].sex, person[i].job,
person[i].category.position);
}
}
}
- 枚舉類型
2.1 概念:在實際問題中,有些變量的取值被限定在一個有限的范圍內。例如,一個星期內只有七天,一年只有十二個月,一個班每周有六門課程等等。如果把這些量說明為整型,字符型或其它類型顯然是不妥當的。為此,C語言提供了一種稱為“枚舉”的類型。
2.2 枚舉變量的聲明:設有變量 a,b,c 被說明為上述的 weekday ,可采
用下述任一種方式:
1)enum weekday{ sun,mou,tue,wed,thu,fri,sat };
enum weekday a, b, c;
2)enum weekday{ sun,mou,tue,wed,thu,fri,sat }a, b, c;
3)enum { sun,mou,tue,wed,thu,fri,sat }a, b, c;
2.3 注意事項:
1)在“枚舉”類型的定義中列舉出所有可能的取值,被說明為該“枚舉”類型的變量取值不能超過定義的范圍。
2)枚舉類型是一種基本數據類型,而不是一種構造類型,因為它不能再分解為任何基本類型。
3)在枚舉值表中應羅列出所有可用值。這些值也稱為枚舉元素。
4)在C編譯中,對枚舉元素按常量處理,故稱枚舉常量。它們不是變量,不能對它們賦值。
5)枚舉元素作為常量,它們是有值的,C語言編譯按定義時的順序使它們的值為0,1,2...
6)枚舉值可以用來作判斷比較。
7)一個整數不能直接賦給一個枚舉變量。
//例3
/#include <stdio.h>void main()
{
enum weekday{sun, mon, tue, wed, thu, fri, sat}a, b, c; /定義枚舉類型weekday,并聲明枚舉變量a, b, c/
a = 1; // a = 1;這樣是不行的,因為這里是用一個整形的1來覆蓋a所代表的 enum
b = mon;
c = sat;
printf("%d, %d, %d", a, b, c);
printf("\n\n");
}
//輸出: 1, 1, 6
//例4
/#include <stdio.h>void main()
{
enum boy{Tom, Danny, Gan, LiLei}month[31], j;
int i;
j = Tom;
for( i=1; i <= 30; i++ )
{
month[i] = j;
j++;
if( j > LiLei )
{
j = Tom;
}
}
for( i=1; i <= 30; i++)
{
switch( month[i] )
{
case Tom: printf(" %4d %s\t", i, "Tom");
break;
case Danny: printf(" %4d %s\t", i, "Danny");
break;
case Gan: printf(" %4d %s\t", i, "Gan");
break;
case LiLei: printf(" %4d %s\t", i, "LiLei");
break;
default:
break;
}
}
printf("\n");
}
//輸出:
1 Tom 2 Danny 3 Gan 4 LiLei 5 Tom
6 Danny 7 Gan 8 LiLei 9 Tom 10 Danny
11 Gan 12 LiLei 13 Tom 14 Danny 15 Gan
16 LiLei 17 Tom 18 Danny 19 Gan 20 LiLei
21 Tom 22 Danny 23 Gan 24 LiLei 25 Tom
26 Danny 27 Gan 28 LiLei 29 Tom 30 Danny
- typedef
3.1 typedef的作用:用 typedef 聲明新的類型名來代替已有的類型名
3.2 用 typedef 定義類型
1)聲明 INTEGER 為整型:“typedef int INTEGER;” 見例5
//例5
/#include <stdio.h>
typedef int INTEGER;void main()
{
INTEGER i = 1;
int j = 2;
printf("%d, %d\n", i, j);
}
//輸出:1, 2
2)聲明結構類型
Typedef struct
{
int month ;
int day ;
int year ;
}DATE;
//例6
/#include <stdio.h>
typedef struct
{
int month;
int day;
int year;
}DATE;
void main()
{
DATE date_one;
date_one.month = 12;
date_one.day = 31;
date_one.year = 2017;
printf("%d - %d - %d \n", date_one.year, date_one.month, date_one.day);
}
//輸出: 2017-12-31
3)聲明NUM為整型數組類型:“typedef int NUM[100];” 見例7.
//例7
/#include <stdio.h>typedef int NUM[100];
void main()
{
NUM num = {0};
printf("%d\n", sizeof(num));
}
//輸出:400
4)聲明STRING為字符指針類型:“typedef char* STRING ;”見例8.
//例8.
/#include <stdio.h>typedef char* P; //聲明字符指針類型P
void main()
{
P p1;
p1 = "I love UNSW";
printf("%s\n", p1);
}
//輸出: I love UNSW
5)聲明P為函數指針類型:“typedef void (*P)();”見例9
//例9
/#include <stdio.h>typedef void (*P)(); //聲明函數指針類型P
void fun();
void main()
{
P p1; // 這里的p1等價于“void (*p1)();”即定義p1為函數指針類型P的實參
p1 = fun; //將函數fun()的入口地址賦給指針變量p1
( * p1)(); //函數指針通過調用函數實現輸出
}void fun()
{
printf("I love UNSW\n");
}
//輸出:I love UNSW
3.3 用 typedef 定義類型的方法
1)按定義變量的方法寫出定義體(如: int i )
2)將變量名換成新類型名(例如:將 i 換成 COUNT )。
3)在最前面加typedef (例如: typedef int COUNT )
4)然后可以用新類型名去定義變量(例如: COUNT i,j;)
3.2 關于typedef的說明
1)用 typedef 可以聲明各種類型名,但不能用來定義變量。
2)用 typedef 只是對已經存在的類型增加一個類型名,而沒有創造新的類型。
3)當不同源文件中用到同一類型數據時,常用 typedef 聲明一些數據類型,把它們單獨放在一個文件中,然后在需要用到它們的文件中用 #include命令把它們包含進來。
4)使用 typedef 有利于程序的通用與移植。
3.1 typedef 與 #define 的比較
相似:typedef 與 #define 有相似之處,例如: typedef int COUNT ; #define COUNT int 的作用都是用 COUNT 代表 int 。
區別:#define 是在預編譯時處理的,它只能作簡單的字符串替換,而 typedef 是在編譯時處理的。實際上它并不是作簡單的字符串替換,而是采用如同定義變量的方法那樣來聲明一個類型。
另外注意,“typedef (int * ) p1;”和“#define p2 int*” 一個有分號,一個沒有分號