C语言自定义数据类型基础知识

枚举

  1. 枚举:C语言中一种自定义数据类型。
  2. 语法:
    1. enum :使用enum关键字来定义, enum  枚举名称 { 枚举元素1, 枚举元素2 , ... 枚举元素n}; 
  3. 枚举常量:枚举元素也称为枚举成员或枚举常量。
    1. 枚举元素的值必须在同一枚举中是唯一的。
    2. 枚举元素的值必须是整数类型,通常int。
    3. 如果没有为枚举元素指定值,编译器会自动为他们分配值,从 0 开始。
    4. 也可以自定义值,需保证唯一性和整型类型。
  4. 枚举变量:定义变量时指定类型是我们所定义的枚举类型,该变量称为枚举变量。枚举变量的值应该是枚举类型中的枚举常量中的一个。
  5. 定义枚举变量的语法:
    1. 先定义枚举类型,在定义枚举变量。
    2. 定义枚举类型的同时声明枚举变量。
    3. 定义枚举类型的同时声明枚举变量,且省略枚举名称。
  6. 遍历枚举时,枚举常量的值应该是连续的。
#include <stdio.h>
// 定义枚举
enum Week {
  MONDAY = 1,
  TUESDAY,
  WEDNESDAY,
  THRUDAY,
  FRIDAY,
  SATURDAY,
  SUNDAY
};

int main() {
  enum Week week;
  printf("请你输入数字:");
  scanf("%d", &week);
  // for (int day = 0; day < week; day++) {
  //   printf("今天是星期%d\n", day);
  // }
  switch (week) {
  case MONDAY:
    printf("星期一\n");
    break;
  case TUESDAY:
    printf("星期二\n");
    break;
  case WEDNESDAY:
    printf("星期三\n");
    break;
  case THRUDAY:
    printf("星期四\n");
    break;
  case FRIDAY:
    printf("星期五\n");
    break;
  case SATURDAY:
    printf("星期六\n");
    break;
  case SUNDAY:
    printf("星期日\n");
    break;
  default:
    printf("输入有误\n");
    break;
  }
  for (int i = MONDAY; i <= SUNDAY; i++) {
    printf("%d\n", i);
  }
  return 0;
}

结构体

  1. 结构体:struct 关键字,将不同的类型的值组合在一起。类似与对象和类的功能。
  2. 声明结构体格式:
  3. struct 结构体名 {
        数据类型1 成员名1;
        数据类型2 成员名2;
        ...
        数据类型n 成员名n;
    };

    结构体一般格式

  4. 结构体变量

    1. 先定义结构体,在创建结构体变量。

    2. 在定义结构体的同时定义结构体变量。

    3. 在定义时也可以省略结构体名。

    4. 结构体是一种自定义的数据类型,结构体变量是根据结构体类型创建的变量,用于存储数据。

  5. 成语的获取和赋值:结构体使用 点号 . ,获取单个成员,进行赋值和取值。

  6. 结构体指针:指向结构体的指针变量。

    1. 语法: struct   结构体名  *结构体指针变量名;

    2. 声明结构体指针:先定义一个结构体变量,在创建结构体指针,取其地址作为结构体指针的值。

    3. 结构体指针访问成员: 通过 -> 操作符范文结构体的成员。

  7. 指针变量p指向一个结构体变量stu,以下3中用法等价:

    1. stu.成员名

    2. (*p).成员名

    3. p->成员名

总结:

结构体是自定义的数据类型,表示一种数据类型;结构体变量代表一个具体变量。

#include <stdio.h>

// 定义结构体
struct Students {
  int id;
  char *name;
  char *genter;
  char *email;
  char *phone;
};
// 定义同时声明结构体变量
// struct Students
// {
//   int id;
//   char *name;
//   char *genter;
//   char *email;
//   char *phone;
// } students;
// 省略结构体名
// struct 
// {
//   int id;
//   char *name;
//   char *genter;
//   char *email;
//   char *phone;
// } students;

