c 中 怎样动态定义二维结构体数组_剖析c语言结构体的高级用法(一)

本文介绍了C语言中结构体的多种使用方式,包括结构体变量、结构体数组、结构体指针数组、结构体嵌套及结构体函数指针的使用,并通过实例详细讲解了如何动态定义二维结构体数组,同时探讨了结构体嵌套中自引用和相互引用的问题,以及结构体赋值的操作。

                               前言                                 

 在写这篇文章之前,说实话,自身对结构体的用法,只会两点——就是点访问式和指针式访问结构体内部成员。这对一个搞底层的工程师来讲,显然实在太low了。不妨读者看到这里,可以停下来思索一下,看看自己对c语言结构体掌握了多少。下面是我这几天结合自己的学习而总结的一篇算比较全的关于结构体的用法,欢迎大家来吐槽。

     正文  

     其实在之前的文章里面,我已经有说为啥在c语言里面要引入结构体这一概念——超详细的链表学习,这里的话,我就不再废话了,直接来点实际的。

一、结构体的各种使用方法(很全):

  • 这里的话,我以实际例子直接开干,就不过多的介绍一些非常基础的东西(有没看明白的读者可以上网查)。
1、结构体传参:     a、先来看第一个实际例子(结构体指针做形参):
 1# include 
2# include 
3
4struct Student {
5    char name[20];
6    float fScore[3];
7}student = {"dire",98.5,89.0,93.5}; //初始化结构体变量 
8
9
10void Display(struct Student *pStruct)11{
12     printf("------Information-------\n");
13     printf("Name:%s\n",pStruct->name);
14     printf("Chinese:%.2f\n",(*pStruct).fScore[0]);
15     printf("Math:%.2f\n",(*pStruct).fScore[1]);
16     printf("English:%.2f\n",pStruct->fScore[2]);
17}
18
19
20int main ()21{
22        Display(&student);        //将结构体变量的首地址作为实参传入pStruct指针变量中 
23
24        return 0;
25}
演示结果:

9696828748b3ff68db3d5d624391ad34.png

说明:

         这里我们定义了一个结构体struct student  ,并且定义了结构体变量student,同时为结构体各个成员赋值,然后定义了一个函数,这个函数传参里面定义了一个结构体变量;然后我们在主函数里面把结构体变量的地址作为函数形参传入到函数里面去;然后在函数里面进行一些操作,比如正如你所见一样,都是在访问结构体成员,而且是指针式的访问(书上把"->"叫做箭头操作符),这个正如我上面开头所说,很常见,但你细心的话,你发现了一个(*pStruct).fScore[0]居然也能够访问成功(看到这里想必你平时可能就没怎么看到这种写法了吧,哈哈哈。),这种写法也是可以的,下次见到就不要见怪 了。

    b、再来看一个示例(结构体变量做形参):

 1   #include 
2   typedef struct A{
3            int a;
4   }s;
5  void fun(s b) 6  {
7        b.a=99;
8        printf("the b.a is %d\n",b.a);
9 }
10 int main(void)11 {
12         s c; //这里的s等价于struct A
13         c.a=8;
14         printf("the c.a is %d\n",c.a);
15
16         fun(c);
17
18         return 0;
19 }

演示结果:

1a08fe75e50cec4002cdc44712f72a95.png

说明:

       这里定义结构体的时候,使用关键字typedef,这个时候结构体右大括号的后面s就不是表示结构体变量了,而是给结构体struct A起了一个别名叫s仅此而已,方便你少敲几个键盘。

2、结构体数组的几种使用形式:

       a、结构体数组示例:

 1   #include 
