首页 > 其他分享 >【C语言】结构体structure

【C语言】结构体structure

时间:2024-04-09 18:00:41浏览次数:13  
标签:name age struct C语言 person job structure 结构

【C语言】结构体structure:

  • C语言可以自定义数据类型。结构体是其中一个自定义的数据类型。
  • 结构体类型是复杂的数据类型,将多个不同数据按一定功能进行整体封装,用一个名称来给结构体命名。可用typedef为结构体提供别名。
  • 关键字struct。结构体包括结构体名称、结构体成员(由成员类型和成员变量名组成)。
  • 结构体中各成员的类型可以不同,可以是基本数据类型,也可以其它结构体或指针等。
  • 需要定义结构体类型。结构体可以作为变量,需要定义该类型的变量。结构体也可以作为函数参数传递,也可以作为函数的返回类型。结构体还可以定义更复杂的抽象数据类型(链表、树等)。

1、定义结构体类型

结构体类型:

关键字struct。结构体包括结构体名称、结构体的成员(由成员类型和成员变量名称组成)。

结构体中各成员的类型可以不同,可以是基本数据类型,也可以其它结构体或指针等。

注意:

① 最后的分号";"不能省略。

② 一般在所有函数之前(即预处理阶段)定义结构体类型。

struct 结构体名称          //结构体名称:即结构体标签
{
    结构体的成员1;         // 结构体的成员:由成员类型和成员变量名称组成
    结构体的成员2;              
    ...
};
// 例如:名为person的结构体,成员变量有字符串name,整数age,字符串job
struct person
{
    char name[32];
    int age;
    char job[16];
};

2、结构体作为变量

(2-1)定义结构体变量

定义结构体类型后,定义结构体变量。可以定义一个或多个结构体变量。

注意:

① 定义结构体类型,不会分配内存。定义结构体变量后,才会为变量分配内存。

② 一般在所有函数之前定义结构体类型。在具体函数中定义局部的结构体变量。

③ 结构体变量名可以和结构体名称相同。

struct person
{
    char name[32];
    int age;
    char job[16];
};

struct person p;                   // 定义一个结构体变量
struct person p1, p2, p3;          // 定义多个结构体变量
struct person p1, p2[60], *p3;     // 定义多个结构体变量

(2-2)访问结构体成员

使用成员访问运算符(".")来访问结构体成员,即:结构体变量名.结构体成员变量名。

#include <stdio.h>
#include <string.h>

struct person
{
    char name[32];
    int age;
    char job[16];
};

int main(void)
{
    struct person p; 

    strcpy(p.name, "Mark");
    p.age = 25;
    strcpy(p.job, "teacher");

    printf("p.name = %s, p.age = %d, p.job = %s\n", p.name, p.age, p.job);
    return 0;
}

// 结果:
p.name = Mark, p.age = 25, p.job = teacher

补充:

也可以在定义结构体类型的时候定义结构体变量,在结构体的末尾大括号{ }外 最后一个分号;前。可以定义一个或多个结构体变量。

定义结构体变量时可以给变量设置初始值,可以使用成员访问运算符(".")访问结构体成员。

注意:若在所有函数之前定义结构体类型,则同时定义的结构体变量就是全局变量。

#include <stdio.h>

struct person
{
    char name[32];
    int age;
    char job[16];
} p = {"Jack",18,"programmer"};     // 定义结构体类型时,定义一个结构体变量

int main(void)
{
    printf("p.name = %s, p.age = %d, p.job = %s\n", p.name, p.age, p.job);
    return 0;
}

// 结果:
p.name = Jack, p.age = 18, p.job = programmer
#include <stdio.h>

struct person
{
    char name[32];
    int age;
    char job[16];
} p[] = {                             // 定义结构体类型时,定义一个结构体数组变量
    {"Jack",18,"programmer"},
    {"Mark",25,"teacher"}
};

int main(void)
{
    int n = sizeof(p) / sizeof(struct person);   // 获取数组元素个数
    for(int i = 0;i < n;i++)
    {
        printf("p[%d].name = %s, p[%d].age = %d, p[%d].job = %s\n", i, p[i].name, i, p[i].age, i, p[i].job);
    }   
    return 0;
}

// 结果:
p[0].name = Jack, p[0].age = 18, p[0].job = programmer
p[1].name = Mark, p[1].age = 25, p[1].job = teacher

3、结构体作为函数参数

结构体作为参数传给函数,传入方式与其它类型变量或指针相同。

注意:结构体作为函数参数,向函数传递的是结构体副本,不会修改原结构体内容。若要修改原结构体内容,则使用结构体指针作为函数参数。

