2017/12/28C语言笔记整理

结构体内成员对齐规则:1.结构体变量本身就是四字节对齐的位置。2.第一个成员,就从结构体开始的地址处,存放这个元素,具体占多少字节,由紧挨着的下个元素决定。3.整个成员变量自身都对齐了,还没有结束。4.整个结构体还要是默认对齐的最小整数倍。//结构体默认的字节对齐:成员变量最大的那个类型所占字节。

#include <stdio.h>

struct data

{

    int a;  //4

    char b; //1+1

    short c;//2

};  //8

typedef struct data1

{

    int a;  //4+4

    double b;   //8

}d; //16

struct

{

    char ch;

}c; //1

struct

{

    char ch[2];

}array; //2

//结构体成员变量的问题

struct data

{

    int a;

    struct data*p; //64位机器指针永远占8字节

}S

struct data1

{

    int a;

    struct data1s; //此时结构体定义不完整

}s;

int main(void)

{

    unsignedshort a=0x1234;

    unsigned char*p1=(unsigned char *)&a;

    int i=8;

    //*p1<<i,就产生了临时变量,内存中不知道地址,但是有一个默认类型(int

  printf(“0x%x.\n”,*p1<<i);    //0x3400

  printf(“0x%x.\n”,*(p1+1));//0x12

}

对齐指令:#pragma packn)(n=12,3,4···

     #pragma pack()

1、两个配合使用表示一个区间,只有这个区间内的结构体享受这个待遇

2、设置对齐

3、设置为一就是不对齐

作用:1、充分利用内存空间,牺牲了速度,降低了访问效率

     2、提高效率、性能,牺牲了内存空间。

#pragma pack1

{

    int a;  //4

    char b; //1

    double c;   //8

}s;(1)->13 (2)->14 (16)->16

总结:指定的对齐方式和结构体自身默认对齐方式,两者取最小

##############################################################################################

1.检查系统错误的宏.一旦发生了,系统错误就会产生一个错误数字(errno),对应相应的错误字符串。

2.标准定义了两个值   EXIT_SUCCESS      EXIT_FAILURE,可以作为exit()的参数,来分别指示是否为成功退出。exit(参数)传递给的是父进程,或者shell终端

#define handle_error(msg)  do{perror(msg); exit(EXIT_FAILURE);}while(0)

#define PRIN (printf("1.\n");printf("2.\n");)

void func(int a)

{

        printf("a= %d.\n", a);

}

#define FUNC printf("所在文件%s所在行数%d.\n", __FILE__,__LINE__)

int main(void)

{

        //文件描述符,没有负数

        int fd =-1;

       

        int ret =close(fd);

       

        if (-1 ==ret)

        {

                handle_error("fileerror!");

        }

 

        int *p =NULL;

       

        if (NULL== p)

        {

                handle_error("mallocerror!");

        }

        int flag= 1;

        if (flag)

        handle_error("action!");   //printf("1.\n"); printf("2.\n");

        else

        {

            printf("noaction.\n");

        }

       

        printf("hello");

        //typeof()关键字,专门用于获得类型,()里可以放变量名,或者表达式

       

        FUNC;

 

        func(NUM);

        int a =3;

        intarr[a] = {};

        intarr_sizeof[sizeof(a)] = {};

        printf("sizeof(s)= %d.\n", sizeof(s));  // 1字节对齐13

        printf("sizeof(s)= %d.\n", sizeof(s));  // 2字节对齐14

        printf("sizeof(s1)= %d.\n", sizeof(s1));  // 2字节对齐14

        return 0;

}

linux内核里的两个宏:在驱动应用中很广泛。

//off_set_of(type, member)计算结构体内元素的偏移量

//containe_of(ptr, type, member),ptr是结构体里成员的指针,通过调用这个宏计算出结构体的首地址.包含两句代码(表达式),必须要加{}.这两个宏:内核双链表。

#define off_set_of(type, member)  ((long)&(((type *)0)->member))

//分析:1、(type *0指向结构体零地址2(type *0)->member得到了结构体某个成元变量名3、给这成员变量名,取地址(相对于零地址),此时&(((type *)0)->member)表示是指针类型4、强制类型转换成(long)

#include <stdio.h>

#define off_set_of(type,member) ((long)&(((type*)0)->member))

#define get_of(ptr,type,member) \

({typeof(((type *)0)->member) *_mptr=ptr;\

(type *)((char *)_mptr-off_set_of(type,member));})

分析:1、得到结构体成员变量的类型 2、指针赋值(得到真实成员变量的地址值)3、减去偏移量得到一个数字,该数字和结构体本身首地址在数值上一样4、最后强制类型转换为结构体指针类型