2   struct{
3     char *name;  //姓名
4     int num;  //学号
5     int age;  //年龄
6     char group;  //所在小组
7     float score;  //成绩
8  }class[5] = {
9    {"Li ping", 5, 18, 'C', 145.0},
10    {"Zhang ping", 4, 19, 'A', 130.5},
11    {"He fang", 1, 18, 'A', 148.5},
12    {"Cheng ling", 2, 17, 'F', 139.0},
13    {"Wang ming", 3, 17, 'B', 144.5}
14};
15int main()16{
17     int i, num_140 = 0;
18     float sum = 0;
19     for(i=0; i<5; i++)
20     {
21         sum += class[i].score;
22         if(class[i].score 140) num_140++;
23     }
24    printf("sum=%.2f\naverage=%.2f\nnum_140=%d\n", sum, sum/5, num_140);
25    return 0;
26   }

演示结果:

e155deddd3bb277df3618d1ba907fa83.png

说明:

       上面的结构体数组class[5]相当于数组里面的每个一个元素是一个结构体。

    b、结构体指针数组:

 1    #include  
2    typedef struct A{
3         int a;
4     }s,*st;
5      int main(void) 6      {
7         s stu1,stu2;
8         st array[2];
9         stu1.a=2;
10         stu2.a=3;
11         array[0]=&stu1;
12         array[1]=&stu2;
13         printf("thearray[0]=%d,array[1]=%d\n",array[0]- >a,array[1]->a);
14
15         return 0;
16    } 

演示结果:

97e4a8f4e086a436ebb4c6b862e38695.png

说明:

        这里的用法跟指针数组用法差不多——c专题之指针---数组指针与指针数组的区别。这里你可能会说了,既然有结构体指针数组的使用,那是不是也也应该有结构体数组指针的用法,我要告诉你的是,这里我做了测试,没有成功,我这里给你看示例(因为我在网上和书上没有查到这种用法,我觉得应该是没有;如果读者看到这里有什么建议可以和我说;我这里测试了只有下标是0的时候,可以访问成功,其他下标不能成功):
 1  #include 
2  struct R{
3int a;
4int b;
5char *name;
6}s[3]={{2,4,"like"},{3,5,"like"},{2,4,"like"}};
7int main(void) 8{
9    struct R (*array)[3];
10    array=&s;
11    printf("the array->b is %d\n",array[0]->a);
12
13return 0;
14 }

      c、结构体里面嵌套结构体数组(这里就顺便也讲了结构体嵌套的知识点了):

结构体嵌套的问题有哪些?

----结构体的自引用,就是在结构体内部,包含指向自身类型结构体的指针。

----结构体的相互引用,就是说在多个结构体中,都包含指向其他结构体的指针

结构体应该注意的问题?

----结构体定义中可以嵌套其他结构体类型的变量,不可以嵌套自己这个类型的变量。

 1 #include
2 struct E {
3     int a;
4 };
5  struct D{
6    struct D a; //A是一个结构体,A的内部还会有一个结构体,
7    //以此下>去,无线循环(类似于递归函数)。在内存分配的时候,由于无限的嵌套,无法确定结构体的长度,所>以时非法的。
8    struct E b;
9    int value;
10};
11int main()12{
13    return 0;
14}

演示结果:

5c71c7a8055cffebbdec0223049e8d80.png

----可以嵌套自己类型的指针。

 1 #include
2 struct E {
3     int a;
4 };
5  struct D{
6
7     struct D *c;
8    struct E b;
9    int value;
10};
11int main()12{
13    return 0;
14}

说明:

      由于指针的长度时确定的(在32位机器上指针长度是4),所以编译器能够确定该

结构体的长度。

       这个指针看似指向自身,其实不是,而是执行同一类型的不同结构。

综合应用:

 1#include 
2 struct A{
3int year;
4int month;
5int day;
6 };
7
8   struct B{
9     long int num;
10     struct A a;
11     //    struct A *b;
12     struct A array[3];
13     char *name;
14}s1={200,{1998,2,3},{{1999,3,4},{1999,5,6}, 
15 {1999,7,8}},"wangwu"};
16
17  int main(void)18   {
19    struct B s2;
20    s2=s1;  
21   printf("%ld %s %d\n",s2.num,s2.name,sizeof(int));
22printf("year:%d,month:%d,day:%d\n",s2.a.year,s2.a.month,s2.a.day);
23printf("year:%d,month:%d,day:%d\n",s2.array[0].year,s2.array[0].month,s2.array[0].day);
24printf("year:%d,month:%d,day:%d\n",s2.array[1].year,s2.array[1].month,s2.array[1].day);
25printf("year:%d,month:%d,day:%d\n",s2.array[2].year,s2.array[2].month,s2.array[2].day);
26  return 0;
27 }

