接續上篇[C語言基礎及指針⑥字符操作](http://www.jianshu.com/p/b7e6fc094087)
如果說類是java中結構化數據類型的核心 , 那么結構體就是C語言中結構化數據類型的核心 。在java中我們常有這樣的寫法:
```java
public class Product {
private String name ;
private String desc ;
// get set ...
}
```
這種常見的javabean的寫法 , 在C語言中可以用結構體來表示 , 關鍵字`struct`:
```c
struct Product {
char* productName;
char* productDesc;
};
```
在學習C語言的結構體的時候 , 我們可以類比成java中的類 , 只是這個類比較特殊,結構體中只有聲明 , 函數沒有實現 , 屬性也不能初始化 , 一般定義在頭文件中 。就好比聲明了一個抽象類 , 里面什么動作也不做 , 屬性只是聲明一樣 , 都需要繼承或是外部去賦值 。
### 結構體的簡單使用:
```c
// 定義一個結構體
// 一個結構體相當于一個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()`函數 。
### 結構體的多種寫法:
```c
/*結構體的幾種寫法*/
// 在聲明結構體的時候 , 定義結構體變量和指針
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` , 可以極大的簡化書寫。
### 結構嵌套:
```c
/*結構體嵌套 , 兩種嵌套方式*/
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 , 可能會出現`{{},{}}`這樣的結構。
### 結構體數組:
```c
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);
}
}
```
> 友情提示:
結構體數組和一般數據操作差不多 , 使用`{}`創建結構體,通過數組指針運算來遍歷結構體數組 。
### 結構體動態內存分配
```c
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. 在遍歷動態的內存中的數據時候 , 需要從首地址開始遍歷 , 所以需要多次將首地址賦值給不同的指針變量。
### 結構體與函數指針
```c
/*結構體與函數指針*/
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.因為結構體中不能有函數實體 , 所以在創建結構體時 , 將函數名稱賦值給函數指針即可。
### 類型別名
```c
/*類型別名 關鍵字: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中的結構體:
```c
/*
* 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操作 。
Android程序員學C系列:
[C語言基礎及指針①](http://www.jianshu.com/p/4701cd1e1914)
[C語言基礎及指針②之指針內存分析](http://www.jianshu.com/p/d556070b12ef)
[C語言基礎及指針③函數與二級指針](http://www.jianshu.com/p/184df8a1f195)
[C語言基礎及指針④函數指針](http://www.jianshu.com/p/181b50e02c89)
[C語言基礎及指針⑤動態內存分配](http://www.jianshu.com/p/93db7c692d1b)
[C語言基礎及指針⑥字符操作](http://www.jianshu.com/p/b7e6fc094087)
[C語言基礎及指針⑦結構體與指針](http://www.jianshu.com/p/36cc18151e87)
- 簡介
- C語言基礎及指針①語法基礎
- C語言基礎及指針②之指針內存分析
- C語言基礎及指針③函數與二級指針
- C語言基礎及指針④函數指針
- C語言基礎及指針⑤動態內存分配
- C語言基礎及指針⑥字符操作
- C語言基礎及指針⑦結構體與指針
- C語言基礎及指針⑧文件IO
- C語言基礎及指針⑨聯合體與枚舉
- C語言基礎及指針⑩預編譯及jni.h分析
- JNI開發系列①JNI概念及開發流程
- JNI開發系列②.h頭文件分析
- JNI開發系列③C語言調用Java字段與方法
- JNI開發系列④C語言調用構造方法
- JNI開發系列⑤對象引用的處理
- NDK開發基礎①使用Android Studio編寫NDK
- NDK開發基礎②文件加密解密與分割合并
- NDK開發基礎③增量更新之服務器端生成差分包
- C++基礎①命名空間結構體和引用