C语言【自定义数据类型、typedef、动态内存分配】

打印 上一主题 下一主题

主题 887|帖子 887|积分 2661

C语言【自定义数据类型、typedef、动态内存分配】

一、自定义数据类型。

​        关于下面讲到的所有自定义数据类型(enum、struct、union),有一点要说的是:定义类型不是声明变量,做这步操作时不分配内存,也不能在定义类型时赋值(枚举那个不是赋值,是做一个限定,赋值时赋限定之外的值也不报错。)。
1、typedef (给类型起别名的关键字)
  1. // C语言中给数据类型起别名的同时不能声明变量。
  2. // 一个错误的示范:// typedef int Integer i;        // 不能在这里声明i。自定义数据类型同理。
复制代码
  1. // 给指针类型起别名
  2. typedef int* intptr;
  3. typedef char* String;
复制代码
  1. // 给数组类型起别名
  2. typedef int fiveInts[5];                // 有一丢丢不一样
  3. // 使用数组类型的别名声明变量并初始化
  4. fiveInts a = {1, 2, 3, 4, 5};        // 记一点,这种大括号形式的初始化只能声明变量时这样使用,否则报错。前面有记错的地方记得改正。
复制代码
  1. // 给数组指针类型起别名
  2. typedef int (* IntArrayPointer)[5];
  3. // 数组指针类型的使用
  4. int a[5] = {1, 2, 3, 4, 5};
  5. IntArrayPointer p = &a;
复制代码
2、枚举

​        可以看作是一个限定取离散值范围的类型。
​        枚举类型的定义。这个类型一般定义为全大写,因为里面的元素全都是常量。
  1. // 定义枚举类型。
  2. enum WEEKDAY{
  3.     MON,                // 默认为0
  4.     TUE,                // 上面是0,这个默认就是1;如果上面定义了2,这个就是3
  5.     WED,               
  6.     THU = 5,        // 告知 THU为5
  7.     FRI,
  8.     SAT = 1,        // 可与上面的重复,但不建议。  不可为浮点数。
  9.     SUN
  10. };
  11. // 使用上面定义的枚举类型。声明并赋值。
  12. void main(){
  13.     // enum WEEKDAY 是类型; wd是变量名; 值可以是枚举类型之外的数,比如100,但不建议。
  14.     enum WEEKDAY wd = TUE;       
  15. }
复制代码
  1. // 隐式定义枚举并声明出变量。
  2. enum {
  3.    // 不管是不是隐式定义,这个大括号中不能没有内容,否则报错。
  4.    A,
  5.    B
  6. } day;
复制代码
​        枚举没有特殊的遍历方法,也就是说枚举的元素如果值是错乱的,一般就无法完成遍历了。
  1. // 枚举变量的内存大小
  2. // 用上面定义的枚举实验。一个枚举变量就是一个元素的值,整型为4。
  3. // 定义枚举时不分配空间。声明变量时,那个变量存的就是枚举中的一个元素。想一想java中的枚举类。
  4. sizeof(enum WEEKDAY);        // 4
复制代码
  1. // 枚举与switch...case的搭配。
  2. switch(wd){                // 借用上面声明的wd变量
  3.     case MON:
  4.         // ...
  5.         break;
  6.     case TUE:
  7.         // ...
  8.         break;
  9.     // ...
  10.     default:
  11.         // ...
  12.         break;
  13. }
复制代码
3、结构体
  1. // 结构体类型的定义
  2. struct Student{       
  3.           int id;
  4.           int age;
  5.     // char arr[];         // 会报错
  6.           char *name;                // 直接赋字符串字面值可以,字面值也算是有过空间分配。如果拿它接收个用户输入就会报错。直接指向有空间的值当然也没问题。
  7. };
  8. // 使用
  9. void main(){
  10.     struct Student stu1;
  11.     stu1.id = 1001;
  12.     // stu1[0] = 1002;        // 没有这种写法的。
  13. }
复制代码
  1. // 结构体指针-----指向结构体类型变量的指针
  2. struct Struct *ptr = &stu1;                // 这个结构体类型上面定义了。stu1上面声明了。
  3. // 结构体指针的使用
  4. (*ptr).id = 1003;
  5. ptr->id = 1004;
复制代码
​        结构体中关于空间有一个对齐的问题。两点要求:1、结构体中某一成员的起始地址为该成员所占字节的整数倍;2、结构体整个空间大小要求为其中最大成员的整数倍。
4、共用体

​        共用体内的成员共同使用同一段空间。
​        共用体所占内存空间为其内部成员中最大的那个空间。
​        应用场景:根据条件在字段内定义不同类型的值。
  1. // 共用体类型定义
  2. union Score{
  3.     int score1;
  4.     double score 2;
  5. }
  6. // 使用
  7. union Score a;        // 声明变量
  8. union Score b = {.score2 = 1};        // 声明变量并赋值。
  9. a.score1 = 10;        // 赋值
复制代码
5、手动动态分配内存

​        内存的自动动态分配是系统在栈空间完成的。
​        *void ** :C99允许定义一个类型为void的指针变量。这个(void*)类型的指针变量可以指向一块地址,但是这个指针变量除了输出首地址外,其余操作均无意义,这个指针变量的++操作移动一个地址,即1Byte。 这个指针变量可以强转为任何指针类型(如强转为int,就可以一次移动4Byte), 也可以被任何指针强转成这个指针类型。 下面的几个手动动态分配内存的函数返回值都为void * , 可以强转为自己需要的指针类型,即使你需要char * 也建议转过去,而不是用void *。
​        以下是一些在空间手动分配内存的几个函数及其使用。需要引入头文件
  1. // malloc函数
  2. // 内存分配成功返回一个void*,指针指向新分配内存的起始地址;分配失败返回NULL
  3. void * malloc(size_t size);               
  4. // malloc函数的使用
  5. int *p = NULL;
  6. if(p==NULL){
  7.     p = (int *) malloc(sizeof(int));        // 分配一个int类型的空间
  8. }
  9. *p = 100;        // 给分配的这个int赋值
  10. free(p);        // 释放这个内存
复制代码
​        我们可以通过指针修改const声明的常量的值。但是const这种常量根本就不能作为数组的长度。
​        如果想使用变量指定数组长度,除了动态分配我想不出别的方法。
  1. // maloc实现数组的动态分配
  2. int n = 5;
  3. int *p = (int *) malloc(n*sizeof(int));
  4. p[0] = 10;        // 因为转成的(int*)类型,所以p[0]即前四个Byte所表示的数组,可赋值或修改。
复制代码
  1. // calloc函数 (自带初始化为0的功能)
  2. // 第一个参数为要分配的元素个数,第二个参数为要分配给每个元素的字节数。
  3. void * calloc(size_t numElements, size_t sizeofElement);       
  4. // calloc函数的使用
  5. int *p = (int *) calloc(5, sizeof(int));        // 给p指针分配了5个int堆内存
  6. free(p);        //释放
复制代码
  1. // realloc函数
  2. // 第一个参数是要重新分配堆内存的指针,第二个参数是新分配内存的大小。
  3. // 返回一个指向重新分配内存块的指针,即free后重新分配
  4. void * realloc(void *ptr, size_t size);
  5. // realloc函数的使用
  6. int *p = (int *) malloc(5*sizeof(int));
  7. p = realloc(p, 5*sizeof(int));
  8. free(p);
复制代码
​        在全局声明的指针,不能再全局分配内存。
​        给指针动态分配好内存后,它的初始值是随机的。
​        calloc函数有初始化0的功能。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

宝塔山

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表