C語言-結構體、共用體,內存管理
結構體
-
結構體的定義及變量使用
#include <stdio.h> #include <string.h> struct student { char name[20]; int age; char sex; }stu3; // 定義結構體的同時定義結構體變量。此時是全局變量 int main(int argc, char const *argv[]) { struct student stu1, stu2; // 定義結構體變量 strcpy(stu1.name, "zs"); stu1.age = 20; stu1.sex = 'M'; stu2 = stu1; // 同類型結構體可以賦值 strcpy(stu2.name, "ls"); stu3 = stu1; strcpy(stu3.name, "ww"); // 不能把它作為一個整體參加數據處理,參加各種運算和操作的是結構體變量的成員項數據 printf("%s,%d,%c\n", stu1.name,stu1.age,stu1.sex); printf("%s,%d,%c\n", stu2.name,stu2.age,stu2.sex); printf("%s,%d,%c\n", stu3.name,stu3.age,stu3.sex); } -
結構體變量初始化
#include <stdio.h> #include <string.h> struct student { char name[20]; int age; char sex; }stu2 = {"ls",20,'M'}; // 變量初始化 int main(int argc, char const *argv[]) { struct student stu1 = {"zs",18,'M'}; // 變量初始化 // struct student stu3; // stu3 = {"zs",18,'M'}; // 錯誤寫法 printf("%s,%d,%c\n", stu1.name,stu1.age,stu1.sex); printf("%s,%d,%c\n", stu2.name,stu2.age,stu2.sex); } -
結構體作為成員變量
#include <stdio.h> #include <string.h> struct birthday { int year; int month; int day; }; struct student { char name[20]; struct birthday date; // 結構體作為成員變量 char sex; }stu1={"zs",{2000,05,20},'M'}; int main(int argc, char const *argv[]) { struct student stu2; stu2 = stu1; stu2.date.year = 1999; printf("%s,%d-%d-%d,%c\n", stu1.name,stu1.date.year,stu1.date.month,stu1.date.day,stu1.sex); printf("%s,%d-%d-%d,%c\n", stu2.name,stu2.date.year,stu2.date.month,stu2.date.day,stu2.sex); } -
無名結構體
#include <stdio.h> #include <string.h> struct student { char name[20]; struct { // 無名結構體 int year; int month; int day; }date; char sex; }stu1={"zs",{2000,05,20},'M'}; int main(int argc, char const *argv[]) { printf("%s,%d-%d-%d,%c\n", stu1.name,stu1.date.year,stu1.date.month,stu1.date.day,stu1.sex); } -
結構體數組
#include <stdio.h> #include <string.h> struct student { char name[20]; int age; char sex; }stu1[5]={"zs",20,'M'}; int main(int argc, char const *argv[]) { struct student stu2[5] = {{"zs",20,'M'},{"ww",19,'M'}}; int i; for (i = 0; i < sizeof(stu2)/sizeof(struct student); ++i) { printf("%s,%d,%c\n", stu2[i].name,stu2[i].age,stu2[i].sex); } } -
結構體指針
#include <stdio.h> #include <string.h> struct student { char name[20]; int age; char sex; }; int main(int argc, char const *argv[]) { struct student stu[5] = {{"zs",20,'M'},{"ww",19,'M'}}; struct student * p; // 結構體指針 p = stu; int i; for (i = 0; i < sizeof(stu)/sizeof(struct student); ++i) { printf("%s,%d,%c\n", (*p).name, p->age, p->sex); // 結構體指針訪問成員變量 p++; } }
共用體
- 概念:
- 在C語言中,不同數據類型的數據可以使用共同的存儲區域,這種數據構造類型稱為共用體,簡稱共用,又稱聯合體。共用體在定義、說明和使用形式上與結構體相似。兩者本質上的不同僅在于使用內存的方式上。
- 由于共用體中各成員的數據長度往往不同,所以共用體變量在存儲時總是按其成員中數據長度最大的成員占用內存空間。
#include <stdio.h> #include <string.h> union student { char name[20]; int age; char sex; }; int main(int argc, char const *argv[]) { union student stu; strcpy(stu.name, "zs"); stu.age = 20; stu.sex = 'M'; printf("%s,%c,%c\n", stu.name, stu.age, stu.sex); // M,M,M printf("%d\n", sizeof(union student)); // 20 // union student stu3[5] = {{"zs",20,'M'},{"ww",19,'M'}}; // 報錯 // union student stu2 = {"zs",20,'M'}; // 報錯 }
typedef
-
typedef 定義別名
#include <stdio.h> #include <string.h> typedef struct student { char name[20]; int age; char sex; }student,STUDENT,*pStu; // 兩個結構體別名,一個指針結構體別名 int main(int argc, char const *argv[]) { student stu; //等價于 struct student stu strcpy(stu.name, "zs"); stu.age = 20; stu.sex = 'M'; pStu p = &stu; // 等價于 struct student *p = &stu; printf("%s\n", p->name); printf("%s,%d,%c\n", stu.name, stu.age, stu.sex); }#include <stdio.h> #include <string.h> struct student { char name[20]; int age; char sex; }; typedef struct student student; int main(int argc, char const *argv[]) { student stu; //等價于 struct student stu }
內存管理
-
C語言定義了4個內存區間:
- 代碼區
- 全局變量與靜態變量區
- 通常定義變量,編譯器在編譯時都可以根據該變量的類型知道所需內存空間的大小,從而系統在適當的時候為他們分配確定的存儲空間。
- 局部變量區即棧區
- 在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。
- 動態存儲區,即堆區
- 有些操作對象只有在程序運行時才能確定,這樣編譯器在編譯時就無法為他們預定存儲空間,只能在程序運行時,系統根據運行時的要求進行內存分配。
- 從堆上分配,亦稱動態內存分配。
-
動態內存管理malloc/free
void * malloc(size_t num)1. malloc函數本身并不識別要申請的內存是什么類型,它只關心內存的總字節數。 2. malloc申請到的是一塊連續的內存,有時可能會比所申請的空間大。其有時會申請不到內存,返回NULL。 3. malloc返回值的類型是void *,所以在調用malloc時要顯式地進行類型轉換,將void * 轉換成所需要的指針類型。 4. 如果free的參數是NULL的話,沒有任何效果。 5. 釋放一塊內存中的一部分是不被允許的。void free(void *p)1. 刪除一個指針p(free(p);),實際意思是刪除了p所指的目標(變量或對象等),釋放了它所占的堆空間,而不是刪除p本身,釋放堆空間后,p成了空懸指針 2. malloc與free是配對使用的, free只能釋放堆空間。如果malloc返回的指針值丟失,則所分配的堆空間無法回收,稱內存泄漏,同一空間重復釋放也是危險的,因為該空間可能已另分配,所以必須妥善保存malloc返回的指針,以保證不發生內存泄漏,也必須保證不會重復釋放堆內存空間。#include <stdio.h> #include <stdlib.h> char * get_string(){ char * s; s = (char *)malloc(10 * sizeof(char)); // 堆空間 scanf("%s", s); // s = "wecolme"; // 字符串常量,靜態變量區。此時free(p)報錯 return s; } int main(int argc, char const *argv[]) { char * p; p = get_string(); printf("%s\n", p); free(p); // 釋放堆空間 p = NULL; // p指針占用內容在棧空間。不置為空指針的話,就是空懸指針(野指針) return 0; } -
野指針
不是NULL指針,是指向“垃圾”內存的指針。“野指針”是很危險的。
野指針的成因主要有兩種:
1. 指針變量沒有被初始化。
2. 指針p被free之后,沒有置為NULL,讓人誤以為p是個合法的指針。
3. 指針操作超越了變量的作用范圍。#include <stdio.h> #include <string.h> int main(int argc, char const *argv[]) { char * p; // p指針未初始化,此時指向的是一個隨機的地址,直接使用將報錯 strcpy(p,"hello"); char * q; // p指針未初始化,此時指向的是一個隨機的地址,直接使用將報錯 *q = 'A'; return 0; }#include <stdio.h> #include <string.h> int main(int argc, char const *argv[]) { char s[] = "wel"; char * p; p = s; strcpy(p,"welcome"); // 指針操作超越了變量的范圍 return 0; }

浙公網安備 33010602011771號