C-结构体

Posted khrushchefox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C-结构体相关的知识,希望对你有一定的参考价值。

结构体

创建和使用

#include <stdio.h>

struct Student  // 结构体标签

    int id;  // 成员
    char* name;
    int age;
s1 = 1, "小明", .age = 18;  // 结构变量

int main()

    struct Student* p = &s1;
    printf("%d", p->id);
    return 0;

内存大小

printf("%llu", sizeof(struct Student));  // 24

规则有三:

  1. 结构体中元素按照定义顺序依次置于内存中, 但并不是紧密排列的.
    从结构体首地址开始依次将元素放入内存时, 元素被放置在自身对齐大小的整数倍地址上.
  2. 如果结构体大小不是所有元素中最大对齐大小的整数倍,则结构体对齐到最大元素对齐大小的整数倍, 填充空间放置到结构体末尾.
  3. 基本数据类型的对齐大小为自身的大小, 结构体数据类型的对齐大小为其元素中最大的对齐大小.

谁能给我讲讲c的结构体啊

结构体定义
  结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。
结构体作用
  结构体和其他类型基础数据类型一样,例如int类型,char类型 只不过结构体可以做成你想要的数据类型。以方便日后的使用。   在实际项目中,结构体是大量存在的。研发人员常使用结构体来封装一些属性来组成新的类型。   结构体在函数中的作用不是简便,其最主要的作用就是封装。封装的好处就是可以再次利用。让使用者不必关心这个是什么,只要根据定义使用就可以了。
结构体的大小与内存对齐
  结构体的大小不是结构体元素单纯相加就行的,因为我们现在主流的计算机使用的都是32Bit字长的CPU,对这类型的CPU取4个字节的数要比取一个字节要高效,也更方便。所以在结构体中每个成员的首地址都是4的整数倍的话,取数据元素是就会相对更高效,这就是内存对齐的由来。每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。   规则:   1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。   2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。   3、结合1、2颗推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
C++中的结构体
  在C语言中,可以定义结构体类型,将多个相关的变量包装成为一个整体使用。在结构体中的变量,可以是相同、部分相同,或完全不同的数据类型。在C语言中,结构体不能包含函数。在面向对象的程序设计中,对象具有状态(属性)和行为,状态保存在成员变量中,行为通过成员方法(函数)来实现。C语言中的结构体只能描述一个对象的状态,不能描述一个对象的行为。在C++中,考虑到C语言到C++语言过渡的连续性,对结构体进行了扩展,C++的结构体可以包含函数,这样,C++的结构体也具有类的功能,与class不同的是,结构体包含的函数默认为public,而不是private。   
C++控制台输出例子:   #include <cstdlib>
  #include <iostream>   //定义结构体  
 struct point      //包含两个变量成员   
int x;  
 int y;   ;  
 using namespace std;  
 int main(int argc, char *argv[])   
  struct point pt;   
pt.x=1;   pt.y=2;   
cout<<pt.x<<endl<<pt.y<<endl;  
 return EXIT_SUCCESS;  
    
结构体的一些性质和作用:
  结构体和其他类型基础数据类型一样,例如int类型,char类型 只不过结构体可以做成你想要的数据类型。以方便日后的使用。   在项目中,结构体是大量存在的。研发人员常使用结构体来封装一些属性来组成新的类型。   结构体在函数中的作用不是简便,其最主要的作用就是封装。封装的好处就是可以再次利用。让使用者不必关心这个是什么,只要根据定义使用就可以了。

上面都是概念性的问题,可以这么理解:一个结构体就是一个变量,.就像 int i;一样。int 变量类型, i是变量名。比喻如果有结构体定义如下:
struct student
int num;
char name[20];
char sex;
zhangsan,lisi;
表示定义了: student zhangsan;(类似如 int i;)
student zhangsan;(类似如 int j;)

当然它和变量有不一样的地方,不然直接也叫变量算了!!!!!
可以赋值 zhangsan.name="ZhangSan";
lisi.sex="MEN";等
参考技术A 第十一章 结构体
11.1 概述
在实际应用中,有不少应用问题如果只采用已学的变量和数组作为数据结构显得很不方便。
例:输入100个学生的学号、姓名和考试成绩,编写程序找出高分者和低分者。
用变量和数组作数据结构可编写程序如下:

main()
int i, num, maxnum, minnum;
char name[20], maxname[20], minname[20];
int score, maxscore, minscore;
maxscore=0; minscore=100;
for(i=1; i<=100; i++)
scanf(%d%s%d”,&num,name,&score);
if(score>maxscore)
maxscore=score; maxnum=num; strcpy(maxname,name);
if(score<minscore)
minscore=score; minnum=num; strcpy(minname,name);

输出


明显缺点:
①变量过多,同一学生的各个数据无联系,没有整体概念,不便管理。
②操作不便(如更新过程)。
显然,选用一种能把一个学生的数据构造成一个整体的构造型数据结构更合适,但不能是数组。
对于这种情况,可以将一个学生的数据定义为一个结构体类型:

