结构体(struct)

从某种意义上说,会不会使用struct,如何使用struct是区别一个开发人员是否具备丰富开发经验的试金石。

处理由不同类型成员构成的构造类型,要采用结构体的方式。

定义:关键字struct.

无名结构体,一般用于定义类型相同时,定义变量;并且不会带来多余的命名。

struct{
char name[40];
int age;
int num;
float score;
}s1,s2,s3,s4;
int main() {
struct{
char name[40];
int age;
int num;
float score;
}s1;
....
return 0;
}

有名结构体

一处定义各处使用

struct stu{
char name[40];
int age;
int num;
float score;
}
int main() {
struct stu s1;
struct stu s2;
struct stu s3;
return 0;
}

typedef

对现有类型取别名,不能创造新的类型(typerename)。

使用方法:

1.先用原类型定义变量

2.在定义前加上typedef

3.将原来的名字改成自己需要的类型名

typedef char        int8;
typedef short int16;
typedef int int32;
typedef long long int64;
int main() {
int8 i8;
int16 i16;
int32 i32;
int64 i64;
return 0;
}

别名结构体

typedef是一个常用于对结构体取别名的关键字,更好的用于结构体中

typedef struct{
char name[40];
int age;
int num;
float score;
}Stu;
int main() {
Stu s1;
Stu s2;
Stu s3;
}

typedef与#define区别

typedef:构成c语言语句参与编译。

#define构成的语句在预处理阶段处理完毕

#fefine DINT int
int main() {
DINT a,b,c;//所有声明时要替换。
}
int main() {
char *p,q;
printf("sizeof(p) = %d sizeof(q) = %d\n",sizeof(p),sizeof(q));//4,1
typedef char * pChar;
pChar a,b;
printf("sizeof(a) = %d sizeof(b) = %d\n",sizeof(a),sizeof(b));//4,4 #define DpChar char *
DpChar m,n;//<=>char * m,n;
printf("sizeof(m) = %d sizeof(n) = %d\n",sizeof(m),sizeof(n));//4,1 return 0;
}

struct的初始化

凡是基本类型,既可以在定义的时候初始化,也可以先定义再赋值。

凡是构造类型,要么在定义的时候初始化,不可以先定义再以实例化的方式赋值。

初始化是一种特殊的语法,跟赋值不等价。

成员赋值,不能已初始化的方式赋值(如数组,字符串等)

struct stu{
char name[100];
int num;
char sex;
float score;
} int main() {
struct stu s = {"assassin",10001,'f',99};
//也可以这样赋值
/*
struct stu s;
s.name = "assassin";//错误的,赋值不能这样写,和初始化有区别
strcpy(s.name,"assassin");
s.num = 1001;
...
*/
return 0;
}
struct stu{
char name[100];
int num;
char sex;
float score;
}
int main() {
struct stu s;
scanf("%s%d %c%f\n",s.name,&s.num,&s.sex,&s.score);//其中s.name,name是个数组,数组时个特殊的指针,所以前面不用取址符。&的优先级低于"."的优先级。
return 0;
}

struct的访问

一类是访问栈上的,一类是访问堆上的。(点乘员运算符,指向成员运算符)

#include<stdio.h>
#include<stdlib.h>
struct stu{
char name[100];
int num;
char sex;
float score;
};
int main() {
struct stu s = {"assassin",10001,'f',99};
struct stu *pa = &s;
//点乘运算访问
printf("name = %s\n",(*pa).name);
printf("num = %d\n",(*pa).num);
printf("sex = %c\n",(*pa).sex);
printf("score = %f\n",(*pa).score); printf("======================\n"); printf("name = %s\n",s.name);
printf("num = %d\n",s.num);
printf("sex = %c\n",s.sex);
printf("score = %f\n",s.score);
//足以说明*pa <=> s //"."点乘优先级高于"*"解引用运算符
printf("======================\n");
//指向成员访问
printf("name = %s\n",pa->name);
printf("num = %d\n",pa->num);
printf("sex = %c\n",pa->sex);
printf("score = %f\n",pa->score);
return 0;
}
/*
name = assassin
num = 10001
sex = f
score = 99.000000
======================
name = assassin
num = 10001
sex = f
score = 99.000000
======================
name = assassin
num = 10001
sex = f
score = 99.000000
*/

