当前位置: 首页 > news >正文

建设统计网站进不去珠海网站设计费用

建设统计网站进不去,珠海网站设计费用,台州律师网站建设,品牌创建的六个步骤---------------------------- ------------------ 岁月漫长心怀热爱#xff0c;携手共赴星辰大海 --------今天来到我们自定义类型 -----结构体的讲解 目录 结构体的类型声明和初始化 结构体的类型声明 结构体成员的直接访问 结构体成员的间接访问 嵌套结构体进行访问 使用… ---------------------------- ------------------ 岁月漫长心怀热爱携手共赴星辰大海 --------今天来到我们自定义类型 -----结构体的讲解 目录 结构体的类型声明和初始化 结构体的类型声明 结构体成员的直接访问 结构体成员的间接访问 嵌套结构体进行访问 使用typedef来定义结构体 匿名结构体类型 结构体的自引用 qsort排序结构体 结构体的传参 结构体内存对齐  为什么存在内存对齐? #pragma改变编译器的默认对齐数 结构体实现位段 结构体位段的声明 位段的内存分配 位段的跨平台性 位段的运用 位段使用的注意事项 结构体的类型声明和初始化 结构体的类型声明 C语⾔已经提供了内置类型如char、short、int、long、float、double等但是只有这些内置类型还是不够的假设我想描述学生描述⼀本书这时单⼀的内置类型是不行的。描述⼀个学生需要名字、年龄、学号、身高、体重等C语言为了解决这个问题增加了结构体这种自定义的数据类型让程序员可以自己创造适合的类型。 声明结构体类型时使用的关键字是struct一般形式如下 struct 结构体名 {成员列表 }; 再声明结构体类型的时候不要忘记花括号后面的分号 ; 哦 struct stu {char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号 } 上面的代码用struct申明了一个名为stu的结构体类型在结构体中定义的变量是stu结构体内部的成员这些成员表示名字年龄 性别学号可以根据结构体成员中不同的作用选择与其相对应的类型。 struct stu {char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号 }s,t; 以上是在声明结构体的同时定义了变量st 结构体成员的直接访问 可以用struct结构体名变量名 {成员列表}; 对变量进行直接初始化  #includestdio.h struct Stu {char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号 }; int main() {//按照结构体成员的顺序初始化struct Stu s { 张三, 20, 男, 2023101314 };//按照自定义顺序初始化结构体成员struct Stu t { .sex 男,.name 李四,.id 2023105201,.age 19 };printf(%s %d %s %s\n, s.name, s.age, s.sex, s.id);printf(%s %d %s %s\n, t.name, t.age, t.sex, t.id);return 0; } 也可以利用scanf函数进行输入 #includestdio.h struct Stu {char name[20];int age;char sex[5];int id; }s1; int main() {scanf(%s, s1.name);//数组可以不用取地址符号scanf(%d, s1.age);scanf(%s, s1.sex);scanf(%d, s1.id);printf(%s %d %s %d, s1.name, s1.id, s1.sex, s1.age);return 0; } 数组的前面可以不用取地址符号 因为数组本身就是地址  自定义初始化结构体成员只要 . 点一下就可以显示成员信息啦 结构体成员的直接访问是通过点操作符 . 访问的点操作符接受两个操作数 使用方式结构体变量.成员名   结构体成员的间接访问 我们可以用指向结构体的指针来访问成员变量 #include stdio.h struct Point {int x;int y; }; int main() {struct Point p { 3, 4 };struct Point* ptr p;ptr-x 10;ptr-y 20;printf(x %d y %d\n, ptr-x, ptr-y);printf(x %d y %d\n, p.x, p.y);return 0; } 1.我们这里定义了两个整形成员的结构体类型 2.并对结构体类型变量p成员赋值34 3.我们用指针ptr对结构体类型变量p取地址  4.利用结构体指针操作符-对结构体成员进行访问 使用方式结构体指针-成员名 #include stdio.h #include string.h struct Stu //结构体类型 {char name[15];//名字int age; //年龄 }; void print_stu(struct Stu s) //打印函数 {printf(%s %d\n, s.name, s.age); } void set_stu(struct Stu* ps) {strcpy(ps-name, 李四);//将李四拷贝到结构体变量的name的位置中ps-age 28; //利用指针访问结构体成员的age并赋值 } int main() {struct Stu s { 张三, 20 };print_stu(s); //打印未拷贝前的结构体成员张三set_stu(s); //传址调用print_stu(s); //打印拷贝后的结构体成员李四return 0; } 嵌套结构体进行访问 当出现结构体嵌套时必须以级联方式访问结构体成员即通过成员选择运算符逐级找到最底层的成员时再引用  #includestdio.h struct Str {int year;int month;int day; }; struct Stu {char name[20];int age;char sex[5];char id[20];struct Str date; }; int main() {struct Stu t { .sex 男,.name 李四,.id 2023105201,.age 19 ,.date.year 2023,.date.month 12,.date.day 1 };printf(%s %d %s %s %d-%d-%d\n, t.name, t.age, t.sex, t.id, t.date.year, t.date.month, t.date.day);return 0; } 使用typedef来定义结构体 typedef struct {结构体成员列表; }结构体别名;与没有typedef的的定义的区别在于 1.没有typedef的定义struct Stu s {结构体成员列表} 2.typedef的定义Stu s {结构体成员列表} 3.typedef可以省略struct这个关键字做到简化代码 4.typede可以对匿名结构体重命名 typedef struct {char name[30];int age[10]; }Stu; int main() {Stu s { .name 张三,.age 18 };return 0; } 匿名结构体类型 声明结构体的时候可以不完全声明 #include stdio.h struct {int a;char name;int b;float score; }x; struct {int a;char name;int b;float score; }*p; int main() {*p x;return 0; } 以上的结构体声明省略了结构体名 假如我定义了两个相同结构体类型的变量x和指针p 那么我是否可以*p x呢 答案是不可以的因为结构体是匿名的编译器会认为是两种不一样的类型 匿名的结构体类型如果没有对结构体类型重命名的话基本上只能使⽤⼀次 匿名结构体不建议大家使用的 不过也可以写来备用到时候用typedef重命名就好啦 结构体的自引用 在结构中包含⼀个类型为该结构本⾝的成员是否可以呢像以下代码 struct Stu {int a;struct Stu; }; 答案是不可行的结构体的自引用不像函数递归可以直接自己调用自己 如果上述代码可行的话那么sizeof(struct Stu)的大小是多少呢 因为⼀个结构体中再包含⼀个同类型的结构体变量这样结构体变量的大小就会无穷的大是不合理的 所以要做到结构体的自引用可以借用指针来实现 struct Stu {int a; //存放数据struct Stu* next;//存放下一个节点的地址//next-同类型的结构体指针 }; 我们可以通过存放相同结构体类型的指针来完成自引用 这就是我们以后要学的数据结构中的链表 注意  在结构体自引用的时候最好不要使用typedef对匿名结构体重命名 就像以下代码是不可行的 typedef struct {int a;Stu* next; }Stu; 因为Stu是对前面的匿名结构体类型的重命名产⽣的但是在匿名结构体内部提前使 用Stu类型来创建成员变量 这是不行的 解决的办法是要自引用时定义结构体不要使用匿名结构体  typedef struct Stu {int a;struct Stu* next; }Stu; qsort排序结构体 我们之前说到qsort可以对任意类型的数据排序 接来我们将用它来排序结构体 void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*)); base首元素地址-数组名 num元素个数 size数据类型的大小 int (*compar)(const void*,const void*))比较大小的函数指针 以下我用qsort排序结构体的名字 #includestdio.h struct Stu {char name[20];int age; }; //strcmp-是库函数是专门用来⽐较两个字符串的⼤⼩的不懂可以看我之前的博客 //假设按照名字来⽐较 int PaiXu(const void* e1, const void* e2) {return strcmp(((struct Stu*)e1)-name, ((struct Stu*)e2)-name);//比较字符串的大小返回0或0或0的值 } int main() {struct Stu s[] { {zhangsan, 20}, {lisi, 30}, {wangwu, 15} };int rs sizeof(s) / sizeof(s[0]);qsort(s, rs, sizeof(s[0]), PaiXu);for (int i 0; i rs; i){printf(%s %d\n, s[i].name,s[i].age);}return 0; } 这是从小到大排序从大到小排序可以通过交换两个指针的位置实现 于是我们可以发现结构体按照名字比较最大是zhangsan最小是lisi 结构体的传参 函数的传参我们学过两种 1.传值 2.传址 #includestdio.h struct Stu {int a[1000];int num; }; struct Stu s { {1,2,3,4},1314 }; void Print1(struct Stu s) {printf(%d %d\n, s.a[0],s.num); } void Print2(const struct Stu* s) //用const加以修饰指针说明s不可修改 {printf(%d %d\n,s-a[0], s-num); } int main() {Print1(s); //传值Print2(s); //传址return 0; } 以上我们发现无论是传值还是传址其结果都是一样的 但是空间、时间复杂度上是不一样的 1.传值比如说我结构体成员中定义了长度为1000的数组a[1000]我的实参开辟了1000个存储空间而传结构体的值过去我的形参也要开辟1000个存储空间多的空间不用这就造成了空间上的浪费 2.传址我们传结构体的地址过去形参中就可以不用多开辟空间效率就高。再加上可以利用const对结构体指针加以限制就可以避免对实参地址的破坏 1.函数传参的时候参数是需要 压栈 会有 时间和空间上的系统开销 。 2.如果传递⼀个结构体 对象的时候结构体过大参数压栈的的系统开销比较大 所以会导致性能的下降。 所以我们一般选择传址调用~ 结构体内存对齐  首先得掌握结构体的对齐规则 1. 结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处 2. 其他成员变量要对齐到某个数字对齐数的整数倍的地址处 对齐数 编译器默认的⼀个对齐数与该成员变量大小的较小值 VS 中默认的值为 8 Linux中gcc没有默认对齐数对齐数就是成员自身的大小 3. 结构体总大小为最⼤对齐数结构体中每个成员变量都有⼀个对齐数所有对齐数中最⼤的整数倍 4. 如果嵌套了结构体的情况嵌套的结构体成员对齐到⾃⼰的成员中最⼤对⻬数的整数倍处结构体的整体⼤⼩就是所有最⼤对⻬数含嵌套结构体中成员的对⻬数的整数倍 我们来看以下代码  再没有学结构体内存对齐之前 大家对以下结构体的大小认识还不是还停留在 两个char类型2个字节一个int类型4个字节结构体就是6个字节  看看S1和S2的大小是多少  #includestdio.h struct S1 {char c1;int i;char c2; }; struct S2 {char c1;char c2;int i; }; int main() {printf(%d\n, sizeof(struct S1));printf(%d\n, sizeof(struct S2));return 0; } 我们发现S1和S2的大小并不是我们预想的6个字节 而是S1是12个字节S2是8个字节 为什么呢请你带着知识的困惑来看我们的结构体内存对齐 以上是S1的情况我们来看 因为VS编译其中默认对齐数是8而(char)、(int)类型的大小是1和4 所以char的对齐数是1int的对齐数是4最大对齐数是4 char一个字节对齐起始位置偏移量为0的地址处 因为1到3地址不是int对齐数的整数倍所以要浪费空间 int要从4地址开始取地址当char取了9地址的时候 由于结构体总大小要为最大对齐数的整数倍所以要浪费空间到12地址 我们来看S2的情况 因为VS编译其中默认对齐数是8而(char)、(int)类型的大小是1和4 所以char的对齐数是1int的对齐数是4最大对齐数是4 char一个字节对齐起始位置偏移量为0的地址处 因为2到3地址不是int对齐数的整数倍所以要浪费空间 int要从4地址开始取地址取到8地址是结构体最大对齐数的整数倍 我相信聪明的你已经学会了接下来看嵌套一个结构体的情况 #includestdio.h struct S2 {char c1;char c2;int i; }; struct S4 {char c1;struct S2 s2;double d; }; int main() {printf(%d\n, sizeof(struct S2));printf(%d\n, sizeof(struct S4));return 0; } 因为VS编译其中默认对齐数是8 而(char)、(double)、S2类型的大小是1、8、8 所以char的对齐数是1double、S2的对齐数是8最大对齐数是8 char一个字节对齐起始位置偏移量为0的地址处 嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处 S2成员最大对齐数是4所以1到3的空间要浪费直到取到12地址 double要对齐所以要浪费13到15的空间直到取到24 24是结构体最大对齐数的整数倍所以结构体大小就是24 为什么存在内存对齐? 平台原因 不是 所有的硬件平台 都能访问任意地址上的任意数据 的 某些硬件平台只能在 某些地址处取某些特定类型的数据 否则抛出硬件异常 性能原因 数据结构(尤其是栈)应该 尽可能地在自然边界上对齐 原因在于 为了访问未对齐的内存处理器需要作两次内存访问 而 对齐的内存访问仅需要⼀次访问 符合的数据更快被CPU访问。 假设⼀个处理器总是从内存中取8个字节则地址必须是8的倍数。 如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数 那么就可以⽤⼀个内存操作来读或者写值了。 否则我们可能需要执行两次内存访问 因为对象可能被分放在两个8字节内存块中。 结构体的内存对齐是拿空间来换取时间的做法 那在设计结构体的时候我们既要满足对齐又要节省空间如何做到 让占⽤空间⼩的成员尽量集中在⼀起 就像我们刚刚写的代码S2的大小是8S1的大小是12 #includestdio.h struct S1 {char c1;int i;char c2; }; struct S2 {char c1;char c2;int i; }; int main() {printf(%d\n, sizeof(struct S1));printf(%d\n, sizeof(struct S2));return 0; } #pragma改变编译器的默认对齐数 #include stdio.h #pragma pack(1)//设置默认对⻬数为1 struct S {char c1;int i;char c2; }; #pragma pack()//取消设置的对⻬数还原为默认 int main() {printf(%d\n, sizeof(struct S));return 0; } 结构体在对齐方式不合适的时候我们可以自己更改默认对齐数 结构体实现位段 结构体位段的声明 1.位段的成员必须是 int、unsigned int 或signed int 在C99中位段成员的类型也可以 选择其他类型char比较常见 2.位段的成员名后边有⼀个冒号和⼀个数字 位段的作用节省内存空间  struct A {int _a:2;int _b:5;int _c:10;int _d:30; }; 这时的A就是一个位段  我们来看一下struct A的大小是多少 #include stdio.h struct A {int _a : 2;int _b : 5;int _c : 10;int _d : 30; }; int main() {printf(%d, sizeof(struct A));return 0; } 首先我们要理解冒号后面的是什么 位段就是一个二进制位 冒号后面的数据的单位就是比特位  我们发现strcut A的大小是8那么8代表什么呢  我们来看如果冒号后面的数据单位是比特位的话 那么struct A的大小就是47个比特位 一个整形4个字节就是32个比特位不够 两个整形就是8个字节就是64个比特位 所以8代表8个字节 如果我们按照原始的方法存储的话4个整形就是16个字节 而我们位段只需要8个字节就可以了节省了内存空间  位段的内存分配 1. 位段的成员可以是 int unsigned int signed int 或者是 char 等类型 2. 位段的空间上是按照需要以 4个字节 int 或者1个字节 char 的方式来开辟的。 3. 位段涉及很多不确定因素位段是不跨平台的注重可移植的程序应该避免使用位段。 所以位段很依赖编译器我们来认识VS下的位段 从右向左使用 如果剩余空间不够下一位成员使用就浪费 位段的跨平台性 1. int 位段被当成有符号数还是无符号数是不确定的 2. 位段中最大位的数目不能确定。16位机器最⼤1632位机器最⼤32写成27在16位机器会出问题 3. 位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义 4. 当⼀个结构包含两个位段第二个位段成员比较大无法容纳于第⼀个位段剩余的位时是舍弃剩余的位还是利用这是不确定的 总结 跟结构相比位段可以达到同样的效果 并且可以很好的节省空间但是有跨平台的问题存在 位段的运用 能够对网络信息进行封装从而提高运行效率。 下图是网络协议中IP数据报的格式我们可以看到其中很多的属性只需要几个bit位就能描述这里使用位段能够实现想要的效果也节省了空间这样网络传输的数据报大小也会较小⼀些对⽹络的畅通是有帮助的。 位段使用的注意事项 位段的几个成员共有同⼀个字节这样有些成员的起始位置并不是某个字节的起始位置那么这些位置处是没有地址的。内存中每个字节分配⼀个地址⼀个字节内部的bit位是没有地址的。 所以不能对位段的成员使用操作符这样就不能使用scanf直接给位段的成员输⼊值只能是先输入放在⼀个变量中然后赋值给位段的成员。 #inclduestdio.h struct A {int _a : 2;int _b : 5;int _c : 10;int _d : 30; }; int main() {struct A sa { 0 };scanf(%d, sa._b);//这是错误的//正确的示范int b 0;scanf(%d, b);sa._b b;return 0; } 通过本篇博客 我相信大家对C语言结构体都有了一定的理解 希望这些知识可以运用在你的实际生活中
http://www.w-s-a.com/news/912630/

