C语言学习笔记8——构造类型

1.结构体

1)结构体类型描述不占内存空间(struct xx{ };整个部分都是类型描述或者叫变量类型),所以不能在定义结构体时给结构体成员变量赋值。类似int i;中是i而非int占内存空间

2)结构体定义的最后勿忘写分号“;”

3)结构体定义放在函数外,防止有些校验严格的编译器不认识这种定义方式

4)结构体变量名也仅仅是结构体的起始位置地址,不能通过变量名引用到结构体的所有成员,这个和数组一样,不能通过数组名得到所有元素,只能通过遍历方式实现。

而字符串指针和字符串赋值的字符数组可以通过指针变量或者数组名+%s得到完整字符串,可能是因为通过输出格式%s实现。

但字符赋值的字符数组无法用%s+数组名的方式完整输出。

        char* strp = "hello";
        char strA[] = "hey";
        char strB[2] = {'h', 'i'};

        printf("strp = %s\n", strp);
        for(i=0; i<5; ++i)
                printf("strA[%d] = %c, %d\n",i,strA[i], strA[i]);

        printf("strA = %s\n", strA);
        for(i=0; i<5; ++i)
                printf("strB[%d] = %c, %d\n",i,strB[i], strB[i]);

        printf("strB = %s\n", strB);

运行结果:

strp = hello
strA[0] = h, 104
strA[1] = e, 101
strA[2] = y, 121
strA[3] = , 0
strA[4] = ▒, -1
strA = hey
strB[0] = h, 104
strB[1] = i, 105
strB[2] = @, 64
strB[3] = , 0
strB[4] = , 0
strB = hi@

5)对结构体部分初始化:struct student_st stu = {.math=98, .Chinese=99};

6) 对结构体成员变量的引用,-> 等价于 *( ).;

只区分结构体变量是一般变量还是指针变量,结构体是一般变量的不管成员是一般变量成员还是指针变量成员都用“.”来引用,结构体是指针变量的不管成员是一般变量成员还是指针变量成员都用

“->”来引用:

struct student
{
        int id;
        char* name;
        int score;
};

struct student std = {.name="xiaoxiao"};
struct student *pstd = &std;
printf("%d, %s, %d\n", std.id, std.name, std.score);
printf("%d, %s, %d\n", pstd->id, pstd->name, pstd->score);

7)结构体数组赋给相应指针,指针每+1或者++是移动到不同的结构体上。

8)嵌套结构体的引用是连续的“.”或者连续的“->”

9)结构体内存对齐公式:当前地址号%sizeof(数据类型大小),如果能被整除则放在当前地址起始+sizeof(数据类型大小)这块内存,否则当前地址号+1,直到能被整除。实际就是之前总结的三条规律的第一条:当前成员变量起始地址是其数据类型大小的整数倍。

网络协议编程不需要字节对齐:结构体描述“__attribute__((packet));”

*注意类型描述结尾没有分号,后直接跟 “__attribute__((packet))”

10)结构体传参:

值传参,直接传结构体变量相当于把结构体中每个成员变量都传过去,开销会很大,所以结构体传参传指针

//值传参
struct simp_st a;
struct simp_st *p = &a;

func(a) --> func(a.i, a.ch, a.f);

func(p) --> func(&a); 

11)无名结构体在描述时就要定义对应的变量,否则无法使用

struct { }a, *p;

2.共用体:共用体和结构体的描述、定义、引用成员方式、传参方式方式都相同

1)共用体和结构体嵌套的情况:

struct
{
    int i;
    char ch;
    union
    {
        int a[10];
        float f;
    }uni_a;        //无头联合体,必须要有变量;结构体亦然
}stru_a;

2)结构体和共用体嵌套的应用

计算32位无符号数高低16位的和

union
{
        struct
        {
                uint16_t i;
                uint16_t j;
        }x;
        uint32_t y;
}uni_a;

        uni_a.y = 0x11223344;
        printf("%x\n", uni_a.x.i + uni_a.x.j);

运行结果:4466

3)位域面试相关

 由于输入的是%d带符号的整数,所以当考虑位域的值时也要考虑正负号的问题,当本变量在位域中的全部bit是0开头的就是正数,那么该部分换算为十进制值就行;如果变量在位域中的全部bit是1开头的,说明是个负数,由于负数的存储方式是绝对值取反加一,那么逆向计算就是减一后取反得到的就是负数的绝对值,再取负值即可。

union
{
        struct
        {
                char a:1;
                char b:2;
                char c:1;
        }x;
        char y;
}w;

int main()
{
        while(1)
        {
        printf("enter w.y value, enter q to quit\n");
        if(1 != scanf("%d", &w.y))
                break;
        printf("w.x.a=%d\n", w.x.a);
        printf("w.x.b=%d\n", w.x.b);
        printf("w.x.c=%d\n", w.x.c);
        }
        exit(0);
}

结果:
当输入为1,w.x.a = -1;//1~00000001,a是bit:0,求w.x.a,
//那么计算机只看这一位和整个八位
//没关系,安装数据存储规则有符号数且最高位为1为负数,
//将其减一取反的值取负号,得负一。

当输入为5,对应bit7:0=00000111。w.x.a是bit:7,结果同上。
w.x.b是bit:1-2也就是11,这两位是b的全部,虽然只有两位
也是遵守计算机数据存储规则,最高位为1说明是负数,
减一取反再取负值即是b的值为-1

*note:数据在计算机中都是以补码存储的,不管占了几个bit位,如果是有符号数,第一位都是符号位,0正1负,按照补码的运算的逆运算反推对应十进制数字

3.枚举:

1)枚举和结构体、共用体/联合体的类型描述不一样:

枚举成员之间用逗号“,”隔开,共用体结构体成员之间用分号隔开“;”;enum类型描述时可以直接赋值,共用体/结构体不能在类型描述时赋值。

2)经常被当作宏集合使用,里面自动赋值比较方便,而且不同成员值可以一样

enum
{
        SPRING = 1,
        SUMMER = 0,
        FALL,
        WINTER
}en_a;

int main()
{
        en_a = FALL;
        printf("%d\n", en_a);
        exit(0);
}

4.结构体中的自引用指针的数据类型别忘记struct

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值