堆上的访问

typedef struct stu{
char name[100];
int num;
char sex;
float score;
}Stu;
int main() {
Stu *pa = (Stu*)malloc(sizeof(Stu));
strcpy(pa->name,"assassin");//赋值
pa->num = 10001;
pa->sex = 'f';
pa->score = 99; printf("name = %s\n",pa->name);
printf("num = %s\n",pa->num);
printf("sex = %s\n",pa->sex);
printf("score = %s\n",pa->score); free(pa);
return 0;
}
/*
name = assassin
num = 10001
sex = f
score = 99.000000
*/

struct赋值

相同结构体类型的变量间,可以赋值。不同类型不可以。词语发基础奠定了可以用与传参和返值。

typedef struct stu{
char name[100];
int num;
char sex;
float score;
}Stu;
int main() {
Stu s;
Stu s2 = {"assassin",1003,'f',99};
s = s2;
printf("%s %d %c %f\n",s.num,s.num,s.sex,s.score);//是可以赋值的 return 0;
}

结构体支持赋值,访问和数组一样

typedef struct _stu{
char name[10];
}Stu;
typedef struct _array{
int arr[10];
}Array;
int main() {
int arr[10] = {1,2,23,4,5,6,78,};
int arr2[10];
arr2 = arr;//error
Stu stu1 = {"assassin"};
Stu stu2;
stu2 = stu1;//正确 Array arr3 = {1,2,23,4,5,6,7,8};
Array arr4;
arr4 = arr3;//和上面有区别
for(int i = 0;i<10;i++) {
printf("%d\n",arr4.arr[i]);
}
}

传参和返回值的本质就是依次赋值

typedef struct _complex{
float real;
float image;
}MyComplex;
//实现一个函数,实现两个负数相加
MyComplex addComplex(MyComplex x,MyComplex y) {
MyComplex t;
t.real = x.real + y.real;
t.image = x.image + y.image;
return t;
}
int main() {
MyComplex c1 = {1,2};
MyComplex c2 = {3,4};
MyComplex retc = addComplex(c1,c2); printf("(%.2f,%.2f)\n",retc.real,retc.image); return 0;
}
//(4.00,6.00)

C语言对于数组的处理就是指针,对于结构体也推荐传指针。(即使有很大的数据,只传4个字节,而且效率提高了很大)

typedef struct _complex{
float real;
float image;
}MyComplex;
//实现一个函数,实现两个负数相加
MyComplex addComplex(MyComplex *px,MyComplex *py) {
MyComplex t;
t.real = px->real + py->real;
t.image = px->image + py->image;
return t;
}
int main() {
MyComplex c1 = {1,2};
MyComplex c2 = {3,4};
MyComplex retc = addComplex(&c1,&c2); printf("(%.2f,%.2f)\n",retc.real,retc.image); return 0;
}
//效率大大提高

结构体数组

结构体数组的本质:是一维数组,只不过是一维数组中的每一个个成员又是结构体。

typedef struct _stu{
int num;
char name[100];
char sex;
float score;
}Stu;
int main() {
Stu s[] = {{1001,"assassin",'f',99},{1002,"Wunworld",'f',89},{1003,"seafwg"},{1004,"intelwisd"}};
for(int i = 0;i < sizeof(s)/sizeof(*s);i++) {
printf("num = %d\n",s[i].num);
printf("name = %s\n",s[i].nam);
printf("sex = %c\n",s[i].sex);
printf("score = %f\n",s[i].score);
}
}