#include <stdio.h>

struct person
{
    char name[32];
    int age;
    char job[16];
};

void changestruct(struct person person);

int main(void)
{
    struct person p; 

    strcpy(p.name, "John");
    p.age = 18;
    strcpy(p.job, "programmer");
    printf("programmer: %s, age %d\n", p.name, p.age);
    changestruct(p);                        // 结构体作为参数传入函数
    printf("End: programmer: %s, age %d\n", p.name, p.age);

    return 0;
}

void changestruct(struct person person)    // 参数类型是结构体类型 
{    
    person.age = 22;                  // 不修改原结构体
    printf("After: programmer: %s, age %d\n", person.name, person.age);
}

// 结果:
programmer: John, age 18
After: programmer: John, age 22
End: programmer: John, age 18

4、结构体作为函数返回值

函数若返回结构体,则函数的返回类型是结构体类型,需有结构体变量接收函数返回的结构体。

#include <stdio.h>
#include <string.h>

struct person
{
    char name[32];
    int age;
    char job[16];
};

struct person getstruct(void);         // 函数返回类型是结构体类型

int main(void)
{
    struct person p;                  // 定义结构体变量
    p = getstruct();                  // 接收函数返回的结构体
    
    if(strcmp(p.job, "programmer") == 0)
        printf("programmer: %s, age %d\n", p.name, p.age);

    return 0;
}

struct person getstruct(void)         // 函数返回类型是结构体类型 
{
    struct person person; 

    strcpy(person.name, "Willion");
    person.age = 30;
    strcpy(person.job, "programmer");

    return person;                    // 函数返回结构体
}

// 结果:
programmer: Willion, age 30

 5、结构体可以作为其它结构体的成员

注意:若结构体的成员是其它结构体(子结构体),则子结构体必须在之前定义,才能作为结构体的成员。否则,报错(error: field 'birth' has incomplete type。 注:此处birth为成员变量名)。

#include <stdio.h>
#include <string.h>

struct birthday
{
    int year;
    int month;
};

struct person
{
    char name[32];
    int age;
    char job[16];
    struct birthday birth;      // 结构体成员为其它结构体
};

int main(void)
{
    struct person p;

    strcpy(p.name, "Jack");
    p.age = 18;
    strcpy(p.job, "programmer");
    p.birth.year = 2006;        // 使用成员访问运算符"."一级一级访问成员
    p.birth.month = 2;

    printf("%s, %d, %s, birthday %d-%d", p.name, p.age, p.job, p.birth.year, p.birth.month);
    return 0;
}

// 结果:
Jack, 18, programmer, birthday 2006-2

 6、结构体大小

  • 使用sizeof获取结构体大小。
  • sizeof(结构体变量),返回结构体所有成员的内存的大小以及可能的填充字节。
  • 因结构体的内存布局和对齐方式,可能会占用字节填充。
#include <stdio.h>

struct person
{
    char name[32];        // 字符串name:32字节
    int age;              // 整数age:4字节
    char *job;            // 字符串指针job:8字节(64位的计算机。若是32位的计算机,则4字节)
};

int main(void)
{
    struct person p;
    printf("p memory size is %d\n", sizeof(p));
    return 0;
}

// 结果:
p memory size is 48       // 优化对齐,有填充

可使用__attribute__设置内存布局,告诉编译器在编译过程中进行优化对齐。此功能和编译器有关。gcc编译器是非紧凑模式的。

__attribute__((packed)):使用紧凑内存布局,即取消优化对齐,按实际占用字节数对齐。

注意:attribute两边都是两个下划线"_"。

#include <stdio.h>

struct person
{
    char name[32];        // 字符串name:32字节
    int age;              // 整数age:4字节
    char *job;            // 字符串指针job:8字节(64位的计算机)
};

struct person_packed
{
    char name[32];
    int age;
    char *job;
}__attribute__((packed));    // 取消优化对齐

int main(void)
{
    struct person p;
    struct person_packed p_packed;
    printf("p memory size is %d\n", sizeof(p));
    printf("p_packed memory size is %d\n", sizeof(p_packed));
    return 0;
}

// 结果:
p memory size is 48            // 优化对齐,有填充
p_packed memory size is 44     // 取消优化对齐

 可使用标准库stddef.h中的宏offsetof查看结构体中各成员相对于结构体开头偏移多少字节。

宏 offsetof 的声明:      offsetof(type, member-designtor)

参数:type是class类型(例如:结构体),member-designtor是结构体的成员变量名。

返回:结构体的成员变量名相对于结构体开头的偏移量(单位:字节)。

