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*);
};

友情提示:
jint是int的别名

结语

结构体就介绍到这里 , 下一篇我们来学习C语言中的IO操作 。

Android程序员学C系列:
C语言基础及指针①
C语言基础及指针②之指针内存分析
C语言基础及指针③函数与二级指针
C语言基础及指针④函数指针
C语言基础及指针⑤动态内存分配
C语言基础及指针⑥字符操作
C语言基础及指针⑦结构体与指针
C语言基础及指针⑧文件IO
C语言基础及指针⑨联合体与枚举
C语言基础及指针⑩预编译及jni.h分析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,423评论 3 44
  • 一、框架 1、Mac系统及常用工具、进制;C数据类型、常量变量、运算符、表达式、格式化输入输出 2、关系运算符、逻...
    师景福阅读 675评论 0 1
  • 原文地址:C语言函数调用栈(一)C语言函数调用栈(二) 0 引言 程序的执行过程可看作连续的函数调用。当一个函数执...
    小猪啊呜阅读 4,585评论 1 19
  • 谁说只有恋人之间的才算情,才称得上爱?有一种情超过两个人的小爱,那是一群人凝聚成的爱,感觉到分别,突然发现我好爱好...
    培培de小事阅读 521评论 4 8
  • 微恙,躲在家里修身养息,谁也不理。夜跑后来杯红酒,顺手微信回复了找我几天的好友萝琳。于是一顿劈头盖脑的怒喝照...
    冷酷的猫阅读 451评论 0 1