C语言struct结构体介绍

目录
  • struct
  • struct的嵌套
  • 实验

struct

C 语言没有其他语言的对象(object)和类(class)的概念,struct 结构很大程度上提供了对象和类的功能。

下面是struct自定义数据类型的一个例子。

struct tag {
    member-list
    member-list
    member-list
    ...
} variable-list;

声明了数据类型car和该类型的变量car。

struct car
{
    char *name;
    float price;
    int speed;
} mycar;
struct car myca = {"大众", 178.9, 100};
mycar.name = "本田";

如果将 struct 变量传入函数,函数内部得到的是一个原始值的副本。

#include <stdio.h>
struct turtle {
  char* name;
  char* species;
  int age;
};
void happy(struct turtle t) {
  t.age = t.age + 1;
}
int main() {
  struct turtle myTurtle = {"MyTurtle", "sea turtle", 99};
  happy(myTurtle);
  printf("Age is %i\n", myTurtle.age); // 输出 99
  return 0;
}

上面示例中,函数happy()传入的是一个 struct 变量myTurtle,函数内部有一个自增操作。但是,执行完happy()以后,函数外部的age属性值根本没变。原因就是函数内部得到的是 struct 变量的副本,改变副本影响不到函数外部的原始数据。

指针变量也可以指向struct结构。

struct book {
  char title[500];
  char author[100];
  float value;
}* b1;

上面示例中,变量b1是一个指针,指向的数据是struct book类型的实例。

为了使用指向该结构的指针访问结构的成员,必须使用 -> 运算符,如下所示:

b1->title;//9-2.c
struct Books
{
    char title[50];
    char author[50];
    char subject[100];
    int book_id;
};
// 函数声明
void printBook(struct Books *books);
int main()
{
    struct Books Book1;
    struct Books Book2;
    /**
     * Book1 描述
     */
    strcpy(Book1.title, "C Programming");
    strcpy(Book1.author, "Nuha Ali");
    strcpy(Book1.subject, "C Programming Tutorial");
    Book1.book_id = 6495407;
    /* Book2 详述 */
    strcpy(Book2.title, "Telecom Billing");
    strcpy(Book2.author, "Zara Ali");
    strcpy(Book2.subject, "Telecom Billing Tutorial");
    Book2.book_id = 6495700;
    /* 通过传 Book1 的地址来输出 Book1 信息 */
    printBook(&Book1);
    /* 通过传 Book2 的地址来输出 Book2 信息 */
    printBook(&Book2);
    return 0;
}
void printBook(struct Books *book)
{
    printf("Book title : %s\n", book->title);
    printf("Book author : %s\n", book->author);
    printf("Book subject : %s\n", book->subject);
    printf("Book before book_id : %d\n", book->book_id);
    (*book).book_id = (*book).book_id + 1;
    printf("Book agter book_id : %d\n", book->book_id);
}

struct 结构也可以作为数组成员。下面示例声明了一个有1000个成员的数组books,每个成员都是自定义类型book的实例。

struct Books
{
    char title[50];
    char author[50];
    char subject[100];
    int book_id;
};
int main(int argc, char const *argv[])
{
    struct Books books[1000];
    books[0].book_id = 22;
    books[0].book_id = 7;
    return 0;
}

struct的嵌套

struct 结构的成员可以是另一个 struct 结构。

struct species {
  char* name;
  int kinds;
};
struct fish {
  char* name;
  int age;
  struct species breed;
};

上面示例中,fish的属性breed是另一个 struct 结构species。

// 写法三
struct fish shark = {
  .name="shark",
  .age=9,
  .breed={"Selachimorpha", 500}
};

引用breed属性的内部属性,要使用两次点运算符(shark.breed.name)。

对字符数组属性赋值,要使用strcpy()函数,不能直接赋值,因为直接改掉字符数组名的地址会报错。

strcpy(shark.breed.name), "Harry");

struct 结构内部不仅可以引用其他结构,还可以自我引用,即结构内部引用当前结构。比如,链表结构的节点就可以写成下面这样。

struct node {
  int data;
  struct node* next;
};

上面示例中,node结构的next属性,就是指向另一个node实例的指针。下面,使用这个结构自定义一个数据链表。