struct student 类型名

int num; 成员表
char name[20];
int score;
;

定义了一个结构体类型,它包含三个成员。

11.2 定义结构体类型变量的方法
前面定义的结构体类型只是一种“模型”,还必须定义结构体变量后才能存放数据。
定义结构体变量有三种方法:
1、先定义结构体类型再定义结构体变量
定义了结构体类型后:
struct student st, stmax, stmin;

类型符 变量名
定义了三个结构体变量,每个变量包含三个成员,每个变量可存放一个学生的数据。

2、在定义结构体类型的同时定义结构体变量
struct student

int num;
char name[20];
int score;
st, stmax, stmin;

3、直接定义结构体类型变量
struct 不出现类型名

int num;
char name[20];
int score;
st, stmax, stmin;

常用第一种方法

说明:
①类型与变量不同,只对变量分配空间与操作。
②对成员可以单独使用,相当于普通变量。
③成员也可以是一个结构体变量。
struct date struct student
int month; int num;
int day; char name[20];
int year; struct date birthday;
; st1, st2;
④成员名可以与程序中的变量名相同,两者代表不同的对象。

11.3 结构体变量的引用 ■成员引用
可以对成员单独引用,形式为:
结构体变量名 . 成员名

成员运算符

st.num=1001;st.score=90;strcpy(st.name,”Li”);
printf(“%d%s%d”,st.num,st.name,st.score);
scanf(“%d%s%d”,&st.num,st.name,&st.score) ;
可以引用成员的地址

如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低一级的成员,只能对最低级的成员进行存取与运算。

st1.birthday.year=1960;
st1.birthday.month=5;
st1.birthday.day=15;

■整体引用
可以对结构体变量进行整体赋值:
stmax=st; 将st中的所有内容赋值给stmax。

对结构体变量的整体操作只限于赋值操作和参数传递,而且要求类型一致。不能对结构体变量进行整体输入输出。

结构体应用举例:
编写程序输入100个学生的学号、姓名和考试成绩,找出高分者和低分者。

struct student
int num;
char name[20];
int score;
;

main()
int i; struct student st,stmax,stmin;
stmax.score=0; stmin.score=100;
for(i=1;i<=100;i++)
scanf(“%d%s%d”,&st.num,st.name,&st.score);
if(st.score>stmax.score) stmax=st;
if(st.score<stmin.score) stmin=st;

printf(“\n%5d%15s%5d”,stmax.num,stmax.name,
stmax.score);
printf(“\n%5d%15s%5d”,stmin.num,stmin.name,
stmin.score);


11.4 结构体变量的初始化
对结构体变量可以在定义时指定初始值 struct student

int num;
char name[20];
int score;
st=1001,”wang”,95;

11.5 结构体数组 可以定义结构体数组来存放批量数据。
■结构体数组的定义
struct student

int num;
char name[20];
int score;
;struct student a[100];
定义a数组,可以存放100个学生的数据。
a数组的每个元素又是一个结构体变量。

■结构体数组的初始化
在定义结构体数组的同时指定初值。
struct student

int num;
char name[20];
int score;

struct student a[2]=
1001,”LiLi”,85,1002,”wang”,90;

或:
struct student

int num;
char name[20];
int score;
a[2]=
1001,”LiLi”,85,1002,”wang”,90;

■结构体数组元素的引用
成员引用:
a[0].num=1001;
strcpy(a[0].name,”wang”);
a[0].score=85;
整体引用:
a[1]=a[0]; 与普通数组元素的引用相同

■结构体数组的应用
输入100个学生的学号、姓名和考试成绩,然后按从高分到低分的顺序排列后输出。

struct student
int num;
char name[20];
int score;
;
main()
int i, j;
struct student a[100], t;
for(i=0;i<100;i++)
scanf(“%d%s%d”,&a[i].num,a[i].name,
&a[i].score);