实例投票:现有三位侯选人员,侯选人包含名字和选票数两项,现在 10 人对其投票,每个人限投票一次,投票完毕,打印投票结果,如有名字打错,算作弃权处理。

typedef struct _candidate{
char name[30];
int voteCount;
}Candidate;
void disCandidate(Candidate *c,int n,int m);
int main() {
//初始化候选人
Candidate can[3] = {
{"assassin",0},
{"wunworld",0},
{"seafwg",0}
};
int count = 0;
char buf[1024];
//是个人选举
for(int i = 0;i < 10;i++) {
printf("请你选举自己心中的候选人");
scanf("%s",buf);
int flag = 1;
for(int j = 0;j < 3;j++) {
if(!strcmp(buf,can[j].name)) {
can[j].voteCount++;
flag = 0;
}
}
if(flag != 0) {
count++;
}
}
disCandidate(can,3,count);
}
//显示选举后的选票人
void disCandidate(Candidate *c,int n,int count) {
for(int i = 0;i < n;i++) {
printf("Name:10%s VoteCount:%2d\n",c[i].name,c[i].voteCount);
}
printf("the give up people: %d\n",count);
//进行排序
int idx = 0;
for(int i = 0;i < n;i++) {
if(c[i].voteCount > c[idx].voteCount) {
idx = i;
}
}
printf("恭喜%s获得了选举!\n",c[idx].name);
}

结构体的嵌套

struct _birth {
int year;
int month;
int day;
}; typedef struct _stu {
char name[20];
int num;
char sex;
float score;
struct _birth birth;
//<=>
/*struct _birth {
int year;
int month;
int day;
}birth;*/
}Stu;
int main() {
Stu s = {"assassin",10001,'f',99,{1992,04,15}};
printf("name = %s\n",s.name);
printf("year = %d\n",s.birth.year);
printf("month = %d\n",s.birth.month);
printf("day = %d\n",s.birth.day);
}
/*
name = assassin
year = 1992
month = 4
day = 15
*/

结构体类型的大小

类型本身不占空间,类型产生的变量才占空间

结构体中的每个成员的地址均是可以获得的。

typedef struct _staff{
char sex;
int age;
}Staff; int main() {
Satff s;
printf("sizeof(Staff) = %d\n",sizeof(Staff));
printf("sizeof(s) = %d\n",sizeof(s)); printf("&s = %p\n",&s);
printf("&s.sex = %p\n",&s.sex);
printf("&s.age = %p\n",&s.age); return 0;
}
/*
sizeof(Staff) = 8
sizeof(s) = 8
&s = 0061FEA8
&s.sex = 0061FEA8
&s.age = 0061FEAC
*/
typedef struct _staff{
char sex;
int age;
short like;
}Staff; int main() {
Staff s;
printf("sizeof(Staff) = %d\n",sizeof(Staff));
printf("sizeof(s) = %d\n",sizeof(s)); printf("&s = %p\n",&s);
printf("&s.sex = %p\n",&s.sex);
printf("&s.age = %p\n",&s.age);
printf("&s.like = %p\n",&s.like); return 0;
}
/*
sizeof(Staff) = 12
sizeof(s) = 12
&s = 0061FEA4
&s.sex = 0061FEA4
&s.age = 0061FEA8
&s.like = 0061FEAC
*/

为什么结构体里面的char,short是4个字节

sex后面空了三个字节,然后去填age,like后面空了两个字节,sex与age直接空了三个字节。like应该填到那个位置。

内存对齐

一个成员变量需要多少个机器周期去读的现象,称为内存不对齐。x实现内存对齐主要原因是牺牲空间换取时间的方法。

对齐规则

x86linux默认#pragma(4),window默认#pragma pack(8)。linux最大支持4字节对齐。

方法:

1.取pack(n)的值(n=1 2 4 8--),去结构体中类型最大值m,两者取小即为外对齐 大小Y=(m<n?m:n);

2.将每一个结构体的成员大小与Y比较取较小者为X作为内对其的大小。