// p9-2.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    struct node
    {
        int data;
        struct node *next;
    };
    struct node *head;
    // 生成一个三个节点的列表 (11)->(22)->(33)
    head = malloc(sizeof(struct node));
    head->data = 11;
    head->next = malloc(sizeof(struct node));
    head->next->data = 22;
    head->next->next = malloc(sizeof(struct node));
    head->next->next->data = 33;
    head->next->next->next = NULL;
    // 遍历这个列表
    for (struct node *cur = head; cur != NULL; cur = cur->next)
    {
        printf("%d\n", cur->data);
    }
    return 0;
}

实验

考虑下面发这些声明和数据,并debug

#include <stdio.h>
int main(int argc, char const *argv[])
{
    struct NODE
    {
        int a;
        struct NODE *b;
        struct NODE *c;
    };
    // 5个成员的数组nodes
    struct NODE nodes[5] =
        {
            {5, nodes + 3, NULL},
            {15, nodes + 4, nodes + 3},
            {22, NULL, NULL},
            {12, nodes + 1, nodes},
            {18, nodes + 2, nodes + 1},
        };
    struct NODE *np = nodes + 2;
    struct NODE **npp = &nodes[1].b;
    /* nodes 是数组,数组名就是该数组的指针,也是该数组第一个元素的指针 */
    // 输出该数组的地址
    printf("nodes的地址是 %p\n", nodes); // 0x7ffeefbff460
    printf("nodes的地址是 %p \n", &nodes);
    printf("nodes+2的地址是 %p \n", nodes + 2);
    // printf("%d\n", nodes.a)//错误;指针访问属性 需要使用 ->
    printf("nodes[0] a的值 %d\n", nodes->a);    // 5 通过指针访问
    printf("(*nodes).a)的值 %d\n", (*nodes).a); // (*nodes)获取的是nodes[1]
    printf("nodes[3] a的值 %d\n", nodes[3].a); // 12
    printf("nodes[3].c的值 %p\n", nodes[3].c); //0x7ffeefbff460
    //  访问的是nodes[0]
    printf("nodes[3].c->a的值 %d\n", nodes[3].c->a); // 5
    // printf("%d\n", *nodes); 使用* 操作符对指针执行间接访问,*nodes的右值是nodes的整个结构
    // printf("%d\n", *nodes.a); //错误
    printf("nodes[4]的值地址 %p \n", &nodes[4]);
    printf("nodes[3].b->b的值 %p \n", nodes[3].b->b); //  nodes[3].b 获取的是 nodes + 1 即 nodes[1]的指针,然后nodes[1]->b ,就是nodes[4]的指针
    // [] () . ->  是一级运算 从左往右边 结合,  * &是二级运算
    printf("*nodes[3].b->b的值 %p \n", *nodes[3].b->b);  // {18, nodes + 2, nodes + 1},//最后运算*,由前边可以知道 nodes[3].b->b就是nodes[4]的指针,然后*,得到nodes[4]。看下一提题的验证
    printf("nodes[3] a 的值 %d \n", (*nodes[3].b->b).a); // 18
    printf("&nodes[3].a 的值%p \n", &nodes[3].a); // 数子12 第物理地址
    // printf("&nåodes[3].c %p \n", &nodes[3].c);
    printf("&nodes[3].c的值%p \n", &nodes[3].c->a); //数字15 的物理地址
    printf("&nodes->a 的值%p \n", &nodes->a);       //数字5 的物理地址
    printf("nodes+2的地址是 %p \n", nodes + 2);
    printf("np的值%p \n", np);       // np为nodes[2]的地址
    printf("np->a的值%d \n", np->a); // 12
    // printf("np->c->c->a的值%d \n", np->c->c->a); // 12
    printf("npp的值%p \n", npp); // np为nodes[2]的地址
    // printf("npp->a的值%p \n", npp->a); // 非法
    printf("*npp的值%p \n", *npp);
    printf("**npp的值%p \n", **npp);
    return 0;
}

