• C语言中的结构体


    一结构体

    1. 结构体

    如果需要保存学生的年龄、成绩、姓名等多个字段时需要用到结构体,即将多个相关的数据封装在一起。

    struct Stu{

    char name[20];

    int age;

    float score;

    };

    定义了一个新的数据类型Stu,可以通过Stu定义变量。

    struct Stu s1, s2;

    s1.age = 18;

    s1.score = 90;

    s2.age = 20;

    s2.score =99;

    Stu是数据类型,不是变量, s1和s2是变量,s1有两个成员age和score

    2. 结构体变量的赋值与初始化

    struct XYPoint {

    int x;

    int y;

    };

    struct XYPoint  point = {3,4}; //初始化

    struct XYPoint point2;

    point2 = point; //赋值

    //成员分别赋值

    point2.x = 10;

    point2.y = 20;

    练习:定义一个表示学生的结构体

    struct Person{

    char name[20];

    int age;

    int height;

    };

    struct Person p;

    p = (struct Person) {"zhangsan", 18, 172}; //强制转换后赋值是正确的

    也可以这样初始化,指定属性的名称:

    struct Person p = {.name = "zhangsan", .age = 15, .height = 173};

    3. 在iOS中的应用

    struct Rect{

    XYPoint  origin;

    XYSize   size;

    };

    4. 结构体取别名

    typedef  struct Stu Student;

    Student s1; //用别名定义变量

    typedef  unsigned long   size_t;

    size_t  xx;

    也可以在声明的时候定义别名:

    typedef struct {

    int width;

    int height;

    }  Size;

    Size就是这个结构体的别名

    5.返回结构体的函数

    如根据给定的数值创建一个函数返回该结构体

    Rect  rectMake( int x, int y, int width, int height){

    Rect rect = {{x,y } , {width, height} };

    return rect;

    }

    Rect rect1 = rectMake(10,20,100,30);

    6.结构体大小

    结构体对齐

    7.结构体指针

    Rect  rect1 = rectMake(12,23,34,45);

    Rect *p = &rect1;

    (*p).origin.x = 100;

    p-> origin.x = 100;  //箭头实际上就是先取*再取.操作

    二、枚举

    1. 枚举的定义

    季度、 星期几、 颜色、 型号等数据在存储时,可以使用枚举类型

    enum  Color {

    Red,

    Green,

    Blue,

    Yellow,

    Brown

    };

    定义了一个数据类型Color,可以通过Color来定义变量,其变量的取值只能是定义Color类型时指定的取值,如:Red,Green,Blue,Yellow,Brown。如:

    enum Color myColor = Red;

    2.枚举变量的输出

    printf("%d ", myColor);

    枚举可以按%d的形式输出,输出结果是一个整形数字,定义枚举类型时,默认就是从0开始的一组整形数字

    在给枚举变量赋值时,也可以这样实现:

    enum Color myColor2 = 2;

    跟 

    enum Color myColor2 = Blue;

    这两条效果是一样的,枚举本质上就是一个整型,使用枚举就是为了方便阅读或记忆。

    3.注意

    在定义枚举时,其变量的取值一般是以类型名开头,如:

    enum Week {

    WeekSunday,

    WeekMonday,

    WeekTuesday,

    WeekWednsday,

    WeekThursday,

    WeekFriday,

    WeekSaturday

    };

    这样在通过枚举类型定义变量时,

    enum Week  day1= Week...

    给变量赋值时,就以类型名开头,系统会自动提示该类型的可能取值。不至于与其他的枚举类型取值弄混。

    在以后学iOS开发时,会使用到系统提供的大量的枚举类型

    三、动态内存分配与宏

    1. 静态内存分配

    程序在编译时就已经确定所要分配内存空间的大小,如常用的变量、常量等。

    2. 动态内存分配 

    在运行时,程序员可以在堆空间中动态分配存储空间。

    可以通过 malloc(100); 函数在堆中开辟100个字节大小的空间,返回该空间的首地址。需要通过指针访问该空间。

    char *p = (char *) malloc(100); 

    因为malloc()函数的返回值是void *, 在有的编译器中需要进行强制类型转换,如上一行代码。

    动态分配存储空间不一定成功,所以需要进行验证,如:

    if ( !p ) {

    perror ("malloc error");

    }

    perror打印标准报错,在命令行中,标准输出和标准报错都是终端。有时需要将标准报错设置为某个文件。

    需要注意的是,堆空间本身没有数据类型,用p指向这个空间,将这个空间看作是 char *[] 数组。

    可以通过指针变量p赋值如下:

    p[0] = 'A';

    p[30] = 'Z';

    再如:

    int * q = malloc(100);

    if (!q) {

    perror("malloc");

    }

    如果用int *指针指向这100个字节的堆空间,则该空间可以存储25个int类型的数据, q[0]是前4个字节, q[1]是第5到第8个字节。可以这样赋值

    q[0] = 110;

    q[1] = 250;

    3.释放存储空间

    堆空间使用完成后,需要手动释放,

    free(p);

    free(q);

    开辟空间实际上就是在系统中注册这一段空间,我用了;释放空间就是告诉系统,我不用了。

    4. 根据字符串大小动态开辟存储空间保存字符串

    int i = 0;

    while ( i++ < 100 ){

    int n = 0;

    scanf("%d", &n);

    char *p = malloc( n+1 );

    scanf("%s", p);

    printf("%p的位置,存储的是:%s", p, s);

    free(p);

    }

    每次循环都会动态在堆中开辟一块存储空间,空间的大小由用户输入,然后再输入字符串保存到该空间中,输出该字符串。用完后,释放该空间

    5. 静态分配与动态分配的区别

    存储位置不同:栈和堆;

    静态分配在编译时决定,动态分配是在程序运行时决定大小;

    静态分配空间的大小由编译器决定,动态分配由程序员决定

    静态分配的空间自动释放,动态分配的空间需要手动释放。因此需要注意的是:如果没有手工释放动态分配的空间,堆空间的存储空间不会随着函数的调用结束而释放,在程序的运行期间会一直占用这块空间,直到程序结束。

    四、宏

    1. 宏就是在预处理阶段的简单的字符串替换,预处理是在编译前进行。

    C语言程序编译由四步:

    预处理:根据预处理指令修改源文件,宏是字符串替换,#include是把头文件复制到源文件中

    gcc -o test.i  test.c  -E

    编译,将代码翻译成中间语言或汇编代码

    gcc -o test.s  test.i  -S

    汇编,将汇编代码翻译成目标机器指令

    gcc -o test.o  test.s  -c

    链接,将有关的目标文件、库文件链接在一起。

    gcc -o test   test.o

    执行就是

    ./test

    2. 定义宏

    #define  PI  3.14159

    int main(){

    printf( "%f ", PI *10*10);

    }

    在编译前,将程序中的PI字符串用3.14159代替

    一般情况下,将可能会被修改的常量定义为宏。如定义数组时,如果数组的长度可能会发生变化,可以将数组的长度用宏来代替。

    在iOS开发中经常使用宏来保存url地址,在项目开发时,经常使用测试系统,上传APP Store时需要使用正式URL

    如让NSLog仅在调试阶段使用,在发布时不需要,可以这样定义

    #ifdef  DEBUG

    #define  CuiLog(…)  NSLog(__VA_ARGS__)

    #else

    #define CuiLog(…)  

    #endif

    或者:

    #ifdef DEBUG

    #define CuiLog(format,...)  printf(format,##__VA_ARGS__)

    #else

    #define CuiLog(format, ...)

    #endif 

    3.带参数的宏

    #define  PI 3.14159

    #define  A(r)  PI*r*r

    #define Area(r)  (PI*(r)*(r))

    //带参数的宏建议变量和结果都加上小括弧

    int main(){

    printf("%f ",  A(10));

    printf("%f ",  A(5+5) );

    printf("%f ",  Area(10) );

    printf("%f ",  Area(5+5));

    return 0;

    }

    练习:把求两个数的和,两个数的积定义为宏

    写一个宏求三个数的最大值

    作业

    1. 创建一个公司的员工的结构体,存储员工的姓名、工龄和年龄。在main函数中创建由5名员工组成的数组。要求编写函数实现:

    1)从终端读入5名员工信息

    2)按年龄排序

    3)按工龄排序

    4)按照当前顺序,打印每名员工的信息。

    *)改进,尝试把按年龄排序,按工龄排序用一个函数来实现(排序函数需要一个指向函数的参数),函数原型:

    void sort( Employee *employees, int count,  int (*p) (Employee, Employee))

    定义一个比较年龄的函数,如

    compareByAge( Employee e1, Employee e2){

    if ( e1. age < e2.age ){

    return 1;

    }else {

    return 0

    }

    }

    或直接写成

    compareByYears( Eimployee e1, Employee e2 ){

    return e1.years < e2.years;

    }

    如果还有员工编号的话,还可以继续按员工编号排序,继续进行扩展,但是sort排序函数不变,只需要增加一个按员工编号比较的函数就可以了。

  • 相关阅读:
    93. Restore IP Addresses
    92. Reverse Linked List II
    阿里巴巴 内推 面试
    hulu
    287. Find the Duplicate Number *HARD*
    89. Gray Code
    87. Scramble String *HARD* 动态规划
    84. Largest Rectangle in Histogram *HARD* -- 柱状图求最大面积 85. Maximal Rectangle *HARD* -- 求01矩阵中的最大矩形
    BZOJ2693jzptab
    最大公约数和
  • 原文地址:https://www.cnblogs.com/ljcgood66/p/5281279.html
Copyright © 2020-2023  润新知