結構體
概述
數組:描述一組具有相同類型數據的有序集合,用於處理大量相同類型的數據運算。
有時我們需要將不同類型的數據組合成一個有機的整體,如:一個學生有學號/姓名/性別/年齡/地址等屬性。顯然單獨定義以上變量比較繁瑣,數據不便於管理。
C語言中給出了另一種構造數據類型——結構體。
結構體變量的定義和初始化
定義結構體變量的方式:
- 先聲明結構體類型再定義變量名
- 在聲明類型的同時定義變量
- 直接定義結構體類型變量(無類型名)
結構體類型和結構體變量關係: - 結構體類型:指定了一個結構體類型,它相當於一個模型,但其中並無具體數據,系統對之也不分配實際內存單元。
- 結構體變量:系統根據結構體類型(內部成員狀況)爲之分配空間。
//結構體類型的定義
struct stu
{
char name[50];
int age;
};
//先定義類型,再定義變量(常用)
struct stu s1 = { "mike", 18 };
//定義類型同時定義變量
struct stu2
{
char name[50];
int age;
}s2 = { "lily", 22 };
struct
{
char name[50];
int age;
}s3 = { "yuri", 25 };
結構體成員的使用
#include<stdio.h>
#include<string.h>
//結構體類型的定義
struct stu
{
char name[50];
int age;
};
int main()
{
struct stu s1;
//如果是普通變量,通過點運算符操作結構體成員
strcpy(s1.name, "abc");
s1.age = 18;
printf("s1.name = %s, s1.age = %d\n", s1.name, s1.age);
//如果是指針變量,通過->操作結構體成員
strcpy((&s1)->name, "test");
(&s1)->age = 22;
printf("(&s1)->name = %s, (&s1)->age = %d\n", (&s1)->name, (&s1)->age);
return 0;
}
結構體數組
#include <stdio.h>
//統計學生成績
struct stu
{
int num;
char name[20];
char sex;
float score;
};
int main()
{
//定義一個含有5個元素的結構體數組並將其初始化
struct stu boy[5] = {
{ 101, "Li ping", 'M', 45 },
{ 102, "Zhang ping", 'M', 62.5 },
{ 103, "He fang", 'F', 92.5 },
{ 104, "Cheng ling", 'F', 87 },
{ 105, "Wang ming", 'M', 58 }};
int i = 0;
int c = 0;
float ave, s = 0;
for (i = 0; i < 5; i++)
{
s += boy[i].score; //計算總分
if (boy[i].score < 60)
{
c += 1; //統計不及格人的分數
}
}
printf("s=%f\n", s);//打印總分數
ave = s / 5; //計算平均分數
printf("average=%f\ncount=%d\n\n", ave, c); //打印平均分與不及格人數
for (i = 0; i < 5; i++)
{
printf(" name=%s, score=%f\n", boy[i].name, boy[i].score);
// printf(" name=%s, score=%f\n", (boy+i)->name, (boy+i)->score);
}
return 0;
}
結構體套結構體
#include <stdio.h>
struct person
{
char name[20];
char sex;
};
struct stu
{
int id;
struct person info;
};
int main()
{
struct stu s[2] = { 1, "lily", 'F', 2, "yuri", 'M' };
int i = 0;
for (i = 0; i < 2; i++)
{
printf("id = %d\tinfo.name=%s\tinfo.sex=%c\n", s[i].id, s[i].info.name, s[i].info.sex);
}
return 0;
}
結構體賦值
#include<stdio.h>
#include<string.h>
//結構體類型的定義
struct stu
{
char name[50];
int age;
};
int main()
{
struct stu s1;
//如果是普通變量,通過點運算符操作結構體成員
strcpy(s1.name, "abc");
s1.age = 18;
printf("s1.name = %s, s1.age = %d\n", s1.name, s1.age);
//相同類型的兩個結構體變量,可以相互賦值
//把s1成員變量的值拷貝給s2成員變量的內存
//s1和s2只是成員變量的值一樣而已,它們還是沒有關係的兩個變量
struct stu s2 = s1;
//memcpy(&s2, &s1, sizeof(s1));
printf("s2.name = %s, s2.age = %d\n", s2.name, s2.age);
return 0;
}
結構體和指針
- 指向普通結構體變量的指針
#include<stdio.h>
//結構體類型的定義
struct stu
{
char name[50];
int age;
};
int main()
{
struct stu s1 = { "lily", 18 };
//如果是指針變量,通過->操作結構體成員
struct stu *p = &s1;
printf("p->name = %s, p->age=%d\n", p->name, p->age);
printf("(*p).name = %s, (*p).age=%d\n", (*p).name, (*p).age);
return 0;
}
- 堆區結構體變量
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
//結構體類型的定義
struct stu
{
char name[50];
int age;
};
int main()
{
struct stu *p = NULL;
p = (struct stu *)malloc(sizeof(struct stu));
//如果是指針變量,通過->操作結構體成員
strcpy(p->name, "test");
p->age = 22;
printf("p->name = %s, p->age=%d\n", p->name, p->age);
printf("(*p).name = %s, (*p).age=%d\n", (*p).name, (*p).age);
free(p);
p = NULL;
return 0;
}
- 結構體套一級指針
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
//結構體類型的定義
struct stu
{
char *name; //一級指針
int age;
};
int main()
{
struct stu *p = NULL;
p = (struct stu *)malloc(sizeof(struct stu));
p->name = malloc(strlen("test") + 1);
strcpy(p->name, "test");
p->age = 22;
printf("p->name = %s, p->age=%d\n", p->name, p->age);
printf("(*p).name = %s, (*p).age=%d\n", (*p).name, (*p).age);
if (p->name != NULL)
{
free(p->name);
p->name = NULL;
}
if (p != NULL)
{
free(p);
p = NULL;
}
return 0;
}
結構體做函數參數
- 結構體普通變量做函數參數
#include<stdio.h>
#include <string.h>
//結構體類型的定義
struct stu
{
char name[50];
int age;
};
//函數參數爲結構體普通變量
void set_stu(struct stu tmp)
{
strcpy(tmp.name, "mike");
tmp.age = 18;
printf("tmp.name = %s, tmp.age = %d\n", tmp.name, tmp.age);
}
int main()
{
struct stu s = { 0 };
set_stu(s); //值傳遞
printf("s.name = %s, s.age = %d\n", s.name, s.age);
return 0;
}
- 結構體指針變量做函數參數
#include<stdio.h>
#include <string.h>
//結構體類型的定義
struct stu
{
char name[50];
int age;
};
//函數參數爲結構體指針變量
void set_stu_pro(struct stu *tmp)
{
strcpy(tmp->name, "mike");
tmp->age = 18;
}
int main()
{
struct stu s = { 0 };
set_stu_pro(&s); //地址傳遞
printf("s.name = %s, s.age = %d\n", s.name, s.age);
return 0;
}
- 結構體數組名做函數參數
#include<stdio.h>
//結構體類型的定義
struct stu
{
char name[50];
int age;
};
//void set_stu_pro(struct stu tmp[100], int n)
//void set_stu_pro(struct stu tmp[], int n)
void set_stu_pro(struct stu *tmp, int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
sprintf(tmp->name, "name%d%d%d", i, i, i);
tmp->age = 20 + i;
tmp++;
}
}
int main()
{
struct stu s[3] = { 0 };
int i = 0;
int n = sizeof(s) / sizeof(s[0]);
set_stu_pro(s, n); //數組名傳遞
for (i = 0; i < n; i++)
{
printf("%s, %d\n", s[i].name, s[i].age);
}
return 0;
}
- const修飾結構體指針形參變量
//結構體類型的定義
struct stu
{
char name[50];
int age;
};
void fun1(struct stu * const p)
{
//p = NULL; //err
p->age = 10; //ok
}
//void fun2(struct stu const* p)
void fun2(const struct stu * p)
{
p = NULL; //ok
//p->age = 10; //err
}
void fun3(const struct stu * const p)
{
//p = NULL; //err
//p->age = 10; //err
}
共用體(聯合體)
- 聯合union是一個能在同一個存儲空間存儲不同類型數據的類型;
- 聯合體所佔的內存長度等於其最長成員的長度,也有叫做共用體;
- 同一內存段可以用來存放幾種不同類型的成員,但每一瞬時只有一種起作用;
- 共用體變量中起作用的成員是最後一次存放的成員,在存入一個新的成員後原有的成員的值會被覆蓋;
- 共用體變量的地址和它的各成員的地址都是同一地址。
#include <stdio.h>
//共用體也叫聯合體
union Test
{
unsigned char a;
unsigned int b;
unsigned short c;
};
int main()
{
//定義共用體變量
union Test tmp;
//1、所有成員的首地址是一樣的
printf("%p, %p, %p\n", &(tmp.a), &(tmp.b), &(tmp.c));
//2、共用體大小爲最大成員類型的大小
printf("%lu\n", sizeof(union Test));
//3、一個成員賦值,會影響另外的成員
//左邊是高位,右邊是低位
//低位放低地址,高位放高地址
tmp.b = 0x44332211;
printf("%x\n", tmp.a); //11
printf("%x\n", tmp.c); //2211
tmp.a = 0x00;
printf("short: %x\n", tmp.c); //2200
printf("int: %x\n", tmp.b); //44332200
return 0;
}
枚舉
枚舉:將變量的值一一列舉出來,變量的值只限於列舉出來的值的範圍內。
枚舉類型定義:
enum 枚舉名
{
枚舉值表
};
- 在枚舉值表中應列出所有可用值,也稱爲枚舉元素。
- 枚舉值是常量,不能在程序中用賦值語句再對它賦值。
- 舉元素本身由系統定義了一個表示序號的數值從0開始順序定義爲0,1,2 …
#include <stdio.h>
enum weekday
{
sun = 2, mon, tue, wed, thu, fri, sat
} ;
enum bool
{
flase, true
};
int main()
{
enum weekday a, b, c;
a = sun;
b = mon;
c = tue;
printf("%d,%d,%d\n", a, b, c);
enum bool flag;
flag = true;
if (flag == 1)
{
printf("flag爲真\n");
}
return 0;
}
typedef
typedef爲C語言的關鍵字,作用是爲一種數據類型(基本類型或自定義數據類型)定義一個新名字,不能創建新類型。
- 與#define不同,typedef僅限於數據類型,而不是能是表達式或具體的值
- #define發生在預處理,typedef發生在編譯階段
#include <stdio.h>
typedef int INT;
typedef char BYTE;
typedef BYTE T_BYTE;
typedef unsigned char UBYTE;
typedef struct type
{
UBYTE a;
INT b;
T_BYTE c;
}TYPE, *PTYPE;
int main()
{
TYPE t;
t.a = 254;
t.b = 10;
t.c = 'c';
PTYPE p = &t;
printf("%u, %d, %c\n", p->a, p->b, p->c);
return 0;
}