演示结果:

60d4cd4751ade6818bff4bf5848e4ef8.png

说明:

        在这里我们可以看到,结构体之间是可以进行赋值的,就比如s2=s1,这样就可以用结构体变量s2来继续访问结构体里面的各个成员(可以达到同样的效果的)。这里在结构体里面嵌套了结构体变量和结构体数组,用法和不嵌套的时候是一样的。下面我们关键来讲一下这个结构体里面嵌套结构体指针,该怎样来操作呢,这是要讲的重点了(读者看到这里也可以先想想该如何进行操作):

 1 #include 
2  struct B{
3    long int num;
4    struct B*b;
5 }s1={200,0};
6
7  int main(void) 8  {
9struct B s2={200,&s1
10};
11
12     printf("the s2.num=%ld\n",s2.num);
13     printf("(*(s2.b)).num=%ld\n",(*(s2.b)).num);
14
15return 0;
16  }

演示结果:

5d2943e2dea6c4f1ce359a6b879bad05.png

说明:

       这里操作的话,转了一个弯来,总之还是那句话,你在使用指针的时候,记得事先一定要给它赋有效的地址值,千万不要是NULL(关于这个原因可以看这里——c专题之指针---野指针和空指针解析)。下面是我在网上看到的多嵌套的写法(大家只要了解一下就行,实际写代码不会这样搞,这样搞确实是比较恶心):

 1   #include
2   struct s1 3   {
4         float a;
5         struct 6        {
7           int ba;
8           int bb;
9
10           struct11           {
12               int bca;
13               int (*bcb)[3];//数组指针
14            } *bc;
15        } b;
16    };
17int main( void )18{
19int a[3]={3};
20struct21{
22    int bca;
23    int (*bcb)[3];
24}bc=
25{
26    3,
27    &a
28};
29
30struct s1 s=31{
32    3.14,
33    {
34        1,
35        2,
36        ( void* )&bc
37    }
38};
39    struct s1 *p=&s;
40    printf("%d\n",*(p->b.bc->bcb)[0]);
41    return 0;
42 }

演示结果:

d03f3606d1c0c7b04369be88a35ba3f3.png

3、结构体函数指针:

 1 #include 
2 #include 
3 struct A{
4int(*add)(int a,int b);//函数指针
5int(*sub)(int a,int b);
6int(*mult)(int a,int b); 
7   };
8   int test_add(int a,int b) 9   {
10        return (a+b);
11   }
12   int test_sub(int a,int b)13   {
14        return (a-b);
15   }
16  int test_mult(int a,int b)17  {
18        return (a*b);
19   }
20  void print_usage()21 {
22        printf("打印用法\n");
23 }
24 int main(int argc,char **argv)25   {
26        struct A s={
27       .add=test_add,
28       .sub=test_sub,
29       .mult=test_mult,
30          };
31      int a=9,b=3;
32         printf("a+b=%d\n",s.add(a,b));
33          printf("a-b=%d\n",s.sub(a,b));
34          printf("a*b=%d\n",s.mult(a,b));
35
36           return 0;
37 } 

演示结果:

52c883c56c9637fcb619d73e5af32368.png

说明:

       用法还是和函数指针的用法一样,区别不大。

二、总结:

       上面汇总了一些结构体的高级用法,有些不怎么常见,但是开阔一些眼界还是有的,哈哈。

319e588df241c0b179c513dbc2bcbbbf.png


32ebac4741d257b9f75ab99d9ce969f0.gif

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值