3.所谓按X对齐,即为地址(设起始地址为0)能被X整除的地方开始存放数据。

4.外部对其原则是依据Y的值(Y的最小整数倍),进行补空操作。

例如:以上述为例

typedef struct _staff{
char sex;
short num;
int age;
}Stu;
1.外对齐:pack(8)默认为8 n=8,则按照1,m=4,即Y=4,----外对齐。(sex与age直接空了三个字节)
2.内对齐:上述Y=4,与成员大小1,2,4比较取小值(x=1,2,4)---内对齐
3.按照X对齐:
0-1 2-4 4-8-----8(外侧是Y的最小整数倍补齐)
例如:成员大小1,4,2比较后(X=1,4,2)则:
0-1 4-8 8-10(10不是Y的最小整数倍取12)---大小为12
eg:pack(1), n=1,m=4,Y=1,
成员:1 4 2,则X=1 1 1,
外对齐:0-1 1-5 5-7(7是1的倍数)---大小为7

eg:

#pragma pack(4)
typedef struct _stu{
char sex;
double num;
int age;
}Stu;
int main() {
printf("sizeof(Stu) = %d\n",sizeof(Stu));
}
/*
sizeof(Stu) = 16
sizeof(s) = 16
*/
/*pack(4),n=4,m=8--->Y=4
成员:1 8 4与Y比较取小者X=1 4 4
0-1 4(能与X整除放成员个大小)-12 12-16-----大小为16
*/

结构体注意事项

typedef struct _stu{
char name[20];
int score;
}Stu;
int main() {
Stu s;
strcpy(s.name,"bob");
s,score = 99;
}
typedef struct _stu{
char *name;
int score;
}Stu;//只有8个字节,name未初始化
int main() {
Stu s;
strcpy(s.name,"bob");//Error 会挂机
s.name = (char*)malloc(100);//解决办法放在堆上
strcpy(s.name,"jim");
printf("name = %s score = %d\n",s.name,s.score);
free(s.name);//必须要释放
s.score = 99;
}

申请空间的时候从外至内,释放空间的时候从内之外。

typedef struct _stu{
char *name;
int score;
}Stu;//只有8个字节,name未初始化
int main() {
Stu *ps = (Stu *)malloc(sizeof(Stu));//ps实在栈上申请了8,结构体在堆上,没有初始化。并没有指向。解决办法,再次申请一个堆空间存放地址
ps->name = (char*)malloc(100);
strcpy(ps->name,"assassin");
ps->score = 200;
printf("name = %s score = %d\n",ps->name,ps->score);
free(ps->name);//
free(ps);
return 0;
}

数据类型:内存是以字节为单位进行线性编址的硬件基础,对内存进行格式化。

