如果說類是java中結構化數據類型的核心 , 那麼結構體就是C語言中結構化數據類型的核心 。在java中我們常有這樣的寫法:
public class Product { private String name ; private String desc ; // get set ... }
這種常見的javabean的寫法 , 在C語言中可以用結構體來表示 , 關鍵字struct:
struct Product {
char* productName;
char* productDesc;
};
在學習C語言的結構體的時候 , 我們可以類比成java中的類 , 只是這個類比較特殊,結構體中只有聲明 , 函數沒有實現 , 屬性也不能初始化 , 一般定義在頭文件中 。就好比聲明了一個抽象類 , 裡面什麼動作也不做 , 屬性只是聲明一樣 , 都需要繼承或是外部去賦值 。
結構體的簡單使用:
// 定義一個結構體
// 一個結構體相當於一個java中的類 , 結構體中只有聲明 , 函數沒有實現 , 屬性也不能初始化 , 一般定義在頭文件中
struct Person
{
char* name;
int age;
};
struct News {
// 使用字符數組 , 在賦值的時候和字符指針略有不同
char title[128];
char* content;
};
/*簡單使用結構體*/
void makeSimpleStruct() {
// 使用結構體 , 使用字面量的形式創建一個結構體
struct Person person = { "zeno",21 };
// 打印
printf("輸出:姓名 - %s ; 年齡 - %d\n", person.name, person.age);
//另一種創建結構體的方式
struct Person person2;
person2.name = "非我";
person2.age = 23;
printf("\n輸出:姓名 - %s ; 年齡 - %d\n", person2.name, person2.age);
struct News news;
//news.title 是字符數組 , 不能直接 news.title = "xxx" , 需要使用strcpy()函數
strcpy(news.title, "我是新聞標題");
news.content = " 我是新聞正文";
printf("\n\n輸出:\n標題 \n %s \n正文:\n %s\n", news.title, news.content);
}
友情提示:
1.結構體的兩種創建方式,①通過字面量的方式創建 。② 通過定義結構體變量然後給成員賦值 , 類似對象給成員屬性賦值。
2.字符數組的賦值,不能直接="xxx",而需要使用
strcpy()函數 。
結構體的多種寫法:
/*結構體的幾種寫法*/
// 在聲明結構體的時候 , 定義結構體變量和指針
struct Product {
char* productName;
char* productDesc;
}product , *productP;
// 匿名結構 , 沒有結構體名稱 , 可以定義多個結構體變量, 可作為單例使用
struct {
char * name;
int age;
}person;
/*結構體多種寫法的使用*/
void defineMultiStruct() {
// 在聲明結構體的時候定義結構變量 , 操作方便 , 不用再定義一遍
product.productName = "全新X系列寶馬 , X5";
product.productDesc = "無刮痕 , 全新X系列寶馬 , 享受駕駛愉悅 , 就開寶馬轎車";
printf("\n\n\n\n");
printf("產品信息:\n產品名稱:%s\n產品描述:%s\n",product.productName,product.productDesc);
printf("\n\n\n使用結構體指針 , 使用結構體指針不用.符號 , 使用->符號來操作結構體成員 , ->操作符是(*p).的簡寫 \n\n");
productP = &product;
printf("產品信息:\n產品名稱:%s\n產品描述:%s\n", productP->productName, productP->productDesc);
/*使用匿名結構體 , 始終只有一個結構體實例 , 可以作為單例來使用*/
person.name = "逝我";
person.age = 23;
printf("\n\n");
printf("用戶信息:\n用戶姓名:%s\n用戶年齡:%d\n", person.name, person.age);
}
友情提示:
1.結構體指針的操作 , 結構體指針使用的是->操作符,相當於
(*p).。
2.在結構體}xxx聲明的變量 , 相當於
struct structName xxx , 可以極大的簡化書寫。
結構嵌套:
/*結構體嵌套 , 兩種嵌套方式*/
struct Product {
char* productName;
char* productDesc;
};
// one
struct GoodsBean {
int total;
int status;
struct Goods {
char* goodsName;
char* goodsDesc;
};
};
// two
struct ProductBean
{
int total;
int status;
struct Product product;
};
/*結構嵌套示例*/
void nestingStruct() {
// one
printf("\n\n\n\n結構嵌套示例\n\n");
// 使用字面量的形式賦值
struct GoodsBean goodsBean = { 10,0,{ "全新Iphone6s","金色全新Iphone6s , 能與Android手機媲美的Iphone6s" } };
printf("商品總數:%d\n商品狀態:%d\n商品名稱:%s\n商品描述:%s\n", goodsBean.total, goodsBean.status, goodsBean.goodsName, goodsBean.goodsDesc);
// two
printf("\n\n");
struct ProductBean productBean;
productBean.total = 100;
productBean.status = 0;
productBean.product.productName = "金色經典 , 小米5 , 你值得擁有";
productBean.product.productDesc = "全新金色小米5 , 剛買沒幾個月";
printf("商品總數:%d\n商品狀態:%d\n商品名稱:%s\n商品描述:%s\n", productBean.total, productBean.status, productBean.product.productName, productBean.product.productDesc);
}
友情提示:
在結構體嵌套的時候 , 使用字面量創建結構體 , 嵌套的結構體也是使用{}來創建,so , 可能會出現
{{},{}}這樣的結構。
結構體數組:
struct Person
{
char* name;
int age;
};
/*結構體數組*/
void useStructArray() {
printf("\n\n\n\n結構體數組示例\n\n");
// 結構體數組
struct Person persons[] = { {"zeno",20},{"非我",24}, {"逝我",23} };
struct Person *p = &persons;
int personArrSize = sizeof(persons) / sizeof(struct Person);
printf("遍歷結構體數組:\n");
// 遍歷
for (; p < persons + personArrSize; p++)
{
printf("姓名:%s \t 年齡:%d\n", p->name, p->age);
}
}
友情提示:
結構體數組和一般數據操作差不多 , 使用{}創建結構體,通過數組指針運算來遍歷結構體數組 。
結構體動態內存分配
struct Person{
char* name;
int age;
};
/*結構體與動態內存分配*/
void structAndMalloc() {
printf("\n\n\n\n結構體與動態內存分配\n\n");
// 申請堆內存空間 , 空間地址是連續的
struct Person* person = (struct Person*)malloc(sizeof(struct Person) * 10);
struct Person* p = person;
p->name = "小九";
p->age = 20;
p++;
p->name = "非我";
p->age = 24;
printf("遍歷結構體動態內存:\n");
struct Person* loop_p = person;
// 遍歷
for (; loop_p < person + 2; loop_p++)
{
printf("姓名:%s \t 年齡:%d\n", loop_p->name, loop_p->age);
}
}
友情提示:
1. 因為申請的動態內存返回的指針是內存空間的首地址 , 所有可以通過指針運算p++ , 來進行結構體的賦值
2. 在遍歷動態的內存中的數據時候 , 需要從首地址開始遍歷 , 所以需要多次將首地址賦值給不同的指針變量。
結構體與函數指針
/*結構體與函數指針*/
struct Dog {
char* name;
int age;
void(*dogWow)(char* wow);
};
void dogWow(char* wow) {
printf("狗是:%s 叫\n", wow);
}
/*結構體與函數指針的使用*/
void useStructAndFunction() {
printf("\n\n\n\n");
printf("結構體中,函數沒有實現 , 在創建結構體時 , 將函數名稱賦值給函數指針即可\n");
struct Dog dog = { "小黃",3,dogWow };
dog.dogWow("汪汪。。。");
}
友情提示:
1.因為結構體中不能有函數實體 , 所以在創建結構體時 , 將函數名稱賦值給函數指針即可。
類型別名
/*類型別名 關鍵字:typedef*/
/*
1.不同名稱代表在做不同的事情typedef int jint;
2.不同情況下,使用不同的別名
3.書寫簡潔
*/
// 簡單別名
typedef char* Name;
// 結構體別名
typedef struct ImageInfo {
char* name;
int size;
char* path;
}ImageInfo , *ImageInfo_P;
/*修改文件名稱*/
void reFileName(ImageInfo_P imgeInfo_p, char* reName) {
imgeInfo_p->name = reName;
}
/*類型別名示例*/
void useTypedef() {
// 普通變量別名使用
printf("\n\n\n\n類型別名示例\n\n");
Name name = "zeno";
printf("類型別名:Name = %s\n", name);
/*結構體別名使用 , 和使用java對象類似*/
ImageInfo imageInfo;
char pathStr[120] = {"D://imag//"};
imageInfo.name = "美麗風景.jpg";
// 修改文件名稱
reFileName(&imageInfo, "大中國.jpg");
imageInfo.size = 2333;
// 拼接字符串
strcat(pathStr, imageInfo.name);
imageInfo.path = pathStr;
printf("\n\n文件信息:\n文件名:%s\n文件大小:%d kb\n文件路徑:%s\n", imageInfo.name, imageInfo.size, imageInfo.path);
}
友情提示:
結構體別名和在結構體}xxx; , 有說不同 , 別名只是給結構體重新起了個名字 , 本身不是結構體變量 , 不能像
}xxx;直接通過
xxx.xxx進行操作 , 別名還是需要聲明之後 , 才能進行
.xxx操作 。
在jni.h頭文件中 , 大量使用了結構體 , 所有學好結構體是看懂jni.h的第一步 , 下面我們來見識見識 , jni.h中的結構體:
/*
* JNI invocation interface.
*/
struct JNIInvokeInterface {
void* reserved0;
void* reserved1;
void* reserved2;
jint (*DestroyJavaVM)(JavaVM*);
jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);
jint (*DetachCurrentThread)(JavaVM*);
jint (*GetEnv)(JavaVM*, void**, jint);
jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);
};
友情提示:
jnit是int的別名
結語
結構體就介紹到這裡 , 下一篇我們來學習C語言中的IO操作 。