相关文章:

  • 按营销型网站要求重做网站 费用点金网站建设
  • 深圳做网站互联网服务
  • 网站sem托管wordpress安装无法连接数据库
  • 深圳网站建设开发公司哪家好微信小程序商家入口
  • 江门站排名优化建立什么网站赚钱
  • 科普文章在那个网站做招聘网站代做
  • 监控设备东莞网站建设游戏网站域名
  • 对商家而言网站建设的好处网址导航怎么彻底删除
  • app设计网站模板企业展厅策划设计公司有哪些
  • wordpress销售主题手机网站关键词优化
  • 怎么查一个网站是什么程序做的三亚城乡建设局网站
  • 深圳分销网站设计公司做网站一般需要多久
  • 企业网站设计代码丹东seo排名公司
  • 企业网站建设定制开发服务网站建设说课ppt
  • 大连市城乡建设局网站网站免费网站入口
  • 做暧网站网站备案ps
  • 知名网站建设公司电话长子网站建设
  • 网站建设的意义与目的建立什么船籍港
  • 广州注册公司营业执照网站建设代码优化
  • 百度网站官网马克互联网主题 wordpress
  • 网站制作 客户刁难深圳自助建站
  • 怎么去推广一个网站广东餐饮品牌设计
  • 网站代码加密了怎么做兰州最新大事
  • 现在ui做的比较好的网站去年做啥网站致富
  • 广东网站建设咨询电话好牌子网
  • 公司怎样制作网站南阳网站关键词
  • 营销型网站建设与网盟完整php网站开发
  • 网站做微信链接怎么做的石桥铺网站建设公司
  • 济南mip网站建设公司做图书馆网站模板
  • app 门户网站网站项目框架