精华内容
下载资源
问答
  • 结构体如下 struct ff{ int b; int *c; }; struct ff *p=(struct ff *)malloc(sizeof(struct)); p->c=(int *)malloc(sizeof(int)*5); *(p->c+1)=5; 最后一句这样的指针运算,引用,赋值。是否合法。
  • C语言结构体

    2018-12-17 11:22:00
    C语言结构体初始化的四种方法 C语言聚合数据类型包括数组和结构体,其中数组中是相同类型的元素的集合,可以通过下标引用或之子很间接访问,但结构体各个成员可以是不同的数据类型。 结构声明 完整的结构声明:...

    C语言结构体初始化的四种方法

    C语言聚合数据类型包括数组和结构体,其中数组中是相同类型的元素的集合,可以通过下标引用或之子很间接访问,但结构体各个成员可以是不同的数据类型。

    结构声明

     完整的结构声明:struct tag {number-list} variable-list; 黑体部分至少要出现两个。

    {number-list}和variable-list,每次声明新变量都要用单独的声明,而且每次声明后并不是同一种类型,尽管结构体内容完全一样

     1 struct {
     2     int a;
     3     float b;
     4     char c;
     5 }x;
     6 
     7 struct {
     8     int a;
     9     float b;
    10     double c;
    11 }*z;
    12 
    13 z = &x;//这样赋值是错误的,因为类型不一致,但C语言会忽略,C++会报错

      tag和{number-list},这样不用每次都使用单独的声明,只用struct tag即可对结构变量进行声明。

    1 struct temp{
    2     int a;
    3     float b;
    4     char c;
    5 };
    6 struct temp x;
    7 struct temp *z;

     typedef、{number-list}和name,这样不用每次都使用单独的声明,只用name即可对结构变量进行声明,比上面的tag更加简洁,这时name是类型名,而不是结构标签。

    1 typedef struct {
    2     int a;
    3     float b;
    4     double c;
    5 }temp;
    6 temp x;
    7 temp *z;

     结构体初始化

    (1)定义时赋值,需要对应顺序,不能错位

     1 temp x = {1, 2.3, 4.66}; 

    (2)定义后逐个赋值

    temp x;
    x.a = 1;
    x.b = 2.3;
    x.c = 4.66;
    

    (3)定义时乱序赋值(C风格),这种方法在Linux内核(kernel)中经常使用,在音视频编解码库FFmpeg中也大量频繁使用,还是很不错的一种方式。

    temp x = {
    	.b = 2.3,
    	.a = 1,
    	.c = 4.66
    
    };
    

    (4)定义时乱序赋值(C++风格),类似于key-value键值对的方式

    temp x = {
    	b : 2.3,
    	a : 1,
    	c : 4.66
    };

    访问结构成员

    (1)直接访问

     如上面声明的结构体变量所示,对x中的成员进行访问时,如下访问

    int m = x.a; 
    float = x.b;

    (2)间接访问

     如果存在指向结构体的指针,则如下访问

    int m = (*z).a;
    int m = z->a;

    结构的自引用

     结构内部包含一个类型为结构本身的成员,为自引用,高级的数据结构,链表和树都用到了该种结构。

    声明时,编译器需知道结构体的大小,以便分配内存空间,所以不能直接用该结构体,否则会无限循环下去,无法知道结构体的大小。因此需要对该结构体成员使用指针。指针长度是固定的,取决于使用的机器和编译器,因此长度可知。

     1 typedef struct {
     2     int a;
     3     temp *b;
     4     double c;
     5 }temp; 
     6 //上面是错误的
     7 typedef struct selftemp_tag{
     8     int a;
     9     struct selftemp_tag *b;
    10     double c;
    11 }selftemp;

    上面的声明是错误的,因为temp *b在声明之前就使用了。下面的声明中,定义了一个tag标签来解决该问题,同时标签前需加struct。

    结构的互引用(不完整声明,还不知道怎么用)

     结构体之前互相引用,那么哪个结构应该首先声明呢?问题的解决方案是使用不完整声明,它声明一个作为结构标签的标识符

     1 struct B;
     2 
     3 struct A{
     4     struct B * partner;
     5     //其他声明
     6 };
     7 
     8 struct B{
     9     struct A * partner;
    10     //其他声明
    11 };

    在A的成员列表中需要标签B的不完整声明,一旦A声明之后,B的成员列表也可被声明.(并不知道怎么用)

    结构进行函数传参 

     结构变量用作函数参数进行传递时,如果传递整个结构体的话,结构体成员少时并没有影响,若成员很多,传递整个结构体会浪费内存空间,因此这时应该传递结构体指针,从而提高传递效率。

    联合

     如果想在不同时刻把不同的东西存储在同一个位置,就需要用到联合,声明和结构体类似

    union {
    	float f;
    	int i;
    }fi;

    当存储在同一位置的不仅仅是简单的整型或浮点型数值,而是完整的结构时,称为变体记录,具体程序实例参考《c和指针》P213

    联合的各个成员具有不同的长度,联合的长度就是它最长成员的长度,因此如果没有动态内存分配的话,默认按照最长成员的长度进行内存分配,会造成内存空间的浪费。

    联合的变量可以被初始化,但初始值必须是联合第一个成员的类型

    union {
    	float f;
    	int i;
    }fi = {0.5};

    初始化的值必须位于一对花括号里面。

    转载于:https://www.cnblogs.com/qinguoyi/p/10130435.html

    展开全文
  • c语言结构体引用元素“.”与“->”辨析 后缀表达式后跟一个圆点和一个标识符仍是后缀表达式。第一个操作数表达式的类型必须是结构或联合,标识符必须是结构或联合的成员的名字。结果值是结构或联合中命名的成员,...

    c语言结构体引用元素“.”与“->”辨析

    后缀表达式后跟一个圆点和一个标识符仍是后缀表达式。第一个操作数表达式的类型必须是结构或联合,标识符必须是结构或联合的成员的名字。结果值是结构或联合中命名的成员,其类型是对应成员的类型。如果第一个表达式是一个左值,并且第二个表达式的类型不 是数组类型,则整个表达式是一个左值。
    后缀表达式后跟一个箭头(由-和>组成)和一个标识符仍是后缀表达式。第一个操作数 表达式必须是一个指向结构或联合的指针,标识符必须是结构或联合的成员的名字。结果指向指针表达式指向的结构或联合中命名的成员,结果类型是对应成员的类型。如果该类型不是数组类型,则结果是一个左值。
    因此,表达式 E1->MOS 与(*E1).MOS 等价(此处E1是指向结构体的指针)
    表达式E1.MOS与(&E1)->MOS等价(此处E1是一个结构体)
    展开全文
  • c语言结构体学习整理(结构体初始化,结构体指针)

    千次阅读 多人点赞 2019-06-02 15:16:47
    1、C语言结构体 1.1几种常用的结构体定义 1.2注意: 2、关于结构体变量的定义和引用 3、结构体的存储(内存对齐) 3.1结构体成员优化 4、结构体自引用 5、结构体的不完整声明 6、结构体传参 结论 7、...

    出处:https://blog.csdn.net/as480133937/article/details/83473208


    目录

    1、C语言结构体

    1.1几种常用的结构体定义

    1.2注意:

    2、关于结构体变量的定义和引用

    3、结构体的存储(内存对齐)

    3.1结构体成员优化

    4、结构体自引用

    5、结构体的不完整声明

    6、结构体传参

    结论

    7、结构体变量的初始化

    7.1定义时赋值

    7.2定义结构体之后逐个赋值

    7.3定义之后任意赋值

    8、结构体数组及其初始化

    8.1结构数组初始化

    8.2数组初始化

    8.3四种方法

    9、结构体与指针

    9.1指向结构体变量的指针

    9.2向结构体数组的指针

    9.3结构体成员是指针类型变量


    1、C语言结构体

    数据经常以成组的形式存在。例如,雇主必须明了每位雇员的姓名、年龄和工资。如果这些值能够存储在一起,访问起来会简单一些。但是,如果这些值的类型不同(就像现在这种情况),它们无法存储于同一个数组中。在C中,使用结构可以把不同类型的值存储在一起。

    1.1几种常用的结构体定义

    //结构体名也叫标识符
    
    struct 结构体名{
        结构体所包含的变量或数组
    };
    
    struct{
        结构体所包含的变量或数组
        //后面不需要再使用结构体名定义其他变量,那么在定义时也可以不给出结构体名
        //这样做书写简单,但是因为没有结构体名,后面就没法用该结构体定义新的变量。
    } name1, name2;
    
    tepedef struct{
        结构体所包含的变量或数组
    } name;
    /* 声明变量时只能:name Stu*/
    
    tepedef struct 结构体名{
        结构体所包含的变量或数组
    } name;
    /* 声明变量时可:name Stu 或者 struct 结构体名 Stu*/
    
    struct 结构体名 *变量名;
    
    总结:最好带有结构体名进行定义声明。


    结构与数组的区分:

    聚合类型:能够同时存储超过一个的单独数据。

    C语言提供了两种类型的聚合数据类型,那就是数组和结构。那么这两者之间有什么区分呢?

    数组:它是相同类型的元素的集合;他的每个元素是通过下表引用或指针间接访问来选择(因元素长度相同,课通过下表访问);

    结构:是具有不同类型的成员;因结构的成员长度不同,所以不内容能通过下标访问,是通过名字访问;结构的变量属于标量类型

     

    1.2注意:

    [注意]

    1. 结构体和结构体变量是两个不同的概念:结构体是一种数据类型,是一种创建变量的模板,编译器不会为它分配内存空间,就像 int、float、char 这些关键字本身不占用内存一样;结构体变量才包含实实在在的数据,才需要内存来存储。
    2. 结构体中各成员的定义和之前的变量定义一样,但在定义时也不分配空间
    3. 结构体变量的声明需要在主函数之上或者主函数中声明,如果在主函数之下则会报错
    4. c语言中的结构体不能直接进行强制转换,只有结构体指针才能进行强制转换
    5. 相同类型的成员是可以定义在同一类型下的

     5.例如:

    
    struct Student
    { 
    	int number,age;//int型学号和年龄
    	char name[20],sex;//char类型姓名和性别
    	float score;
    };
    

    2、关于结构体变量的定义和引用

    在编译时,结构体的定义并不分配存储空间,对结构体变量才按其数据结构分配相应的存储空间

    
     struct Book
     { 
     	char title[20];//一个字符串表
    
    示的titile 题目
    	char author[20];//一个字符串表示的author作者
     	float value;//价格表示 
     };//这里只是声明 结构体的定义 
    struct Book book1,book2;//结构体变量的定义 分配空间
    
    book1.value;//引用结构体变量
    

    定义结构体变量以后,系统就会为其分配内存单元,比如book1和book2在内存中占44个字节(20+20+4)具体的长度你可以在你的编译器中使用sizeof关键字分别求出来。

    例如:

    #include<stdio.h>
    
    struct Book
    {
        char title[20];//一个字符事表示的titile题目
        char author[20];/∥一个字符表示的author作者
        float value;//价格表示
    };//这星只是声明结构体的定义
    
    struct Book book1,book2;//结构体变量
    
    int main()
    {
        sizet size=sizeof(int);
        size t sizel=sizeof(char);
        size t size2=sizeof(float);
        size_t size3=sizeof(book1);
        printf("int占%d\nchar占%d\nfloat占%xd\nbook1占%xd",size,size1,size2,size3);
    }
    

    注意:用sizeof关键字求结构体长度时,返回的最大基本类型所占字节的整数倍 比方说我们上面求得的为44 为 float(4个字节)的整数倍,但是我们把title修改为title[22]; 这时正常长度为46 ,但是你会发现实际求得的为48,(4的整数倍)

    3、结构体的存储(内存对齐)

    1. 结构体整体空间是占用空间最大的成员(的类型)所占字节数的整数倍。
    2. 结构体的每个成员相对结构体首地址的偏移量(offset)都是最大基本类型成员字节大小的整数倍,如果不是编译器会自动补齐,

    关于这个我们简单介绍下:

    偏移量----偏移量指的是结构体变量中成员的地址和结构体变量首地址的差。即偏移字节数,结构体大小等于最后一个成员的偏移量加上他的大小,第一个成员的偏移量为0

    struct S1
    {
        char a;
    
        int b;
    
        double c;
    };
    

    这里char a 偏移量为1 之后为int b 因为偏移量1不为int(4)的整数倍,所以会自动补齐,而在 double c 时,偏移量为8 是double(8)的整数倍,所以不用自动补齐 最后求得结构体得大小为 16

    如图所示:

    å¨è¿éæå¥å¾çæè¿°

    结构体对齐规则:

    1. 第一个成员在与结构体变量偏移量为0的地址处。
    2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数=编译器默认的对齐数与该成员大小的较小值。VS中默认对齐数为8,linux默认对齐数为4.
    3. 结构体总大小为最大对齐数(每个成员都有一个对齐数)的整数倍。
    4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

    3.1结构体成员优化

    你可以在声明中对结构的成员列表重新排列,让那些对边界要求最严格的成员首先出现,对边界要求最弱的成员最后出现。这种做法可以最大限度地减少因边界对齐而带来的空间损失。例如,下面这个结构

    struct ALIGN2{
        int b;
        char a;
        char c;
    }
    

    所包含的成员和前面那个结构一样,但它只占用8个字节的空间,节省了33%。两个字符可以紧挨着存储,所以只有结构最后面需要跳过的两个字节才被浪费。

    #include<stdio.h>
    //用typedef定义了一个结构体
    typedef struct book
    {
        char title[20];
        char author[20];
        float value;
    }BOOK; //这里的BOOK就等于struct book
    
    int main()
    {
        B0OK book1={
        “Hamlet",
        "shakespeare”,
        25};
    
        printf("%s\n",book.title);
        printf("%d",book.value);
    };
    
    等价于:
    struct book book1{
    "....."
    "....."
    "....."
      ...
    };
    

     

    4、结构体自引用

    在一个结构内部包含一个类型为该结构本身的成员是否合法呢?这里有一个例子,可以说明这个想法。
     

    struct SELF_REF1{
            int a;
            struct SELF_REF1b;
            int c;
    }

    这种类型的自引用是非法的,因为成员b是另一个完整的结构,其内部还将包含它自己的成员b。这第2个成员又是另一个完整的结构,它还将包括它自己的成员b。这样重复下去永无止境。这有点像永远不会终止的递归程序

    正确的结构体自引用如下:
     

    struct SELF_REF2{
            int a;
            struct SELF_REF2*b;
            int c;
    };

    这个声明和前面那个声明的区别在于b现在是一个指针而不是结构。编译器在结构的长度确定之前就已经知道指针的长度,所以这种类型的自引用是合法的。

    警告:
    警惕下面这个陷阱(没有结构体名):

    typedef struct(
                int a;
                SELF_REF3*b;
    }SELF_REF3;
    
    这个声明的目的是为这个结构创建类型名SELF_REF3。但是,它失败了。
    类型名直到声明的末尾才定义,所以在结构声明的内部它尚未定义。


    解决方案是定义一个结构标签来声明b,如下所示:
     

    typedef struct SELF_REF3_TAG{
                int a;
                struct SELF_REF3_TAG*b;
                int c;
    )SELF_REF3;

    5、结构体的不完整声明

    偶尔,你必须声明一些相互之间存在依赖的结构。也就是说,其中一个结构包含了另一个结构的一个或多个成员。和自引用结构一样,至少有一个结构必须在另一个结构内部以指针的形式存在。

    问题在于声明部分:如果每个结构都引用了其他结构的标签,哪个结构应该首先声明呢?

    解决方案是使用不完整声明(incomplete declaration):它声明一个作为结构标签的标识符。然后,我们可以把这个标签用在不需要知道这个结构的长度的声明中,如声明指向这个结构的指针。接下来的声明把这个标签与成员列表联系在一起。

    struct B;
    
    struct A{
        struct B*partner;
        /*other declarations*/
    );
    
    struct B{
        struct A *partner;
        /*other declarations */
    );

    在A的成员列表中需要标签B的不完整的声明。一旦A被声明之后,B的成员列表也可以被声明。

    6、结构体传参

    typedef struct{
        char product[PRODUCT_SIZE]; //PRODUCT_SIZE = 20
        int quantity;
        float unit_price;
        float total_amount;
    } Transaction;
    
    void print_receipt(Transaction trans)
    {
        printf("%s\n", trans. product);
         printf("%d @%.2f total %.2f\n", trans.quantity, trans.unit_price, trans.total_amount;
    }
    

    如果current_trans是一个Transaction结构,我们可以像下面这样调用函数:

    print_receipt( current_trans);

    警告:

    这个方法能够产生正确的结果,但它的效率很低,因为C语言的参数传值调用方式要求把参数的一份拷贝传递给函数。机器上整型和浮点型都占4个字节,那么这个结构将占据32个字节的空间。要想把它作为参数进行传递,我们必须把32个字节复制到堆栈中,以后再丢弃。

    代码修改:

    void print_receipt(Transaction * trans)
    {
        printf("%s\n", trans->product);
        printf("8d e%.2f total %.2f\n", trans->quantity, trans->unit _price, trans->total_amount);
    }
     

    这个函数可以像下面这样进行调用:

    print_receipt(&current_trans);

    这次传递给函数的是一个指向结构的指针。指针比整个结构要小得多,所以把它压到堆栈上效率能提高很多。

    传递指针另外需要付出的代价:是我们必须在函数中使用间接访问来访问结构的成员。结构越大,把指向它的指针传递给函数的效率就越高。

    结论

    结构体传参有两种形式,一个是传结构体,一个是传地址,但是建议选择传地址。因为在栈帧知识中,函数传参,是需要压入栈的,但是如果传结构体对象时,结构体过大,所占空间也就过大,会导致性能下降。

    结构体传参,是不会发生降级,要将参数设置为结构体的地址。


     

    7、结构体变量的初始化

    ps:在对结构体变量初始化时,要对结构体成员一一赋值,不能跳过前面成员变量,而直接给后面成员赋初值,但是可以只赋值前面几个,对与后面未赋值的变量,如果是数值型,则会自动赋值为0,对于字符型,会自动赋初值为NULL,即‘\0’

    #include<stdio.h>
    struct Student
    {
        char cName[28];
        int number;
        char csex;
        float score;
    }stu1;
    
    //这里我们只对cName还有number初始化
    
    int mai()
    {
        struct Student stul={"赵", 12345, };
        printf("Name1:%s\nSex1:%c\nSchool Number1:%d\n分数:%f",stul.cName,stu1.csex,stul.number,stu1.score)
    }
    

    7.1定义时赋值

    struct Student
    { 
    	char name[20];
    	char sex;
    	int number;
    }stu1={"zhaozixuan",'M',12345};
    //或者
    struct Student
    { 
    	char name[20];
    	char sex;
    	int number;
    };
    struct Student stu1={"zhaozixuan",'M',12345};
    
    

    7.2定义结构体之后逐个赋值

    stu1.name="王伟";
    stu1.sex='M';
    stu1.number=12305;
    //也可用strcpy函数进行赋值
    strcpy(stu1.name,"王伟");
    
    

    7.3定义之后任意赋值

    可参考这篇博文:https://blog.csdn.net/qq_36588941/article/details/90736496

     struct Student stu1={
      .name="Wang",
      .number=12345,
      .sex='W', 
     };//可以对任意变量赋值
    

    这样写的好处时不用按照顺序来进行初始化,而且可以对你想要赋值的变量直接进行赋值,而不想赋值的变量可以不用赋值

    需要注意的是如果在定义结构体变量的时候没有初始化,那么后面就不能全部一起初始化了;

     

    8、结构体数组及其初始化

    8.1结构数组初始化

    结构体数组与结构体变量区别只是将结构体变量替换为数组

    struct Student
    { 
    	char name[20];
    	char sex;
    	int number;
    }stu1[5]={
    	 {"zhaozixuan",'M',12345},
    	 {"houxiaohong",'M',12306},
    	 {"qxiaoxin",'W',12546},
    	 {"wangwei",'M',14679},
    	 {"yulongjiao",'W',17857}
    };
    stu1[3].name[3]//表示stu1的第三个结构变量中姓名的第五个字符
    //若初始化时已经是结构体数组全部元素[]中的数可以不写如stu1[]=
    

    这样初始化也是对的:

    struct Student stu1[5]={
    	 {"zhaozixuan",'M',12345},
    	 {"houxiaohong",'M',12306},
    	 {"qxiaoxin",'W',12546},
    	 {"wangwei",'M',14679},
    	 {"yulongjiao",'W',17857}
    };

    注意结构体数组要在定义时就直接初始化,如果先定义再赋初值是错误的

    例如:

    struct Student stu1;
    stu1[3]={
      {"zhaozixuan",'M',12345},
      {"houxiaohong",'M',12306},
      {"qxiaoxin",'W',12546}
      };
      
    

    这样子是错误的!!!!

    8.2数组初始化

    char str[20];
    str="I love you";/* 这样会修改数组的地址,但是数组的地址分配之后是不允许改变的 */
    //数组名是常量,不允许被赋值
    

    8.3四种方法

    1.定义数组时直接定义

    char str[20]=“I love you”;

    2.用strcpy函数进行复制
     

    char str[20];
    strcpy(str,“I love you”);

    3.用memset函数进行复制

    void *memset(void *s,int c,size_t n)

    作用:将已开辟内存空间s的首n个字节的值设为值c。

    char str[20];
    memset(str,'a',20);
    

    如果是字符类型数组的话,memset可以随便用,但是对于其他类型的数组,一般只用来清0或者填-1,如果是填充其他数据就会出错

    int str[10];
    memset(str,1,sizeof(str));//这样是错误的
    
    

    这里我们说下这个错误:

    首先我们要知道memset在进行赋值时,是按字节为单位来进行赋值的,每次填充的数据长度为一个字节,而对于其他类型的变量,比如int,占4个字节 所以sizeof(str)=40; 而用memset赋值时,将会对指向str地址的前40个字节进行赋值0x01(00000001) 的操作,把0x00000000赋值4次0x01操作变为0x01010101(00000001000000010000000100000001)

    相当于给“前10个int”进行了赋值0x01010101的操作 对应十进制的16843009
    所以会出很大的错误 

     

    #include<stdio.h>
    #include<string.h>
    #include<memory.h>
    
    char str[20];
    int i,num[10];
    
    int main()
    {
        memset(str, 'a', 20);
        for(i=0; i<20; i++)
            printf("%c",str[i]);//char类型没有问题
        
        memset(num,5,sizeof(num));
        size_t size = sizeof(num);
        printf("字节长度为:%d\n", size);
        for(i=0; i<20; i++)
            printf("%d",mum[i]);//int类型会出现很大的bug 
        return 0;
    }

    这里请务必要注意,但是如果是清零一个数组用memset还是很方便的
    简单使用的话同学们用strcmp函数就行

    4.使用指针(注意内存分配)

    char *str;
    str=“I love you”;

    这两句话的本质是,在内存中开辟一段内存空间,把"I love you"放进这段内存空间,然后把这段内存空间的地址交给str,由于str是变量,所以给它赋值是合法的。

    int str[10]={1};//这里只是把str的第一个元素赋值为1,其他元素默认为0

    9、结构体与指针

    我们知道,指针指向的是变量所占内存的首地址,在结构体中,指针指向的是结构体变量的起始地址,当然也可指向结构体变量的元素

    9.1指向结构体变量的指针

    定义形式一般为
    struct      结构体名    * 指针名;
    比如: struct    Student    * p;

     

    struct Student
    {	
    	char cName[20];
     	int number;
     	char csex;  
    }student1;
    struct Student*p;
    p=&student1;
    //若为结构体数组则
    struct Student stu1[5];
    struct Student*p;
    p=stu1;//因为stu1为结构体数组而p=stu1直接是指向stu1的首地址,就不用再加&符
    
    

    结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必须在前面加&

     

    用结构体指针变量访问结构体变量成员有以下两种方式:

    (*p).cName //这里的括号不能少
    p->cName

    简单来说以下三种形式是等价的

    p->cName
    (*p).cName 
    student1.cName
    p->cName //可以进行正常的运算
    

    注意:p->number++; 是将结构体变量中number的值进行运算,然后再加一

    9.2向结构体数组的指针

    在我们想要用指针访问结构体数组的第n个数据时可以用

    struct Student stu1[5];
    struct Student*p;
    p=stu[n];
    (++p).number//是指向了结构体数组下一个元素的地址
    
    

    9.3结构体成员是指针类型变量

    struct Student
    {
     	char* Name;//这样防止名字长短不一造成空间的浪费
     	int number;
     	char csex;  
    }student1;
    
    

    在使用时可以很好地防止内存被浪费,但是注意在引用时一定要给指针变量分配地址,如果你不分配地址,结果可能是对的,但是Name会被分配到任意的一的地址,结构体不为字符串分配任何内存存储空间具有不确定性,这样就存在潜在的危险

    struct Student
    {
     	char* Name;
     	int number;
     	char csex;  
    }stu,*stu;
    
    stu.name=(char*)malloc(sizeof(char));//内存初始化
    

    这里我们说一下,同学们看书的时候一般不会看到,
    如果我们定义了结构体指针变量,他没有指向一个结构体,那么这个结构体指针也是要分配内存初始化的,他所对应的指针类型结构体成员也要相应初始化分配内存

    展开全文
  • 成员名”的方式引用结构体变量中的成员,除了这种方法以外还能够使用指针。前面讲过,&student1 表示结构体变量 student1 的首地址,即 student1 第一个项的地址。若是定义一个指针变量 p 指向这个地址的话,p ...

    结构体指针,可细分为指向结构体变量的指针和指向结构体数组的指针。html

    指向结构体变量的指针

    前面咱们经过“结构体变量名.成员名”的方式引用结构体变量中的成员,除了这种方法以外还能够使用指针。

    前面讲过,&student1 表示结构体变量 student1 的首地址,即 student1 第一个项的地址。若是定义一个指针变量 p 指向这个地址的话,p 就能够指向结构体变量 student1 中的任意一个成员。

    那么,这个指针变量定义成什么类型呢?只能定义成结构体类型,且指向什么结构体类型的结构体变量,就要定义成什么样的结构体类型。好比指向 struct STUDENT 类型的结构体变量,那么指针变量就必定要定义成 struct STUDENT* 类型。

    下面将前面的程序用指针的方式修改一下:数组

    # include # include

    structAGE

    {intyear;intmonth;intday;

    };structSTUDENT

    {char name[20]; //姓名

    int num; //学号

    struct AGE birthday; //生日

    float score; //分数

    };int main(void)

    {struct STUDENT student1; /*用struct STUDENT结构体类型定义结构体变量student1*/

    struct STUDENT *p = NULL; /*定义一个指向struct STUDENT结构体类型的指针变量p*/p= &student1; /*p指向结构体变量student1的首地址, 即第一个成员的地址*/strcpy((*p).name, "小明"); //(*p).name等价于student1.name

    (*p).birthday.year = 1989;

    (*p).birthday.month = 3;

    (*p).birthday.day = 29;

    (*p).num = 1207041;

    (*p).score = 100;

    printf("name : %s\n", (*p).name); //(*p).name不能写成p

    printf("birthday : %d-%d-%d\n", (*p).birthday.year, (*p).birthday.month, (*p).birthday.day);

    printf("num : %d\n", (*p).num);

    printf("score : %.1f\n", (*p).score);return 0;

    }

    输出结果是:

    name : 小明

    birthday : 1989-3-29

    num : 1207041

    score : 100.0

    咱们看到,用指针引用结构体变量成员的方式是:spa

    (*指针变量名).成员名.net

    注意,*p 两边的括号不可省略,由于成员运算符“.”的优先级高于指针运算符“*”,因此若是 *p 两边的括号省略的话,那么 *p.num 就等价于 *(p.num) 了。

    从该程序也能够看出:由于指针变量 p 指向的是结构体变量 student1 第一个成员的地址,即字符数组 name 的首地址,因此 p 和 (*p).name 是等价的。

    可是,“等价”仅仅是说它们表示的是同一个内存单元的地址,但它们的类型是不一样的。指针变量 p 是 struct STUDENT* 型的,而 (*p).name 是 char* 型的。因此在 strcpy 中不能将 (*p).name 改为 p。用 %s 进行输入或输出时,输入参数或输出参数也只能写成 (*p).name 而不能写成 p。

    一样,虽然 &student1 和 student1.name 表示的是同一个内存单元的地址,但它们的类型是不一样的。&student1 是 struct STUDENT* 型的,而 student1.name 是 char* 型的,因此在对 p 进行初始化时,“p=&student1;”不能写成“p=student1.name”。由于 p 是 struct STUDENT* 型的,因此不能将 char* 型的 student1.name 赋给 p。

    此外为了使用的方便和直观,用指针引用结构体变量成员的方式:指针

    (*指针变量名).成员名code

    能够直接用:htm

    指针变量名->成员名blog

    来代替,它们是等价的。“->”是“指向结构体成员运算符”,它的优先级同结构体成员运算符“.”同样高。p->num 的含义是:指针变量 p 所指向的结构体变量中的 num 成员。p->num 最终表明的就是 num 这个成员中的内容。

    下面再将程序用“->”修改一下:内存

    # include # include

    structAGE

    {intyear;intmonth;intday;

    };structSTUDENT

    {char name[20]; //姓名

    int num; //学号

    struct AGE birthday; /*用struct AGE结构体类型定义结构体变量birthday, 生日*/

    float score; //分数

    };int main(void)

    {struct STUDENT student1; /*用struct STUDENT结构体类型定义结构体变量student1*/

    struct STUDENT *p = NULL; /*定义struct STUDENT结构体类型的指针变量p*/p= &student1; /*p指向结构体变量student1的首地址, 即第一项的地址*/strcpy(p->name, "小明");

    p->birthday.year = 1989;

    p->birthday.month = 3;

    p->birthday.day = 29;

    p->num = 1207041;

    p->score = 100;

    printf("name : %s\n", p->name); //p->name不能写成p

    printf("birthday : %d-%d-%d\n", p->birthday.year, p->birthday.month, p->birthday.day);

    printf("num : %d\n", p->num);

    printf("score : %.1f\n", p->score);return 0;

    }

    展开全文
  • C语言结构体指针

    2018-10-04 18:30:42
    结构体指针,C语言结构体指针详解 结构体指针,可细分为指向结构体变量的指针和指向结构体数组的指针。 指向结构体变量的指针 前面我们通过“结构体变量名.成员名”的方式引用结构体变量中的成员,除了这种方法之外...
  • C语言结构体变量

    2019-07-08 16:06:41
    结构体变量的定义 ...struct为结构体关键字,student就是这结构体的类型名,而 num,name, score就是该结构体的成员,他们可以是不同类型的,注意在定义类型的时候不要对结构体成员num,name, ...
  • 结构体变量的引用 结构体变量的初始化 结构体数组 结构体和指针 共用体 9.1 结构体 结构体是一种构造数据类型 用途把不同类型的数据组合成一个整体-------自定义数据类型 结构体类型定义 struct [结构体名] { 类型...
  • C语言结构体概述

    2020-03-17 12:23:59
    在编码的过程中有时需要将不同类型的数据组合成一个有机的整体,以便于引用,类似于Java的面向对象。 定义一个结构的一般形式: struct 结构名{ 成员列表 }; 例如:定义一个学生的结构体(包括学号、姓名、性别、...
  • c语言结构体链表

    2015-05-11 12:42:00
    引用自身的结构体,一个结构体中有一个或多个成员的基类型就是本结构体类型时,说明这个结构体可以引用自己,所以称作引用自身的结构体。 例如下面的结构体: struct link{ char ch; struct link *p} a; ...
  • C语言结构体和共用体_07 概述 定义结构体类型变量的方法 结构体变量的引用 结构体变量的初始化 结构体数组 指向结构体类型数据的指针 用指针处理链表 共用体 枚举类型 用 typedef定义...
  • 成员名”的方式引用结构体变量中的成员,除了这种方法之外还可以使用指针。 前面讲过,&student1 表示结构体变量 student1 的首地址,即 student1 第一个项的地址。如果定义一个指针变量 p 指向这个地址的话,p ...
  • 位域不同于一般的结构体成员,它以位为单位来定义成员的长度,因此在结构体中定义位域时,必须要指明位域成员所需要占用的二进制位数。一个简单的定义位域的示例如下: struct Foo { int a: 5; // 数据
  • C语言结构体指针详解

    2019-09-26 15:23:05
    成员名”的方式引用结构体变量中的成员,除了这种方法之外还可以使用指针。前面讲过,&student1 表示结构体变量 student1 的首地址,即 student1 第一个项的地址。如果定义一个指针变量 p 指向这个地址的话,p ...
  • c语言结构体对齐

    千次阅读 2010-10-10 15:09:00
    C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一不小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这...
  • 有以下声明和定义: <p>struct Student { char num[10]; int age; }; <p>struct Student stu...引用结构体变量成员的表达式错误的是 。 A. (p++)->num B. p->num C. (*p).num D. stu[3].age</p>
  • 结构体 是由一批数据组合而成的一种新的数据类型。组成结构型数据的每个数据称为结构型数据的“成员”。 结构体的声明 struct tag{ member-list; }variavle-list; //例如学生结构体 ...结构体的自引用必须使用指针
  • 关于结构体成员引用有这样的规律: 箭头(->):左边必须为指针; 点号(.):左边必须为实体。 那么如果一个结构体指针引用一个成员,这个成员又是一个结构体(并且是一个实体),那么如果要引用这个成员的...
  • 是结构体变量引用结构体成员名的方法,而符号->是结构体指针变量引用结构体成员名的方法,使用->可以方便(*指针变量).结构体成员名的写法 例: #include <stdio.h> int main(){ typedef struct ...
  • stru.i = 100;

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 343
精华内容 137
关键字:

c语言结构体成员引用

c语言 订阅