Day10

指针

  • 指针与函数
#include 
void test();
int main()
{
    /*
     * 指向函数的指针
     *   计算机也会给函数分配存储空间,所以函数也有自己的地址,所以指针
     * 变量也可以保存函数的地址
     *
     * 数组名保存的就是数组的地址,函数名中保存的也是函数的地址
     *
     * 如何定义函数指针变量
     * 1. 将需要函数拷贝
     * 2. 在函数返回值和函数名之间加*
     * 3. 修改函数名称
     * 4. 需要将*和变量名称用括号括起来
     *
     * 注意点:
     * 如果是数组,我们可以直接将数组名称赋值给一个指针变量
     * 如果是函数,我们可以直接将函数名称赋值给一个指针变量
     */

    //定义函数指针变量
    void (*funcp)();
    //将函数的地址赋值给函数指针
//    funcp = &test;
    funcp = test; //因为函数名称保存的是地址,所以这种写法也可以



    //test();  //调用函数的第一种方式
    //(*funcp)(); //调用函数的第二种方式
    funcp();  //调用函数的第三种方式
    return 0;
}

void test(){
    printf("打印点东西");
}
  • 练习
    回调函数
#include 
int sum(int, int);
int minus(int, int);
int main()
{
    /*
     * 需求: 要求一个函数既可以计算两个变量的和也可以计算两个变量的差
     */
    int res = test(10, 20, minus);
    printf("%i\n", res);
    return 0;
}
/*
 * 注意点: 指向函数的指针,作为函数的形参的时候,指针变量的名称,就是形参名称
 * 如果指向函数的指针作为函数的形参,那么这个函数可以称之为回调函数
 */
int test(int a, int b, int (*funcp)(int ,int)){
    return funcp(a, b);

}

int sum(int a,int b){
    return a + b;
}

int minus(int a, int b){
    return a - b;
}

结构体

  • 基本概念
    /*
     * 结构体
     *   结构体是构造类型的一种,数组也是构造类型,数组的作用是存储一组相同
     * 类型的数据,结构体的作用是存储一组不同类型的数据
     *
     * 如何定义结构体变量
     * 1. 先定义结构体的类型
     * 2. 通过结构体的类型定义结构体的变量
     *
     * 定义结构体的类型
     * struct 结构体类型名称{
     *      数据类型 属性名称;
     *      数据类型 属性名称;
     *      .
     *      .
     * }
     *
     * 定义结构体变量
     * struct 结构体类型名称 变量名称;
     *
     * 访问结构体属性
     * 结构体变量名称.结构体属性名称;
     */
    //定义结构体的类型
    struct Person{
        char *name;
        int age;
        double height;
    };
    //定义结构体变量
    struct Person p;
    //使用结构体变量
    p.name = "niuzi";
    p.age = 18;
    p.height = 1.6;
    printf("%s\n", p.name);
    printf("%i\n", p.age);
    printf("%lf\n", p.height);
  • 结构体变量初始化
/*
     * 结构体的初始化
     * 1. 定义的同时初始化
     * 2. 先定义后初始化
     * 3. 先定义结构体变量,后再完全初始化,但是不建议这样写
     */
    
    struct Dog
    {
       char *name;
       int age;
    };
    //1. 先定义后初始化
//    struct Dog p;
//    p.name = "ww";
//    p.age = 10;
    
    //2. 定义的同时初始化
    //注意点: 定义的同时初始化,那么初始化顺序必须和结构体类型中的顺序一致
//    struct Dog p ={"ww", 10};
    struct Dog p ={.name = "ww", .age = 10}; //这种顺序可以变
  • 定义结构体变量
/*
     * 定义结构体变量的几种方式
     * 1. 先定义结构体类型,再定义结构体变量
     * 2. 定义结构体类型的同时定义结构体变量
     * 3. 定义结构体类型的同时省略结构体名称,同时定义结构体变量
     */
    //1.先定义结构体类型,再定义结构体变量