struct data

{

    char a;//1+1

    short b;//2

    int c;//4

    float d;//4+4

    double e;//8

}s={1,2,3,3.14,1.14};

int main(void)

{

    intoff=off_set_of(struct data,e);

    printf("off=%d.\n",off);

    printf("&s=%p\n",&s);

    struct data*p=get_of(&s.a,struct data,a);

    printf("&s=%p\n",p);

    return 0;

}

//typeof()//参数可以是变量名或表达式

例如:

1.  typeof(int)p;

    p=1;

2.

    int *p,a;

    typeof(p)p_a=&a;

struct da

{

    int a;

    short b;

};  //8

struct data

{

    char a; //1+1

    short b;    //2

    int c;      //4

    struct da s;    //8

}s={1,3,10,3.14,1.14};

int main(void)

{

    struct da*p=container_of(&s.s.b,struct da,b);

}

总结;

1.不会因为有结构体成员而影响你的基本类型决定基本类型

2.里面的结构体对齐方式,已经在结构体外面决定了(遍历完整个结构体)

#include <stdio.h>

位字段:专用于结构体,结构体成员的类型必须是:int || unsigned int

有时侯,结构体成员表示的数据很小,就用几个位来表示。

struct data

{

        unsigneda : 1;  // 1就是一个bit,范围:01

        unsignedb : 2;  // 2就是erbit,范围:03

        unsignedc : 28; // 28

}s, *p = &s;

//word 32位 就是一个int

struct data1

{

        unsigneda : 1;    //1就是一个bit,范围:01

        int : 31;                  // 无名字段,不可访问,只是占位

        unsignedb : 2;    //2就是erbit,范围:03

        unsignedc : 2;   // 28

}s1;

struct data2

{

        unsigneda : 1;    //1就是一个bit,范围:01

        int : 0;                   // 0字段,不可访问,只是占位  整个字剩下的位,全部写0

        unsignedb : 30;   // 2就是erbit,范围:03

        int : 0;

        unsignedc : 2;   // 28

}s2;

//位字段:下一个字段不够在剩余的bit存放时,必须另起一个字。字段不能跨字。

struct data3

{

        int a :2;

        int b :32;

}s3;

int main(void)

{

        s3.a = 2;

       

        printf("s3.a= %d.\n", s3.a);

 

        printf("szieof(s3)= %d.\n", sizeof(s3));

/*

        printf("szieof(s)= %d.\n", sizeof(s));

        // 超出字段表示的数据范围,结果不可预期

        s.b = 2;

        printf("s.b= %u.\n", s.b);

//      printf("s.a = %u.\n", s.a = 3);

        // 字段不可取地址

//      unsigned*p_b = &s.b;

*/

        return 0;

}

#include <stdio.h>

#include <features.h>

#include <stdint.h>

#include <sys/socket.h>

#include <bits/types.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#if 0 // 网络结构体

/* Internet address. */

typedef uint32_t in_addr_t;

typedef uint16_t in_port_t;    // 16的无符号short类型

struct in_addr

  {

    in_addr_ts_addr;

  };

 

/* Structure describing an Internet socketaddress.  */

struct sockaddr_in

  {

   __SOCKADDR_COMMON (sin_);              /*AF_INET IPv4 Internet protocols  指定网络地址类型*/

    in_port_tsin_port;                        /* Portnumber. 端口号 16位无符号short */

    structin_addr sin_addr;           /* Internet address.  具体的网址32位无符号int*/

 

    /* Pad tosize of `struct sockaddr'.  */

    unsignedchar sin_zero[sizeof (struct sockaddr) -

               __SOCKADDR_COMMON_SIZE -

               sizeof (in_port_t) -

               sizeof (struct in_addr)];

  };

#endif

/*

        网络结构体:主流还是ipv4

*/

#define PORT 0x1234

#define ADDR "19.16.1.22"

//把本地ip地址转换成网络字节序地址

//in_addr_t inet_addr(const char *cp);

//输出型参数干的事儿

void set_net_struct(struct sockaddr_in *p)

{

        p->sin_family= AF_INET;

        p->sin_port= htons(PORT);

        p->sin_addr.s_addr= inet_addr(ADDR);

}

 

int main(void)