C/C++(结构体)的更多相关文章

  1. Go结构体实现类似成员函数机制

    Go语言结构体成员能否是函数,从而实现类似类的成员函数的机制呢?答案是肯定的. package main import "fmt" type stru struct { testf ...

  2. C#基础回顾(二)—页面值传递、重载与重写、类与结构体、装箱与拆箱

    一.前言 -孤独的路上有梦想作伴,乘风破浪- 二.页面值传递 (1)C#各页面之间可以进行数据的交换和传递,页面之间可根据获取的数据,进行各自的操作(跳转.计算等操作).为了实现多种方式的数据传递,C ...

  3. go语言结构体

    定义: 是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体. 成员: 每个值称为结构体的成员. 示例: 用结构体的经典案例处理公司的员工信息,每个员工信息包含一个唯一的员工编号.员工的名字. ...

  4. C语言中的结构体

    用户自己建立自己的结构体类型 1.  定义和使用结构体变量 (1).结构体的定义 C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体. (2).声明一个结构体类型的一般形式为: ...

  5. C++_系列自学课程_第_12_课_结构体

    #include <iostream> #include <string> using namespace std; struct CDAccount { double bal ...

  6. java socket传送一个结构体给用C++编写的服务器解析的问题

    另一端是Java写客户端程序,两者之间需要通信.c++/c接收和发送的都是结构体,而Java是直接发送的字节流或者byte 数组.解决方法:c++/c socket 在发送结构体的时候其实发送的也是字 ...

  7. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  8. HDOJ 1009. Fat Mouse' Trade 贪心 结构体排序

    FatMouse' Trade Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  9. C语言结构体对齐

    1.结构体变量中的元素如何访问? (1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式):实质上都是指针方式访问.(2)结构体变量中的元素访问方式:只有一种,用.或者->的方式来 ...

  10. C与指针(结构体指针,函数指针,数组指针,指针数组)定义与使用

    类型 普通指针 指针数组(非指针类型) 数组指针 结构体指针 函数指针 二重指针 定义方式 int *p; int *p[5]; int (*p)[5]; int a[3][5]; struct{.. ...

随机推荐

  1. 如何知道 CPU 是否支持虚拟化技术(VT)

    作者: Sk 译者: LCTT geekpi 我们已经知道如何检查你的 Linux 操作系统是 32 位还是 64 位以及如何知道你的 Linux 系统是物理机还是虚拟机.今天,我们将学习另一个有用的 ...

  2. 超轻便的 Cache_Lite 文件缓存

    Cache_Lite提供了快速,轻便和安全的缓存系统.它针对文件容器进行了优化,并且防止缓存损坏(因为它使用文件锁定和/或散列测试). 个人感觉还是挺方便的. Cache_Lite 官方参考地址. C ...

  3. idea+spring4+springmvc+mybatis+maven实现简单增删改查CRUD

    在学习spring4+springmvc+mybatis的ssm框架,idea整合简单实现增删改查功能,在这里记录一下. 原文在这里:https://my.oschina.net/finchxu/bl ...

  4. 洛谷 P1156 垃圾陷阱 (01背包拓展)(好题!!)

    这真是一道好题目 学到了很多 一开始感觉吃或者不吃会有后效性 然后看到洛谷的题解,直接把这个有后效性的部分当作dp的维度和值 因为这个垃圾可以堆或者不堆,所以这个很像01背包, 但是加了非常多的限制条 ...

  5. Python学习笔记(4)--数据结构之元组tuple

    元组(tuple) 定义:tuple和list十分相似,但是tuple是不可变的,即不能修改tuple 初始化:(), ('a', ) , ('a', 'b')   //当只有一个元素时,需加上逗号, ...

  6. HDU 4941 Magical Forest (Hash)

    这个题比赛的时候是乱搞的,比赛结束之后学长说是映射+hash才恍然大悟.因此决定好好学一下hash. 题意: M*N的格子,里面有一些格子里面有一个值. 有三种操作: 1.交换两行的值. 2.交换两列 ...

  7. USART

    串口通信是一种设备间非常常用的串行通行方式,其简单便捷,大部分电子设备都支持. 一.物理层 常用RS-232标准,主要规定了信号的用途.通信接口以及信号的电平标准.  “DB9接口”之间通过串口信号线 ...

  8. ArcGIS api for javascript——加入两个动态地图

    描述 这个示例表现如何加两个动态地图到一个地图.动态服务按用户缩放或平移服务器每次绘制的地图,ArcGISDynamicMapServiceLayer表示ArcGIS JavaScript API动态 ...

  9. hdu 1024 最大m子段和

    注:摘的老师写的 最大m子段和问题 以-1 4 -2 3 -2 3为例最大子段和是:6最大2子段和是:4+(3-2+3)=8所以,最大子段和和最大m子段和不一样,不能用比如先求一个最大子段和,从序列中 ...

  10. 千千万万的IT开发project师路在何方

    已经找不到该文章的最初出处了,有找到的人请告诉我.谢谢~~ 千千万万的IT开发project师路在何方 2007-06-25 21:41 恭喜,你选择开发project师作为自已的职业! 悲哀.你选择 ...