//    struct Person
//    {
//        char *name;
//        int age;
//    };
//    struct Person p;

    //2. 定义结构体类型的同时定义结构体变量
    struct Person
    {
        char *name;
        int age;
    } p2;

    p2.age = 18;
    p2.name = "ll";
    printf("%i\n", p2.age);

    //3. 定义结构体类型的同时省略结构体名称,同时定义结构体变量
    //匿名结构体,结构体类型只能使用一次
    struct
    {
        char *name;
        int age;
    } p3;
  • 结构体变量作用域
    结论; 和变量的作用域一样,在代码块中只能在该代码块中使用,外界无法访问的到

  • 结构体数组
    定义一个数组保存结构体变量

    /*
     * 结构体数组
     * 结构体类型 数组名称[元素个数];
     */
    struct Person
    {
        char *name;
        int age;
    };
    struct Person p1 = {"ww", 16};
    struct Person p2 = {"jj", 18};
    struct Person p3 = {"nn", 20};
    //结构体数组第一种方式
    struct Person ps[3] = {p1, p2, p3};
    //结构体数组第二种方式
    struct Person ps[3] = {
        {"ww", 16},
        {"jj", 18},
        {"nn", 20}    
    };
  • 结构体内存分析


    Day10_第1张图片
    /*
     * 结构体内存分析
     */

    /*
     * 结构体在分配内存的时候,会做一个内存对齐操作
     * 会先获取所有属性中内存最大的属性的字节,然后在开辟最大属性字节的内存给第一个属性
     * 之后再分配给第二个属性,如果分配的内存存储第一个属性后,不够第二个属性存储
     * 那么会再次开辟最大属性字节的内存,再往后分配
     * 
     */
    
    struct Person
    {
        char *name;
        int score;
    };
    
    //结构体在分配内存的时候,会做一个内存对齐的操作,会按照结构体属性当中
    // 占用内存最大的那个字节属性的字节倍数来分配
    
    struct Person p;
    printf("sizeof = %i\n", sizeof(p)); //8
    //结构体变量名称没有保存结构体首属性的地址
    printf("p = %p\n", p); //00000054
    printf("&p = %p\n", &p); //0028FEB8
    printf("p.name = %p\n", &p.name); //0028FEB8
    printf("p.score = %p\n", &p.score); //0028FEBC
  • 结构体指针
/*
     * 结构体指针
     * 定义指向结构体变量的指针的套路和过去定义指向普通变量一样
     * 
     * 如果指针指向了一个结构体变量,那么访问结构体属性就有三种方式
     * 1. 结构体变量名称.属性名称
     * 2. (*结构体指针变量名称).属性名称
     * 3. 结构体指针变量->属性名称
     */

    struct Person
    {
       char *name;
       int age;
    };
    struct Person per = {"niuzi", 18};
    //定义结构体指针
    struct Person *p;
    p = &per;
    //指针两种访问属性方式
    printf("%s\n", (*p).name);
    printf("%i\n", p->age);
  • 结构体嵌套
    /*
     * 结构体嵌套
     * 可以提高代码的复用率
     */

    //1. 定义一个日期的结构体
    struct Date
    {
       int year;
       int month;
       int day;
    };
    //2. 定义一个人的结构体
    struct Person
    {
       char *name;
       int age;
       struct Date birthday;  //结构体嵌套
    };
    //结构体嵌套初始化
    struct Person per = {"ww", 18, {2008,10,23}};
    printf("%i\n", per.birthday.year); //访问嵌套属性
    printf("%i\n", per.birthday.month);
    printf("%i\n", per.birthday.day);
  • 结构体和函数
    注意点: 结构体变量之间是值传递,和普通变量一样
 /*
     * 结构体和函数
     * 结构体是构造类型,但是结构体变量之间是值传递,和普通变量一样
     *
     * 注意点: 定义结构体类型的时候不会分配存储空间,只有定义结构体变量
     * 的时候才会分配存储空间
     */

    struct Person
    {
        char *name;
    };
    struct Person p1 = {"nn"};
    struct Person p2;
    p2 = p1; //值传递
    p2.name = "haha";
    printf("p1 = %s\n", p1.name); //nn
    printf("p2 = %s\n", p2.name); //haha
Day10_第2张图片
#include 
struct Person
{
    char *name;
};
void test(struct Person per);

int main()
{
    /*
     * 结构体和函数
     * 结构体是构造类型,但是结构体变量之间是值传递,和普通变量一样
     *
     * 注意点: 定义结构体类型的时候不会分配存储空间,只有定义结构体变量
     * 的时候才会分配存储空间
     */

//    struct Person
//    {
//        char *name;
//    };
//    struct Person p1 = {"nn"};
//    struct Person p2;
//    p2 = p1; //值传递
//    p2.name = "haha";
//    printf("p1 = %s\n", p1.name); //nn
//    printf("p2 = %s\n", p2.name); //haha

    struct Person p1 = {"nn"};
    test(p1);
    printf("p1 = %s\n", p1.name);


    return 0;
}
/*
 * 在main函数中结构体是局部,外部函数无法访问所以要放到外面
 * 结构体变量是值传递,不是传递地址,所以函数内部无法改变结构体的属性
 */
void test(struct Person pe){
    pe.name = "zs";
}

你可能感兴趣的:(Day10)