int main() {
  // 定义结构体变量
  struct Students stu;
  // 结构体成员赋值
  stu.id = 101;
  stu.name = "咸亨";
  stu.genter = "男";
  stu.email = "123@163.com";
  stu.phone = "13895647854";
  printf("stu 的 id %d, stu 的 name %s\n", stu.id, stu.name);
  // 结构体指针
  struct Students stu1 = {102, "tom", "女", "124424@123.com", "18695456889"};
  struct Students *ptr = &stu1;
  // 访问
  ptr->name = "LIHua";
  printf("ptr->name = %s\n", ptr->name);
  (*ptr).phone = "12345678";
  printf("ptr->phone = %s\n",(*ptr).phone);

  return 0;
}

#include <string.h>   strcmp(a, b); 比较连个字符串是否相等,相等等于0, 不等等于 -1;

“hello” == "hello"  ——C语言判断时 当成字面量-》常量,存储在只读数据段中,存储地址是相同的。

共用体

  1. 共用体:union关键字,自定义数据结构。内部可以包含各种属性,但同一时间只能有一个属性。
  2. 结构体变量所占内存长度是各成员内存的长度的叠加,共用体变量所占内存长度等于最长的成员的长度,吉特成员共用一个内存区。
  3. 声明结构体:
union 共用体类型名称 {
    数据类型1  成员名1;
    数据类型2  成员名2;
    ...
    数据类型n  成员名n;

};

共用体:同一时间只能取到一个属性,最后赋值的属性,覆盖前面的属性值。

  1. 声明公用体变量的方式:
    1. 先定义共用体类型,在定义共用体变量;
    2. 定义共用体类型的同时定义共用体变量;
    3. 在定义时可以不给出共用体名。
  2. 成员的获取和赋值
    1. union data a;  a.c = 4;
    2. 声明共用体变量的同时,给任一成员赋值:union data a  = { .c = 2};
    3. 声明共用体变量的同时,给首成员赋值。union data a = { 8 };
    4. 不指定成员名,所以只能为第一个成员赋值。
#include <stdio.h>
int main() {
  // 共用体
  // union data { 
  //   int a; 
  //   char b;
  //   double c;
  // } st, wu;
  // union {
  //   int a;
  //   char b;
  // } st, wu;
  union data {
    int a;
    char b;
    double c;
  };
  // union data st, wu;
  // st.a = 10;
  // union data st = {.b = 20};
  union data st = { 30}; // 赋值给第一个 ,但是公用一个 内存地址,访问都是 30
  printf("%d\n", st.a);
  // printf("%d\n", st.b);
  // printf("%d\n", st.c);

  return 0;
}

typedef

  1. tepydef:为一个数据类型起一个新的别名。
  2. typedef声明数组类型、指针类型、结构体类型、共用体类型等。
  3. 通常typedef声明的类型名的第一个字母大写,以便和系统的区分。
  4.  为某个基本类型起别名:typedef  类型名  别名;也可以一次起多个别名;
  5. 为结构体、共用体起别名;typedef struct Treenode Tree;  别名 Tree。
  6. 为指针起别名;typedef char *String;
  7. 为数组起别名;typedef int Num[100]; 别名 Num;

动态内存分配

  1. 动态内存分配指根据需要向系统申请所需大小的空间,由于未在声明部分定义其为变量或者数组,不能通过变量名或者数组名来引用这些数据,只能通过指针来引用);

  2. 指针:C99允许定义一个类型为void的指针变量,它可以指向任何类型的数据。

  3. void指针:指针变量必须有类型,还不确定会有什么类型的数据写入内存,需要要先获得内存块,稍后再确定写入的数据类型,可以使用void指针。

  4. void 指针与其他所有类型指针之间是互相转换关系,任一类型的指针都可以转为 void 指针,而 void 指针也可以转为任一类型的指针。
  5. 由于不知道 void 指针指向什么类型的值,所以不能用 * 运算符取出它指向的值(解引用)。
#include <stdio.h>