#include <stdio.h>
#include <stddef.h>

struct person
{
    char name[32];        // 字符串name:32字节
    int age;              // 整数age:4字节
    char *job;            // 字符串指针job:8字节(64位的计算机)
};

struct person_packed
{
    char name[32];
    int age;
    char *job;
}__attribute__((packed));    // 取消优化对齐

int main(void)
{
    printf("structure person: name offset %d bytes\n",offsetof(struct person, name));
    printf("structure person: age offset %d bytes\n",offsetof(struct person, age));
    printf("structure person: job offset %d bytes\n",offsetof(struct person, job));

    printf("structure person_packed: name offset %d bytes\n",offsetof(struct person_packed, name));
    printf("structure person_packed: age offset %d bytes\n",offsetof(struct person_packed, age));
    printf("structure person_packed: job offset %d bytes\n",offsetof(struct person_packed, job));
    return 0;
}

// 结果:
structure person: name offset 0 bytes
structure person: age offset 32 bytes
structure person: job offset 40 bytes          // 优化对齐,有填充
structure person_packed: name offset 0 bytes
structure person_packed: age offset 32 bytes
structure person_packed: job offset 36 bytes

7、结构体指针

指针指向结构体时,该指针称为结构体指针。指针变量存储的是结构体变量的内存地址。

  • 需要结构体变量,并获取结构体变量的内存地址(&结构体变量)。
  • 需要结构体指针(*结构体指针变量)。
  • 指针指向结构体(结构体指针变量=&结构体变量)。
  • 通过"->"访问指针指向的结构体的成员(结构体指针变量->结构体成员)。也可以使用"."访问结构体成员( (*结构体指针变量). 结构体成员)。
#include <stdio.h>

struct person
{
    char name[32];
    int age;
    char job[16];
};

int main(void)
{
    struct person person = {"John", 18, "programmer"};       // 声明结构体变量,并初始化
    struct person *p;                                        // 声明结构体指针变量
    p = &person;                                             // 指针指向结构体
    printf("%s, %d, %s\n", p->name, p->age, p->job);         // 通过"->"访问结构体成员
    printf("%s, %d, %s\n", (*p).name, (*p).age, (*p).job);   // 通过"."访问结构体成员
    return 0;
}

// 结果:
John, 18, programmer
John, 18, programmer

 可以根据用户输入,通过指针将内容写入结构体中。

#include <stdio.h>

struct person
{
    char name[32];
    int age;
    char job[16];
};

int main(void)
{
    struct person *p, person;                                // 声明结构体指针和结构体变量
    p = &person;                                             // 指针指向结构体

    printf("Input name: ");
    scanf("%s", &p->name);                                   // 获取用户输入,存储到结构体指针指向的结构体成员变量

    printf("Input age: ");
    scanf("%d", &p->age);

    printf("Input job: ");
    scanf("%s", &p->job);

    printf("%s, %d, %s\n", p->name, p->age, p->job);         // 通过"->"访问结构体成员
    printf("%s, %d, %s\n", (*p).name, (*p).age, (*p).job);   // 通过"."访问结构体成员
    return 0;
}

// 结果:
Input name: John                 【输入:John】
Input age: 18                    【输入:18】
Input job: programmer            【输入:programmer】
John, 18, programmer
John, 18, programmer

可以将结构体指针作为函数参数,结构体指针指向结构体,可通过指针修改原结构体内容。

#include <stdio.h>
#include <string.h>

struct person
{
    char name[32];
    int age;
    char job[16];
};

int changestruct(struct person *p);

int main(void)
{
    struct person *p, p1 = {"John", 18, "programmer"};
    p = &p1;                                               // 结构体指针指向结构体(即结构体指针变量中存储结构体的内存地址)
    printf("Before: %s, %d, %s\n", p->name, p->age, p->job);
    changestruct(p);                                       // 结构体指针作为参数传入函数
    printf("After: %s, %d, %s\n", p->name, p->age, p->job);
    return 0;
}

int changestruct(struct person *p)                          // 函数参数是结构体指针
{
    strcpy(p->name, "Mark");
    p->age = 25;
    strcpy(p->job, "teacher");
    return 0;
}

// 结果:
Before: John, 18, programmer
After: Mark, 25, teacher

8、typedef 数据类型重命名

每次定义结构体变量时,都要使用"struct 结构体名称 结构体变量名",使得代码繁琐。

可以使用typedef给整个结构体定义提供别名,每次定义结构体变量时,只需"别名 结构体变量名"即可,即用 "别名" 代替 "struct 结构体名称" 。