for(i=0;i<99;i++)
for(j=i+1; j<100; j++)
if(a[i].score<a[j].score)
t=a[i]; a[i]=a[j]; a[j]=t; 整体引用
for(i=0;i<100;i++)
printf((“\n%5d%15s%5d”,a[i].num,
a[i].name,a[i].score);


例:(p266例11.2)
对候选人得票的统计程序。设有三个候选人,每次输入一个得票候选人的名字,要求最后输出各候选人的得票结果。
#include “string.h”
struct person
char name[20];
int count;
leader[3]=“Li”,0,”zhang”,0,”wang”,0;

main()
int i, j ;
char leader_name[20];
for(i=1;i<=100;i++)
scanf(“%s”,leader_name);
for(j=0;j<3;j++)
if(strcmp(leader_name,leader[j].name)==0)
leader[j].count++;


printf(“\n”);
for(i=0;i<3;i++)
printf(“\n%15s%5d”,
leader[i].name,leader[i].count);


11.6 指向结构体类型数据的指针
■指向结构体类型变量的指针
struct student st, st1;
struct student *p;
p=&st;

通过指针变量引用结构体变量:
①成员引用
(*p).num=1001; 或 p->num=1001;
(*p).score=85; 或 p->score=85;
strcpy((*p).name,”wang”);
或 strcpy(p->name,”wang”);
②整体引用
st1=*p; 等效于 st1=st;

■指向结构体数组的指针
struct student a[100];
struct student *p;
p=a;
通过指针变量引用结构体数组元素:
①成员引用
(*p).num=1001; 或 p->num=1001;
(*p).score=85; 或 p->score=85;
strcpy((*p).name,”wang”);
或strcpy(p->name,”wang”);
 

一般地:
(*(p+i)).num=1001; 或 (p+i)->num=1001;
(*(p+i)).score=85; 或 (p+i)->score=85;
strcpy((*(p+i)).name,”wang”);
或 strcpy((p+i)->name,”wang”);
也可以用下标法:
p[i].num=1001;
②整体引用
*(p+1)=*(p+0); 或 p[1]=p[0];

■用结构体变量和指向结构体的指针作函数参数
用结构体变量作函数参数时,对应的实参应该是同类型的结构体变量(或数组元素),参数传递是“值传递”。
用指向结构体的指针作函数参数时,对应的实参应该是同类型的结构体变量的地址(或数组的地址),参数传递是“地址传递”。

main()
struct student st=1001,”LiLi”,70;
f(st);
printf(“\n %5d%10s%5d”,
st.num,st.name,st.score);

f(struct student a)
a.score=90;
printf(“\n %5d%10s%5d”,
a.num,a.name,a.score);


main()
struct student st=1001,”LiLi”,70;
f(&st);
printf(“\n %5d%10s%5d”,st.num,st.name,st.score);

f(struct student *a)
a->score=90;
printf(“\n%5d%10s%5d”,a->num,a->name,a>score);

通过指针变量a可以访问它所指向的结构体。
 

11.7 用指针处理链表
■链表概述
链表是一种重要的数据结构─动态数据结构。
以具体例子来说明链表的概念及其应用:
例:选择合适的数据结构来存放一批学生的学号及考试成绩,以便进一步处理。
由于学生人数未知,用静态数据结构不合适。
用链表处理较恰当。

用链表处理该问题的基本思路:
将各学生的数据进行离散存放,来一个学生就分配一小块内存(结点)。并将各结点用指针依次连接起来─链表。

每结点应包含下一结点的开始地址。
最后一个结点中的指针为空。
链头指针指向第一个结点,是访问链表的重要依据。
这样的链表称单向链表。

一个结点可用如下结构体描述:
typedef struct student

int num; 学号
int score; 成绩
struct student *next; 下一结点的首地址
STU;

typedef : 自定义类型符(见11.10)

■单向链表的建立
①输入一个学生的数据。
②分配结点空间,数据存入。
③将该结点的首地址赋给上一结点的next,若该结点是第一个结点,则赋给头指针。
④将该结点的next置为空,表示该结点为当前的最后结点。

STU *creat()
STU st,*p0=NULL,*p,*head=NULL;
while(1)
scanf("%d%d",&st.num,&st.score);
if(st.num<0) break;
p=malloc(sizeof(STU)); *p=st;
(*p).next=NULL;
if(p0==NULL) head=p; p0为前一结点的指针
else (*p0).next=p;
p0=p;

return head;


■单向链表的访问
以输出为例
①通过头指针找到第一个结点.
②输出当前结点的内容,并通过next找到后继结点,┄┄,直到next为空.

void output(STU *head)

STU *p=head;
while(p)

printf("\n %d %d",(*p).num,(*p).score);
p=(*p).next;



■删除结点操作
①按链表的访问方法找到相应结点。
②若该结点是第一个结点,则将后继结点指针赋给头指针。
若该结点是最后一个结点,则将前缀结点的next置为空。
若该结点是中间结点,则将后继结点指针赋给前缀结点的next。
③释放该结点所占的内存单元。

STU *delete(STU *head,int number)
STU *p =head,*p0=NULL;
while(p)

if((*p).num==number)

if(p==head) head=(*p).next;
else if((*p).next==NULL) (*p0).next=NULL;
else (*p0).next=(*p).next;
free(p); break;
else p0=p; p=(*p).next;
return head;


■插入操作

假定将结点p 插入到结点p0的后面, 则插入操作的关键为:
p->next=p0->next; p0->next=p;
参考技术B 结构体就是可以自己定义一个数据的类型

以上是关于C-结构体的主要内容,如果未能解决你的问题,请参考以下文章

C++结构体中定义函数(C++结构体struct与C语言结构体区别)(C++结构体与C++类的区别)(结构体函数)

C语言结构体定义

c语言结构体能否整体赋值

c语言中返回结构体数组

C语言结构体函数的返回值是结构体结构体变量中的信息

C语言结构体函数的返回值是结构体结构体变量中的信息