int main()
{
    int a = 110;
    double b = 3.14;
    // void *类型指针,可以与其他类型的指针相互转换
    //  将右侧int *类型地址,隐式转换为void *
    void *ptr = &a;
    // 将右侧double *类型的地址,隐式转换为void*
    void *ptr1 = &b;
    // 无类型指针不能取值
    //  printf("%d\n", *ptr);

    // void * 类型指针 强转其他类型
    int *p = (int *)ptr;
    double *p1 = (double *)ptr1;
    printf("%d %lf\n", *p, *p1);

    return 0;
}
  1. 其他类型指针赋给 void指针,使用隐式转换即可,void 指针赋给其他类型指针,建议使用显式类型转换。
  2. malloc() 函数:malloc() 函数用于分配一块连续的内存空间。
  3. 函数原型:void *malloc(size_t size);

    返回值说明:

    如果内存分配成功,返回一个void指针,指向新分配内存块的地址;如果分配失败(例如内存不足),返回一个空指针(NULL)。

    参数说明:

    size是要分配的内存块的大小,以字节为单位。

#include <stdio.h>
// 动态分类内存函数malloc,位于stdlib这个头文件当中
#include <stdlib.h>
int main()
{

    // 在堆空间开了一个四字节内存大小
    int *ptr = (int *)malloc(sizeof(int) * 1000);
    // 每次用之前先判断申请内存是否充足
    if (ptr == NULL)
    {
        printf("内存不足!!!!");
        // 程序结束
        return 1;
    }
    // 向申请哪个区域存储一个整数100
    *ptr = 100;
    printf("%d\n", *ptr);
    // 每一次操作完以后,释放内存
    free(ptr);
    // //释放以后不要在操作【访问|赋值这块内存啦】!!!
    printf("%d\n", *ptr);

    return 0;
}
  1. calloc() 函数:用于分配内存并将其初始化为零,它在分配内存块时会自动将内存中的每个字节都设置为零。

    函数原型:

    void *calloc(size_t numElements, size_t sizeOfElement);

    返回值说明:

    如果内存分配成功,返回一个 void 指针,指向新分配内存块的地址;如果分配失败(例如内存不足),返回一个空指针(NULL)。

    参数说明:numElements是要分配的元素的数量;sizeOfElement是每个元素的大小(以字节为单位)。

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int n = 5;
    // 两个参数:元素个数 每个元素占用字节
    int *array = (int *)calloc(n, sizeof(int));
    if (array == NULL)
    {
        printf("申请失败");
        return 1;
    }
    // 申请这块'地',地址信息
    printf("%p\n", array);
    for (int i = 0; i < n; i++)
    {
        array[i] = i * 20;
    }
    // 访问
    for (int i = 0; i < n; i++)
    {
        printf("%d\n", array[i]);
    }
    free(array);
    return 0;
}
  1. realloc() 函数:用于重新分配malloc() 或calloc() 函数所获得的内存块的大小。

    函数原型:

    void* realloc(void *ptr, size_t size);

    返回值说明:

    返回一个指向重新分配内存块的指针。如果内存重新分配成功,返回的指针可能与原始指针相同,也可能不同;如果内存分配失败,返回返回一个空指针(NULL)。

    如果在原内存块上进行缩减,通常返回的原先的地址。

    参数说明:ptr是要重新分配的内存块的指针;size是新的内存块的大小(以字节为单位)。

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main()
{
    // 申请一点空间
    int *ptr = (int *)malloc(400);
    // 判断一下
    if (ptr == NULL)
    {
        printf("申请失败");
        return 1;
    }
    // 成功开了400字节内存
    printf("%d\n", _msize(ptr));
    // 开辟空间不够--->800
    ptr = realloc(ptr, 8000);
    printf("%d\n", _msize(ptr));
    free(ptr);
    return 0;
}
  1. free()函数:

    如果动态分配的内存空间没有被正确释放,这种情况称为内存泄漏,内存泄漏会导致系统中的可用内存逐渐减少,直到耗尽系统可用的内存资源。

    free() 函数用于释放动态分配的内存,以便将内存返回给操作系统,防止内存泄漏。

    函数原型:

    void free(void *ptr);

    返回值说明:

    没有有返回值。

    参数说明:

    ptr是指向要释放的内存块的指针,ptr必须是malloc() 或calloc() 动态分配的内存块地址。

    注意:

    1. 分配的内存块一旦释放,就不应该再次操作已经释放的地址,也不应该再次使用 free() 对该地址释放第二次。

    2. 如果忘记调用free()函数,会导致无法访问未回收的内存块,构成内存泄漏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值