• C和指针 第10章 结构和联合 10.10 问题


    1. 成员和数组元素有什么区别? 
    解析:
    结构中的成员不一定是同一种类型,而数组中的元素都为同一种类型。
    成员是通过成员名进行访问,数组元素是通过下标进行访问。 

    2. 结构名和数组名有什么不同? 
    解析: 
    结构名是一个标量。与其他任何变量一样,当结构名在表达式中作为右值使用时,它表示存储在结构中的值;作为左值使用时,它表示结构存储的内存位置。但是,当数组名在表达式中作为右值使用时,它的值是一个指向数组第1个元素的指针。由于它的值是一个指针常量,因为数组名不能作为左值使用。  

    3. 结构声明的语法有几个可选部分。请列出所有合法的结构声明形式,并解释每一个是如何实现的。 
    /*
    ** method: a label of struct, but no variable of struct.
    */
    struct struct_a{
        int a;
    };

    /*
    ** method2: a label of struct, a variable of struct.
    */
    struct struct_b{
        int a;    
    } b;

    /*
    ** method3: no label of struct, a variable of struct.
    */
    struct {
        int a;
    } c;

    /*
    ** method4: no label of struct, no variable of struct, but a typedef, struct_d the type of struct.
    */
    typedef struct {
        int a;
    } struct_d;
    4. 下面的程序有没有错误?如果有,错误在哪里?
    struct abc {
        int a;
        int b;
        int c;
    }; 
    ...
    abc.a = 25;
    abc.b = 15;
    abc.c = -1;
    解析:
    有错误。abc是一个结构标签,而不是结构变量。只有结构变量才会被分配内存,结构标签不会分配内存。因此是错误的。 
    #include <stdio.h>
    #include <stdlib.h>

    struct abc {
        int a;
        int b;
        int c;
    }; 

    int main( void ){
        struct abc var;
        /*
        ** can't pass compilation. 
        ** abc.a = 25;
        ** abc.b = 15;
        ** abc.c = -1;
        */
        var.a = 25;
        var.b = 15;
        var.c = -1;
        printf( "var.a = %d, var.b = %d, var.c = %d\n", var.a, var.b, var.c );

        return EXIT_SUCCESS;
    }
    /* 输出:

    */
    5. 下面的程序有没有错误?如果有,错误在哪里?
    typedef struct{
        int a;
        int b;
        int c; 
    } abc;
    ...
    abc.a = 25;
    abc.b = 15;
    abc.c = -1; 
    解析:
    有错误。abc是一个结构类型,而不是结构变量。只有结构变量才会被分配内存,结构类型不会被分配内存。因此是错误的。 
    #include <stdio.h>
    #include <stdlib.h>

    typedef struct{
        int a;
        int b;
        int c; 
    } abc;

    int main( void ){ 
        abc var;
        /*
        ** can't pass compilation. 
        ** abc.a = 25;
        ** abc.b = 15;
        ** abc.c = -1;
        */
        var.a = 25;
        var.b = 15;
        var.c = -1;
        printf( "var.a = %d, var.b = %d, var.c = %d\n", var.a, var.b, var.c );

        return EXIT_SUCCESS;
    }
    /* 输出:

    */ 
    6. 完成下面声明中对x的初始化,使成员a为3,b为字符串"hello",c为0。可以假设x存储在静态内存中。
    struct {
        int a;
        char b[10];
        float c; 
    } x = ; 
    #include <stdio.h>
    #include <stdlib.h>

    struct {
        int a;
        char b[10];
        float c; 
    } x = { 3, "hello", 0 };

    int main( void ){
        printf( "x.a = %d, x.b = %s, x.c = %f\n", x.a, x.b, x.c ); 

        return EXIT_SUCCESS;
    }
    /* 输出:

    */
    7. 考虑下面这些声明和数据。
    struct NODE{
        int a;
        struct NODE *b;
        struct NODE *c;
    }; 
    struct NODE nodes[5] = {
        {
            5, nodes + 3, NULL
        },
        {
            15, nodes + 4, node3 + 3
        },
        {
            22, NULL, nodes + 4
        },
        {
            12, nodes + 1, nodes
        },
        {
            18, nodes + 2, nodes + 1
        }
    };
    /* (Others declarations...) */
    struct NODE *np = nodes + 2;
    struct NODE **npp = &nodes[1].b;
    对下面的表达式求值,并写出它的值。同时,写明任何表达式求值过程中可能出现的副作用,应该用最初显示的值对每个表达式求值(也就是说,不要使用某个表达式的结果来对下一个表达式求值)。假定nodes数组在内存中的起始位置为200,并且在这台机器上整数和指针的长度都是4字节。 
    表达式                值                        表达式                      值
    nodes                200                    &nodes[3].c->a           200
    nodes.a             非法                   &nodes->a                  200    
    nodes[3].a         12                       np                               224
    nodes[3].c          200                    np->a                          22
    nodes[3].c->a     5                        np->c->c->a               15
    *nodes               {5, nodes + 3, NULL}    npp                  216
    *nodes.a            非法                    npp->a                       非法 
    (*nodes).a          5                         *npp                           248
    nodes->a            5                         **npp                         {18, nodes+2, nodes+1} 
    nodes[3].b->b     248                     *npp->a                     非法 
    *nodes[3].b->b    {18, nodes+2, nodes+1}(*npp)->a     18
    &nodes               200                      &np                           未知 
    &nodes[3].a        236                      &np->a                      224
    &nodes[3].c        244                      &np->c->c->a            212
    /*
    ** In my computer, the size of pointer is 8 bytes, the size of int is 4 bytes.
    ** You can identify the correctness of question by using analogy.
    */
    #include <stdio.h>
    #include <stdlib.h>

    struct NODE{
        int a;
        struct NODE *b;
        struct NODE *c;
    }; 
    struct NODE nodes[5] = {
        {
            5, nodes + 3, NULL
        },
        {
            15, nodes + 4, nodes + 3
        },
        {
            22, NULL, nodes + 4
        },
        {
            12, nodes + 1, nodes
        },
        {
            18, nodes + 2, nodes + 1
        }
    };

    int main( void ){
        int i;
        for( int i = 0; i < 5; ++i ){
            printf( "nodes[%d].a = %d, nodes[%d].b = %p, nodes[%d].c = %p\n", 
            i, nodes[i].a, i, nodes[i].b, i, nodes[i].c );
            printf( "&nodes[%d] = %p, &nodes[%d].a = %p, &nodes[%d].b = %p, &nodes[%d].c = %p\n", 
            i, &nodes[i], i, &nodes[i].a, i, &nodes[i].b, i, &nodes[i].c ); 
        }
        struct NODE *np = nodes + 2;
        struct NODE **npp = &nodes[1].b;
        printf( "sizeof(int) = %zd, sizeof(int *) = %zd\n", sizeof(int), sizeof(int *) );
        printf( "sizeof(struct NODE) = %zd, sizeof(struct NODE *) = %zd\n", sizeof(struct NODE), sizeof(struct NODE *) );
        int pointer_size = sizeof(int *);
        printf( "nodes = %p\n", nodes );
        /*
        ** can't pass compilation.
        ** because nodes is a pointer.
        ** nodes.a
        */
        printf( "nodes[3].a = %d\n", nodes[3].a );
        printf( "nodes[3].c = %p\n", nodes[3].c );
        printf( "nodes[3].c->a = %d\n", nodes[3].c->a );
        printf( "(*nodes).a = %d, (*nodes).b = %p, (*nodes).c = %p\n", (*nodes).a, (*nodes).b, (*nodes).c );
        /*
        ** can't pass compilation.
        ** because nodes is a pointer, the priority of . operator is higher than * operator.
        ** *nodes.a;
        */
        printf( "(*nodes).a = %d\n", (*nodes).a );
        printf( "nodes->a = %d\n", nodes->a );
        printf( "nodes[3].b->b = %p\n", nodes[3].b->b );
        printf( "&nodes = %p\n", &nodes );
        printf( "&nodes[3].a = %d\n", &nodes[3].a );
        printf( "&nodes[3].c = %p\n", &nodes[3].c );
        printf( "&nodes[3].c->a = %d\n", &nodes[3].c->a );
        printf( "&nodes->a = %d\n", &nodes->a );
        printf( "np = %p\n", np );
        printf( "np->a = %d\n", np->a );
        printf( "np->c->c->a = %d\n", np->c->c->a );
        printf( "npp = %p\n", npp );
        /*
        ** can't pass compilation.
        ** because npp is a pointer points to a pointer points to variable of struct NODE.
        ** *npp = nodes[1].b is a pointer points to variable of struct Node, but this pointer
        ** don't have the member of a, so it is illegal.
        ** npp->a;
        */
        printf( "*npp = %p\n", *npp );
        printf( "(**npp).a = %d, (**npp).b = %p, (**npp).c = %p\n", (**npp).a, (**npp).b, (**npp).c );
        /*
        ** can't pass compilation.
        ** because npp is a pointer points to a pointer points to variable of struct NODE.
        ** *npp = nodes[1].b is a pointer points to variable of struct Node, but this pointer
        ** don't have the member of a, so it is illegal.
        ** the priority of -> operator is higher than * operator.
        ** *npp->a;
        */
        printf( "(*npp)->a = %d\n", (*npp)->a );
        printf( "&np = %p\n", &np );
        printf( "&np->a = %p\n", &np->a );
        printf( "&np->c->c->a = %p\n", &np->c->c->a );
        
        return EXIT_SUCCESS;
    }

    /* 输出:

    nodes[0].a = 5, nodes[0].b = 0000000000404088, nodes[0].c = 0000000000000000
    &nodes[0] = 0000000000404040, &nodes[0].a = 0000000000404040, &nodes[0].b = 0000000000404048, &nodes[0].c = 0000000000404050
    nodes[1].a = 15, nodes[1].b = 00000000004040A0, nodes[1].c = 0000000000404088
    &nodes[1] = 0000000000404058, &nodes[1].a = 0000000000404058, &nodes[1].b = 0000000000404060, &nodes[1].c = 0000000000404068
    nodes[2].a = 22, nodes[2].b = 0000000000000000, nodes[2].c = 00000000004040A0
    &nodes[2] = 0000000000404070, &nodes[2].a = 0000000000404070, &nodes[2].b = 0000000000404078, &nodes[2].c = 0000000000404080
    nodes[3].a = 12, nodes[3].b = 0000000000404058, nodes[3].c = 0000000000404040
    &nodes[3] = 0000000000404088, &nodes[3].a = 0000000000404088, &nodes[3].b = 0000000000404090, &nodes[3].c = 0000000000404098
    nodes[4].a = 18, nodes[4].b = 0000000000404070, nodes[4].c = 0000000000404058
    &nodes[4] = 00000000004040A0, &nodes[4].a = 00000000004040A0, &nodes[4].b = 00000000004040A8, &nodes[4].c = 00000000004040B0
    sizeof(int) = 4, sizeof(int *) = 8
    sizeof(struct NODE) = 24, sizeof(struct NODE *) = 8
    nodes = 0000000000404040
    nodes[3].a = 12
    nodes[3].c = 0000000000404040
    nodes[3].c->a = 5
    (*nodes).a = 5, (*nodes).b = 0000000000404088, (*nodes).c = 0000000000000000
    (*nodes).a = 5
    nodes->a = 5
    nodes[3].b->b = 00000000004040A0
    &nodes = 0000000000404040
    &nodes[3].a = 4210824
    &nodes[3].c = 0000000000404098
    &nodes[3].c->a = 4210752
    &nodes->a = 4210752
    np = 0000000000404070
    np->a = 22
    np->c->c->a = 15
    npp = 0000000000404060
    *npp = 00000000004040A0
    (**npp).a = 18, (**npp).b = 0000000000404070, (**npp).c = 0000000000404058
    (*npp)->a = 18
    &np = 000000000062FE00
    &np->a = 0000000000404070
    &np->c->c->a = 0000000000404058

    --------------------------------
    Process exited after 0.09453 seconds with return value 0
    请按任意键继续. . .

    */

    8. 在一台16位的机器上,下面这个结构由于边界对齐浪费了多少空间?在一台32位的机器上又是如何?
    struct {
        char a;
        int b;
        char c;
    }; 
    /*
    ** In my computer, int has the memory of 4 bytes.
    */
    #include <stdio.h>
    #include <stdlib.h>

    int main( void ){
        struct{
            char a;
            int b;
            char c;
        } var, var2;
        int struct_size;
        int char_size;
        int int_size;
        
        struct_size = sizeof(var);
        char_size = sizeof(char);
        int_size = sizeof(int);
        printf( "sizeof(var) = %zd, sizeof(char) = %zd, sizeof(int) = %zd\n", struct_size, char_size, int_size );
        printf( "wasteful time is %d bytes\n", struct_size - char_size * 2 - int_size );

        return EXIT_SUCCESS;
    }
    /* 输出:

    */

    9. 至少说出位段不可移植的两个理由。
    解析:
    1.int位段被当做有符号数还是无符号数。
    2.位段中位的最大数目。许多编译器把位段成员的长度限制在一个整型值的长度之内,所以一个能够运行于32位整数的机器上的位段声明可能在16位整数的机器上无法运行。
    3.位段中的成员在内存中是从左往右分配的还是从右往左分配的。
    4.当一个声明指定了两个位段,且第2个位段比较大,无法容纳于第1个位段剩余的位时,编译器有可能把第2个位段放在内存的下一个字,也可能直接放在第1个位段后面,从而在两个内存位置的边界上形成重叠。 
    10. 编写一个声明,允许根据下面的格式方便地访问一个浮点值的单独部分。 
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>

    struct FLOAT{
        signed int symbol: 1;
        signed int exponent: 7;
        signed int fraction: 24;
    };

    int main( void ){
        struct FLOAT var;
        int counter;
        int temp;
        
        var.symbol = 1;
        var.exponent = 2;
        var.fraction = 24;
        counter = 1;
        temp = var.fraction;
        while( temp / 10 != 0 ){
            counter++;
            temp /= 10;
        }
        printf( "var.symbol = %d, var_exponent = %d, var.fraction = %f, var = %f\n", 
        var.symbol, var.exponent, var.fraction / pow( 10, counter ), 
        var.fraction / pow( 10, counter ) * var.symbol * pow( 10, var.exponent ) );

        return EXIT_SUCCESS;
    }
    /* 输出:

    */

    11. 如果不使用位段,怎样实现下面这段代码的功能?假定使用的是一台16位的机器,它从左向右为位段分配内存。
    struct {
        int a: 4;
        int b: 8;
        int c: 3;
        int d: 1;
    } x;
    ...
    x.a = aaa;
    x.b = bbb;
    x.c = ccc;
    x.d = ddd; 
    解析:
    x应该被声明为整型(或无符号整型),然后使用移位和屏蔽存储适当的值。单独翻译每条语句,生成了下面的代码:
    x &= 0x0fff; 
    x |= (aaa & 0xf) << 12;
    x &= 0xf00f;
    x |= (bbb & 0xff) << 4;
    x &= 0xfff1;
    x |= (ccc & 0x7) << 1;
    x &= 0xfffe;
    x |= ( ddd & 0x1 );

    如果只关心最终结果,下面的代码效率更高: 
    x = (aaa & 0xf) << 12 | \
        (bbb & 0xff) << 4 | \
        (ccc & 0x7) << 1  | \
        (ddd & 0x1);
    下面是另外一种方法:
    /* note that the value of value continue to change, so it can appear x << 3 statement. */ 
    x = aaa & 0xf;
    x <<= 8;
    x |= bbb & 0xff;
    x <<= 3;
    x |= ccc & 0x7;
    x <<= 1;
    x |= ddd & 1; 
    /*
    12. 下面这个代码段将打印出什么? 
    struct {
        int a: 2;
    } x;
    ...
    x.a = 1;
    x.a += 1;
    printf( "%d\n", x.a ); 
    */ 
    #include <stdio.h>
    #include <stdlib.h>
    struct {
        int a: 2;
    } x;
    struct {
        unsigned a: 2;
    } y; 
    /*... */
    int main( void ){
        x.a = 1;
        printf( "after x.a = 1, x.a = %d\n", x.a );
        x.a += 1;
        printf( "after x.a += 1, x.a = %d\n", x.a ); 
        x.a = -1;
        printf( "after x.a = -1, x.a = %d\n", x.a );
        x.a += 1;
        printf( "after x.a += 1, x.a = %d\n", x.a ); 
        x.a = 3; 
        printf( "after x.a = 3, x.a = %d\n", x.a );
        
        y.a = 1;
        printf( "after y.a = 1, y.a = %d\n", y.a );
        y.a += 1;
        printf( "after y.a += 1, y.a = %d\n", y.a ); 
        y.a = 3;
        printf( "after y.a = 3, y.a = %d\n", y.a );
        y.a += 1;
        printf( "after y.a += 1, y.a = %d\n", y.a ); 
        
        return EXIT_SUCCESS;
    }
    /* 输出:

      */ 
    13. 下面的代码段有没有错误?如果有,错误在哪里?
    union{
        int a;
        float b;
        char c;
    } x;
    ...
    x.a = 25;
    x.b = 3.14;
    x.c = 'x';
    printf( "%d %g %c\n", x.a, x.b, x.c ); 
    解析:
    有错误。因为联合里面的变量共用一个存储空间。之后赋值的成员会覆盖之前成员变量的值。 
    #include <stdio.h>
    #include <stdlib.h>

    union{
        int a;
        float b;
        char c;
    } x;

    int main( void ){
        /*...*/
        x.a = 25;
        printf( "x.a = %d\n", x.a );
        x.b = 3.14;
        printf( "x.b = %f\n", x.b );
        x.c = 'x';
        printf( "x.c = %c\n", x.c );
        printf( "%d %g %c\n", x.a, x.b, x.c );

        return EXIT_SUCCESS;
    }
    /* 输出:

    */

    14. 假定有一些信息已经赋值给一个联合变量,该如何正确地提取这个信息呢?
    解析:
    即在联合中的另一个成员变量赋值之前使用这个值,就能正确地提取这个信息。 参考13题。 
    15. 下面的结构可以被一个BASIC解释器使用,用于记住变量的类型和值。
    struct VARIABLE{
        enum { INT, FLOAT, STRING } type;
        union{
            int i;
            float f;
            char *s;
        } value;
    }; 
    如果结构改写成下面这种形式,会有什么不同呢?
    struct VARIABLE{
        enum { INT, FLOAT, STRING } type;
        union{
            int i;
            float f;
            char s[MAX_STRING_LENGTH];
        } value;
    }; 
    解析:
    类型的大小将与MAX_STRING_LENGTH有关。这里需要注意边界对齐影响类型大小的问题。 
    #include <stdio.h>
    #include <stdlib.h>

    #define MAX_STRING_LENGTH 20

    struct VARIABLE{
        enum { INT, FLOAT, STRING } type;
        union{
            int i;
            float f;
            char *s;
        } value;
    }; 

    struct VARIABLE2{
        enum { INT, FLOAT, STRING } type;
        union{
            int i;
            float f;
            char s[MAX_STRING_LENGTH];
        } value;
    }; 

    int main( void ){
        struct VARIABLE var;
        struct VARIABLE2 var2;
        int var_size, var_size_2;
        
        var_size = sizeof(var);
        var_size_2 = sizeof(var2);
        printf( "var_size = %zd, var_size_2 = %zd\n", var_size, var_size_2 ); 

        return EXIT_SUCCESS;
    }
    /* 输出:

     */

  • 相关阅读:
    【二叉树进阶】红黑树(Red Black Tree) - 平衡二叉搜索树
    前任开发在代码里下毒了,支付下单居然没加幂等
    JVM内部结构图及各模块运行机制总结
    B. DIV + MOD
    线下门店为什么要做新零售?
    怎样判断一个数为素数
    E2. Unforgivable Curse (hard version)
    [OC学习笔记]KVC原理
    clion配置cygwin必按包
    中国多媒体与网络教学学报杂志中国多媒体与网络教学学报杂志社中国多媒体与网络教学学报编辑部2022年第6期目录
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/125455047