typedef:数据类型重命名(提供别名)

  • 可以给基本数据类型重命名,也可以给指针、数组、结构体等数据类型重命名。
  • 结构体重命名后,原结构体定义仍保留,不会丢失或改变。
  • 数据类型重命名,可以减少因误解或混淆导致的错误,使得代码更简洁易读。
typedef struct person
{
    char name[32];
    int age;
    char job[16];
} Person;                   //名为person的结构体,别名为Person

Person person;              // 定义结构体变量person
Person *p                   // 定义结构体指针p
int fun1(Person person)     // 结构体person作为函数参数
int fun1(Person *p)         // 结构体指针p作为函数参数
...

标签:name,age,struct,C语言,person,job,structure,结构
From: https://blog.csdn.net/yannan20190313/article/details/137455152

相关文章

  • 数据结构复习-01enum枚举类型
    enum枚举类型语法:enum Nanme{name1=number1,name2=number2,};举例:enumDay{mon=1;tue=2;};enumDayday=mon;printf("dayis%d",day);输出:注意事项:1.若枚举类型中的首个元素未定义则默认为0 2.枚举类型的非首元素的默认值为......
  • C语言,PHP扩展开发
    c语言代码:/*test_addextensionforPHP*/#ifdefHAVE_CONFIG_H#include"config.h"#endif#include<stdlib.h>#include<stdio.h>#include<string.h>#include<unistd.h>#include"php.h"#include"zend_exc......
  • 【C语言初阶】结构体
    【C语言初阶】结构体文章目录【C语言初阶】结构体7-结构体一、结构体的声明1结构体的基础知识2结构体的声明2.1介绍2.2声明示例3结构体成员类型二、结构体变量的定义和初始化1结构体变量的定义和初始化三、结构体成员的访问1结构体变量直接访问成员2结构体指......
  • 面试中数据结构与算法——知识点最全总结(学完可应对一线大厂)
    各大厂历年高频面试题系列,以下为部分内容不包括全部:双指针类面试题括号类面试题回文类面试题递推类面试题树型dp类面试题区间dp类面试题背包dp类面试题排序相关面试题常见贪心面试题常见图算法面试题子数组类面试题子序列类面试题二分类面试题bfs与dfs类面试......
  • 【C语言】练习:比较十个数的大小
    初始化一个数组,使用for循环输入;把数组中的第一个数字,也就是下标为[0]的数字赋值给一个int类型的变量“max”;使用循环从arr数组中下标为[1]的数字开始对比,如果arr[1]>arr[0],则把arr[1]赋值给max;最后打印出最大数。intmain(){ intarr[10]; for(inti=0;i<10;......
  • [ida] 结构偏移
    IDA帮助:移位指针备忘定义__shifted()指针有时在二进制代码中,我们会遇到指向结构中间的指针。这样的指针通常不存在于源代码中,而是一个优化编译器可能会引入它们以使代码更短或更快。可以使用移位指针来描述此类指针。移位的指针是一个常规指针,其中包含有关名称的其他信......
  • 【C语言】练习:分数求和
    计算1/1-1/2+1/3-1/4+1/5……+1/99-1/100的值,打印出结果首先看题,分子不变为1,分母1-100;既然是分数计算,那结果肯定存在小数,所以在开始定义一个double类型的变量“num”;初始化一个int类型的变量“i”,使用for循环产出1-100的值;在for循环里使用if语句来判断分母是偶数......
  • C语言语法最后一个教案-教案21(预处理 · 头文件)
    最近给大家争取到一个深夜福利保证你在深夜手机刷到嘎嘎香~那就是 官方授权大流量卡缺点:月租太便宜 185GB~100分钟通话时长~长期套餐~畅想自由的气息流量自由的同时还拥有超长通话,而且免费领取。名额有限,咱们废话不多说直接上图。感兴趣的家人私我或者直接加微......
  • 【C语言】链表(原理+实现)
    目录一.链表概念二.链表实现1.创建新节点2.打印链表3.尾插、头插4.尾删、头删5.查找6.指定位置前插入7.指定位置后插入8.指定位置删除9.指定位置后删除 10.销毁链表三.完整代码一.链表概念链表是线性表的一种,与顺序表不同的是,链表在物理存储结构上不连续,在......
  • golang中结构体初始化的语法格式
    在Go语言中,结构体(struct)的初始化可以通过以下几种方式来进行:键值对初始化(字段名明确指定):当结构体字段很多或者你需要只初始化部分字段时,可以采用键值对的方式来初始化结构体。每个字段名后面跟一个冒号和它的值。typePersonstruct{NamestringAgeintC......