{

        structsockaddr_in s;

        //赋值

        set_net_struct(&s);

        printf("网络字节序地址:0x%x.\n", s.sin_addr.s_addr);

#if 0 // 演示网络结构体赋值

/*      // 网络结构体填充

        set_net_struct(structsockaddr_in *p);

 

       

*/

        //1structsockaddr_in定义这种类型的结构体变量

        structsockaddr_in s;

        //2、填充你这个结构体各成员

        s.sin_family= AF_INET;

//      s.sin_ =AF_INET;              (错误)

        //但是已经错了,你的发送数据包,肯定找不到对方。

        //传送过去的IP/PORT都是网络字节序,大端模式:低位(字节)要放到高地址。

        s.sin_port= htons(PORT);    

//      printf("s.sin_port= 0x%x.\n", s.sin_port);

 

        s.sin_addr.s_addr= inet_addr(ADDR);

        //0x16011013

//      printf("网络字节序地址:0x%x.\n", s.sin_addr.s_addr);

#endif

        return 0;

}

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

/*

        柔性数组:是在结构体里,有一个数组,必须是结构体最后的一个元素,而且由特定形式[][0];

        整体的结构体至少有两个成员变量。  

*/

//不好之处:1p(字符串)压根就没用,2、每次要用字符串时,很麻烦(char *)(p+1)

typedef struct data

{

        int a;

        char*p;     // 结构体里存储的字符串, 和你结构体时分离的。

}D;

//柔性数组,最后一个数组name[],不占空间,只是一个符号(常量地址)

typedef struct

{

        int len;

        intarr[];

}S;

// 看一下,遍历

void show_infor(S *p)

{

        int i =0;

//          printf("p->arr[%d]= %d.\n", p->len-1, p->arr[p->len-1]);

        //遍历所有元素

        for (i=0;i<p->len; i++)

        {

                printf("p->arr[%d]= %d.\n", i, p->arr[i]);

        }

}

 

 

//生成柔性数组

void create_soft_arr(int len)

{

        S *p = (S*)malloc(sizeof(S) + sizeof(int)*len);

        //a成员控制我数组个数

        p->len= len;

       

        int i =0;

       

        for (i=0;i<len; i++)

        {

                if(i <= 1)

                       p->arr[i]= 1;

                elseif (i >= 2)

                       p->arr[i]= p->arr[i-1] + p->arr[i-2];

        }

       

        //看一下 用func

        show_infor(p);

       

        free(p);

}

int main(void)

{      

        create_soft_arr(10);

#if 0

        int len =10;

 

        printf("sizeof(S)= %d.\n", sizeof(S));   // 4

        //动态数组生成

        //.符号:结构体变量访问各成员.

        S *p = (S*)malloc(sizeof(S) + sizeof(int)*len);

        //判断空间申请情况,和清0操作,省略

        //数组赋值

        int i =0;

       

        for (i=0;i<len; i++)

        {

                //p->arr得到的是数组名

                p->arr[i]= i+1;

//              (*p).arr[i]= i+1;

        }

        //看一下

        for (i=0;i<len; i++)

        {

                printf("p->arr[%d]= %d.\n", i, p->arr[i]);

        }

/*

        int *p_a= (int *)malloc(10);

 

        charbuf[] = "2017_12_24";

        //把字符串放到我的结构体里

        D *p = (D*)malloc(sizeof(D) + strlen(buf) + 1);     

 

        printf("sizeof(structdata) = %d.\n", sizeof(struct data));

 

        printf("(char*)(p+1) = [%s].\n", (char *)(p+1));

 

        strcpy((char*)(p+1), buf);

 

        printf("(char*)(p+1) = [%s].\n", (char *)(p+1));

*/ 

#endif 

        return 0;

}

#include <stdio.h>

typedef enum STATE

{

    STATE1,

    STATE2,

    STATE3,

    STATE4,

}S;

int main(void)

{

    int num;

    Scurrent_state=STATE1;

    printf("请输入秘密\n");

    int i=4;

    while(i--)

    {

        scanf("%d",&num);

        printf("num=%d\n",num);

        switch(current_state)

        {

            caseSTATE1:

            if(num==4)

            {

                current_state=STATE2;

            }

            else

            {

                current_state=STATE1;

            }

            break;

            caseSTATE2:

            if(num==3)

            {

                current_state=STATE3;

            }

            else

            {

                current_state=STATE1;

            }

            break;

            caseSTATE3:

            if(num==4)

            {

                current_state=STATE4;

            }

            else

            {

                current_state=STATE1;

            }

            break;

            caseSTATE4:

            if(num==2)

            {

                current_state=STATE4;

            }

            else

            {

                current_state=STATE1;

            }

            break;

            default:

                current_state=STATE1;

            break;

        }

    }

    if(current_state==STATE4)

    {

        printf("密码正确\n");

    }

    else

    printf("密码错误\n");

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值