到此这篇关于C语言struct结构体介绍的文章就介绍到这了,更多相关C语言struct内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言中结构体(struct)的几种初始化方法

    本文给大家总结的struct数据有3种初始化方法 1.顺序 2.C风格的乱序 3.C++风格的乱序 下面通过示例代码详细介绍这三种初始化方法. 1)顺序 这种方法很常见,在一般的介绍C的书中都有介绍.顺序初始化的特点是: 按照成员定义的顺序,从前到后逐个初始化:允许只初始化部分成员:在被初始化的成员之前,不能有未初始化的成员. 示例: struct User oneUser = {10, "Lucy", "/home/Lucy"}; 2)乱序(C风格) 顺序的缺陷是

  • C语言 struct结构体超详细讲解

    目录 一.本章重点 二.创建结构体 三.typedef与结构体的渊源 四.匿名结构体 五.结构体大小 六.结构体指针 七.其他 一.本章重点 创建结构体 typedef与结构体的渊源 匿名结构体 结构体大小 结构体指针 其他 二.创建结构体 先来个简单的结构体创建 这就是一个比较标准的结构体 struct people { int age; int id; char address[10]; char sex[5]; };//不要少了分号. 需要注意的是不要少了分号. 那么这样创建结构体呢? s

  • 详解C语言中结构体(struct)的用法

    目录 粉丝问答 三种结构体类型变量说明 1. 先定义结构,再定义结构变量 2. 定义结构体类型的同时说明变量 3. 直接说明结构变量 结构体成员表示方法 结构体指针做参数 结构体初始化 定义变量的同时初始化 先定义在初始化 常用初始化 typedef与struct 前置声明 结构体对齐 粉丝问答 有个粉丝在群里问了这样一个问题,问题在图中已经标出,如下图. DQuestsion 头文件的结构体的定义为: typedef struct{ u8 bmRequestType; u8 bRequest;

  • C语言结构体(struct)的详细讲解

    目录 引言 1. 动态内存管理 2. 结构体 2.1 定义语法 2.2 定义示例 2.3 初始化 2.4 结构体赋值 2.5 结构体数组 2.6 结构体指针赋值 3. 学生管理系统 附:结构体变量的存储原理 总结 引言 当前文章介绍动态堆空间内存分配与释放,C语言结构体定义.初始化.赋值.结构体数组.结构体指针的相关知识点,最后通过一个学生管理系统综合练习结构体数组的使用. 1. 动态内存管理 C语言代码----->编译----->链接------>可执行的二进制文件(windows下x

  • C语言结构体(struct)常见使用方法(细节问题)

    基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量. 结构体定义: 第一种:只有结构体定义 struct stuff{ char job[20]; int age; float height; }; 第二种:附加该结构体类型的"结构体变量"的初始化的结构体定义 //直接带变量名Huqinwei struct stuff{ char job[20]; int age; floa

  • C语言结构体struct详解

    目录 结构体的概念 结构体类型的声明 结构体变量的创建 typedef关键字 结构体的嵌套 结构体变量的初始化 结构体成员的访问 结构体的传参 总结 结构体的概念 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合.组成结构型数据的每个数据称为结构型数据的“成员”.结构体通常用来表示类型不同但是又相关的若干数据. 结构体类型的声明 结构体类型的声明要使用 s t r u c t \color{#0000FF}{ struct} struct关键字,举个例子,比如我要定义一个学生的结构体类

  • C语言 结构体(Struct)详解及示例代码

    前面的教程中我们讲解了数组(Array),它是一组具有相同类型的数据的集合.但在实际的编程过程中,我们往往还需要一组类型不同的数据,例如对于学生信息登记表,姓名为字符串,学号为整数,年龄为整数,所在的学习小组为字符,成绩为小数,因为数据类型不同,显然不能用一个数组来存放. 在C语言中,可以使用结构体(Struct)来存放一组不同类型的数据.结构体的定义形式为: struct 结构体名{     结构体所包含的变量或数组 }; 结构体是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可

  • C语言struct结构体介绍

    目录 struct struct的嵌套 实验 struct C 语言没有其他语言的对象(object)和类(class)的概念,struct 结构很大程度上提供了对象和类的功能. 下面是struct自定义数据类型的一个例子. struct tag { member-list member-list member-list ... } variable-list; 声明了数据类型car和该类型的变量car. struct car { char *name; float price; int spe

  • C语言一看就懂的指针与结构体介绍

    目录 指针 结构体 指针 指针是C语言或者是c++里面最让人头疼的内容之一,正所谓指针在手,可以任指天下,这里只是简单的介绍指针的一些概念,后期我们将会深入剖析指针的基本原理. 注意:一个汉字占2个字节! 首先我们需要认识一下内存这个基本概念: 内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的,为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节,为了能够有效的访问到内存中的每个单元,就把内存单元进行了编号,这些编号被称为内存单元的地址. #inc

  • Go语言中结构体方法副本传参与指针传参的区别介绍

    GO语言结构体方法跟结构体指针方法的区别 首先,我定了三个接口.一个结构和三个方法: type DeptModeA interface { Name() string SetName(name string) } type DeptModeB interface { Relocate(building string, floor uint8) } type Dept struct { name string building string floor uint8 Key string } fun

  • C语言中结构体、联合体的成员内存对齐情况

    前言 最近项目进行中,遇到一个小问题,在数据协议传输过程中,我为了方便解析,就定义了一个结构体,在数据的指针传入函数的时候,我用定义好的结构体进行强制转化,没想到一直解析失败,调试很久,终于反应过来,在用结构体指针对数据强制转换时,定义结构体我没有注意到数据对齐,因为在底层实现中,我传入的数据buffer是排列整齐的,而强制转化的结构体格式中,我定义的时候没有使用__attribute__((__packed__))或者__packed强制数据对齐,导致结构体成员真实排列会按照成员中最大的变量的

  • C语言中结构体和共用体实例教程

    目录 一.实验目的 二.实验内容 三.实验记录 3.1 候选人选票统计 3.2 print函数 3.3 链表 总结 一.实验目的 掌握结构体类型变量的定义和使用: 掌握结构体类型数组的概念和应用: 掌握链表的概念,初步学会对链表进行操作: 掌握共用体的概念与使用: 掌握指向结构体变量的指针. 掌握指向结构体数组的指针的应用. 二.实验内容 编写下列程序,然后上机调试运行. 对候选人得票的统计程序.设有3个候选人,每次输入一个得票的候选人的名字,要求最后输出各人得票结果. 编写一个函数print,

  • C语言中结构体与内存对齐实例解析

    1.结构体类型 C语言中的2种类型:原生类型和自定义类型,结构体类型是一种自定义类型. 2.结构体使用时先定义结构体类型再用类型定义变量 -> 结构体定义时需要先定义结构体类型,然后再用类型来定义变量. -> 也可以在定义结构体类型的同时定义结构体变量. // 定义类型 struct people { char name[20]; int age; }; // 定义类型的同时定义变量. struct student { char name[20]; int age; }s1; // 将类型st

  • Go语言之结构体与方法

    目录 一.结构体 1.结构体的定义与使用 2.定义并赋初值 3.匿名结构体(只使用一次,没有名字) 4.结构体的零值 5.结构体的指针 6.匿名字段(字段没有名字,只有类型) 7.嵌套结构体(结构体中套结构体) 8.字段提升 9.结构体相等性 二.方法 1.方法的定义和使用 2.有了函数为啥还需要方法? 3.指针接收器与值接收器 5.匿名字段的方法(方法提升) 6.在方法中使用值接收器 与 在函数中使用值参数 7.在方法中使用指针接收器 与 在函数中使用指针参数 8.非结构体上绑定方法 一.结构

  • Go语言空结构体详解

    目录 前言 什么是空结构体 特点 地址相同 大小为0 原理探究 使用场景 集合(Set) channel中信号传输 总结 前言 在使用 Go 语言开发过程中,我们不免会定义结构体,但是我们定义的结构体都是有字段的,基本不会定义不包含字段的 空结构体.你可能会反过来问,没有字段的空结构体有什么用呢?那么我们这篇文章就来研究下空结构体吧! 注:本文基于go 1.14.4 分析 什么是空结构体 我们说不包含任何字段的结构体叫做空结构体,可以通过如下的方式定义空结构体: 原生定义 var a struc

随机推荐