程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> C語言基礎及指針⑦結構體與指針

C語言基礎及指針⑦結構體與指針

編輯:關於C

如果說類是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操作 。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved