10天学会嵌入式技术之C语言-Day-9

C语言零基础入门:从环境搭建到项目实战的完整学习指南 C语言作为计算机编程的基石,其核心在于理解计算机底层逻辑与内存管理机制。通过掌握变量、函数、指针等基础概念,开发者能够深入理解程序在内存中的运行原理,从而编写高效、可控的系统级软件。这种能力对于嵌入式开发、操作系统、编译器等领域具有重要技术价值。在实际应用中,C语言常用于开发硬件驱动、实时系统和性能敏感的应用程序。本指南围绕C语言零基础学习,提供了从开发环境搭建、核心语法学习到项目实战的完整路径,特别针对指针和内存管理等难点进行了详细解析,并强调了调试工具的使用和常见错误排查,帮助初学者避开自学弯路,快速建 阅读详情

第十三章 自定义数据类型

13.1 枚举

13.3.1 什么是枚举

枚举(Enumeration)是 C 语言中的一种用户自定义数据类型,用于定义一组相关的常
量。枚举使我们可以为这些常量分配有意义的名字,从而提高代码的可读性和可维护性。
如果我们定义一个变量,用来表示一周中的一天,该变量的值只能从七个有效值中选择,
枚举可以帮助我们限制变量的有效值。

13.1.2 如何定义枚举

(1)语法格式

枚举使用 enum 关键字来定义,枚举名称和枚举元素名称都是标识符,定义一个枚举
就是定义了一种枚举数据类型,语法如下:

enum 枚举名称
{
    枚举元素 1,
    枚举元素 2,
    ...
    枚举元素 N
};

(2)枚举常量
        枚举元素也称为枚举成员或枚举常量,具有如下特点:
        1)枚举元素的值必须在同一枚举中是唯一的
        2)枚举元素的值必须是整数类型,通常是 int
        3)如果没有为枚举元素指定值,编译器会自动为它们分配值,从 0 开始,依次递增。
        4)定义枚举的时候也可以为枚举元素自定义值,需保证唯一性和整型类型。

(3)代码演示

// 定义枚举类型,表示星期一到星期天,枚举元素的值自动分配,从 0 到 6。
enum Weekday
{
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
};
// 定义枚举类型,表示一月到十二月。 给枚举元素 JANUARY 设置了值 1,后面的枚举元
//素从 1 开始自增,分别是 1 到 12
enum Month
{
    JANUARY = 1,
    FEBRUARY,
    MARCH,
    APRIL,
    MAY,
    JUNE,
    JULY,
    AUGUST,
    SEPTEMBER,
    OCTOBER,
    NOVEMBER,
    DECEMBER
};
// 定义枚举类型,表示北京地区一年四季的平均温度。为每个枚举元素都设置值,自己
//设置的值需要保证唯一性和整型类型

enum Season
{
    SPRING = 18,
    SUMMER = 30,
    AUTUMN = 20,
    WINTER = -5
};

13.1.3 枚举变量

(1)什么是枚举变量
定义变量时指定类型是我们所定义的枚举类型,该变量称为枚举变量。枚举变量的值应
该是枚举类型中的枚举常量中的一个,不能是其他值。
(2)定义枚举变量的语法
        

1)第一种:先定义枚举类型,再定义枚举变量。

// 定义枚举类型
enum DAY
{
    MON = 1,
    TUE,
    WED,
    THU,
    FRI,
    SAT,
    SUN
};
// 使用枚举类型定义枚举变量
enum DAY day;

2)第二种:定义枚举类型的同时声明枚举变量。

enum DAY
{
    MON = 1,
    TUE,
    WED,
    THU,
    FRI,
    SAT,
    SUN
} day;

3)第三种:定义枚举类型的同时声明枚举变量,且省略枚举名称。

enum
{
    MON = 1,
    TUE,
    WED,
    THU,
    FRI,
    SAT,
    SUN
} day;

(3)示例代码

#include <stdio.h>
int main()
{
    // 定义枚举类型
    enum Weekday
    {
        MONDAY,
        TUESDAY,
        WEDNESDAY,
        THURSDAY,
        FRIDAY,
        SATURDAY,
        SUNDAY
    };
// 定义枚举变量并赋值
    enum Weekday day = WEDNESDAY;
    printf("%d \n", day);
// 修改枚举变量的值
    day = FRIDAY;
    printf("%d \n", day);
// 修改枚举变量的值
// 100 并不是枚举常量中的一个,这样做虽然不会报错,但失去了枚举的意义,不
//建议这么做
    day = 100;
    printf("%d \n", day);
    return 0;
}

2
4
10

13.1.4 枚举的应用

如果枚举常量的值是连续的,我们可以使用循环遍历;如果枚举常量的值不是连续的,
则无法遍历

#include <stdio.h>
int main()
{
    // 定义枚举类型同时定义枚举变量
    enum Weekday
    {
    MONDAY = 1,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
    } day;
// 使用循环遍历出所有的枚举常量
    for (day = MONDAY; day <= SUNDAY; day++)
    {
    printf("%d \n", day);
    }
// 如果枚举常量的值并不是连续的数字,则无法遍历
// 定义枚举类型同时定义枚举变量
  enum Season
  {
    SPRING = 18,
    SUMMER = 30,
    AUTUMN = 20,
    WINTER = -5
  } season;
   for (season = SPRING; season <= WINTER; season++)
  {
    printf("%d \n", season);
  }
    return 0;
}

1
2
3
4
5
6
7

(2)枚举在 switch 中使用

枚举可以与 switch 结合使用,请看如下案例:

#include <stdio.h>
int main()
{
// 定义枚举类型
  enum SEASONS
 {
    SPRING = 1,
    SUMMER,
    AUTUMN,
    WINTER
 };
// 定义枚举变量
   enum SEASONS season;
// 获取用户输入
   printf("请输入你喜欢的季节: (1. spring, 2. summer, 3. autumn 4winter): ");
   
   scanf("%d", &season);
// 判断
   switch (season)
  {
    case SPRING:
        printf("你喜欢的季节是春天");
        break;
    case SUMMER:
        printf("你喜欢的季节是夏天");
        break;
    case AUTUMN:
        printf("你喜欢的季节是秋天");
        break;
    case WINTER:
        printf("你喜欢的季节是冬天");
        break;
    default:
        printf("你没有选择你喜欢的季节");
   }
    return 0;
}

13.2 结构体

13.2.1 为什么需要结构体

C 语言内置的数据类型,除了几种原始的基本数据类型,只有数组属于复合类型,可
以同时包含多个值,但是只能包含相同类型的数据,实际使用场景受限。

需求分析 1:

现有一个需求,编写学生档案管理系统,这里需要描述一个学生的信息。该学生的信息
包括学号、姓名、性别、年龄、家庭住址等,这些数据共同说明一个学生的总体情况。

需求分析 2;

隔壁老王养了两只猫咪,一只名字叫小黄,今年 2 岁,橘色;另一只叫小黑,今年 3 岁,
黑色。请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,年龄,颜色。如果
用户输入的小猫名错误,则显示老王没有这只猫。

传统的解决方法:
尝试 1:单独定义多个变量存储,实现需求,但是,多个变量,不便于数据的管理。
尝试 2:使用数组,它是一组具有相同类型的数据的集合。但在编程中,往往还需要一
组类型不同的数据,例如猫的名字使用字符串、年龄是 int,颜色是字符串,因为数据类型
不同,不能用一个数组来存放。
 

13.2.2 什么是结构体

C 语言提供了 struct 关键字,允许自定义复合数据类型,将不同类型的值组合在一起,
这种类型称为结构体(structure)类型。
C 语言没有其他语言的对象(object)和类(class)的概念,struct 结构很大程度上提供
了对象和类的功能。

13.2.3 声明结构体

(1)格式
构建一个结构体类型的一般形式为:

struct 结构体名
{
    数据类型 1 成员名 1;
    数据类型 2 成员名 2;
    ……
    数据类型 n 成员名 n;
}

(2)示例代码

1)举例:学生

// 定义结构体:学生
struct Student
{
    int id; // 学号
    int age; // 年龄
    char *name; // 姓名
    char gender; // 性别
    char *address; // 家庭住址
};

2)举例:通讯录
 

// 定义结构体:通讯录
struct Contacts
{
    char name[50]; //姓名
    int year; //年
    int month; //月
    int day; //日
    char email[100]; //电子邮箱
    char mobile_number[12]; //手机号
};

13.2.4 声明结构体的变量

(1)方式 1 先定义结构体,然后再创建结构体变量

// 定义结构体
struct Student
{
    int id; // 学号
    int age; // 年龄
    char *name; // 姓名
    char gender; // 性别
    char *address; // 家庭住址
};
// 定义结构体变量
struct Student stu1,stu2;

(2)方式 2 在定义结构体的同时定义结构体变量

// 定义结构体的同时定义 stu1 和 stu2 两个变量
struct Student
{
    int id; // 学号
    int age; // 年龄
    char *name; // 姓名
    char gender; // 性别
    char *address; // 家庭住址
} stu1, stu2;

(3)方式 3 在定义时也可以不给出结构体名

// 不给出结构体的名字
struct
{
    int id; // 学号
    int age; // 年龄
    char *name; // 姓名
    char gender; // 性别
    char *address; // 家庭住址
} stu1, stu2;

注意:在 C 语言中,结构体(struct)和结构体变量是两个不同的概念。
(1)结构体是一种自定义的数据类型,像一种模板,定义了数据的格式。
(2)结构体变量是根据结构体类型创建的变量,代表了一个具体的对象,用于存储数
据。

13.2.5 成员的获取和赋值

成员是结构体的一个组成部分,一般是基本数据类型、也可以是数组、指针、结构体等。
结构体的成员也可以称为属性。
结构体和数组类似,也是一组数据的集合,结构体使用点号 . 获取单个成员,可以进
行赋值和取值。

(1)案例 1:结构体成员逐个赋值

#include<stdio.h>

int main()
{
    //声明结构体
    struct Student
    {
        int id;
        int age;
        char *name;
        char *gender;
        char *address;

    };
//声明结构体变量
struct Student stu;

//对这个结构体成员进行赋值
    stu.id=1001;
    stu.age=19;
    stu.name="Jack";
    stu.gender='m';
    stu.address="chendu";
//获取成员值
    printf("id: %d \n", stu.id);
    printf("name: %s \n", stu.name);
    printf("age: %d \n", stu.age);
    printf("gender: %c \n", stu.gender);
    printf("address: %s \n", stu.address);

    return 0;
}

id: 1001
name: Jack Ma
age: 19
gender: m
address: Changping BeiJing

(2)案例2:使用大括号一次性对结构体所有成员赋值

#include<stdio.h>

int main()
{
    //声明结构体以及结构体变量,并且给结构体成员赋值
    struct Student 
    {
        int id;
        int age;
        char *name;
        char *gender;
        char *address;
     }stu1={002, 19, "Jim Liu", 'f', "Songjiang Shanghai"},stu2={1003, 16, "Tom Chen", 'm', "Baoan Shenzhen"};

    // 获取成员的值

        printf("id: %d \n", stu1.id);
    printf("name: %s \n", stu1.name);
    printf("age: %d \n", stu1.age);
    printf("gender: %c \n", stu1.gender);
    printf("address: %s \n \n", stu1.address);
    printf("id: %d \n", stu2.id);
    printf("name: %s \n", stu2.name);
    printf("age: %d \n", stu2.age);
    printf("gender: %c \n", stu2.gender);
    printf("address: %s \n", stu2.address);


    return 0;
}

id: 1002
name: Jim Liu
age: 19
gender: f
address: Songjiang Shanghai
id: 1003
name: Tom Chen
age: 16
gender: m
address: Baoan Shenzhen

13.2.6 结构体指针

(1)结构体指针介绍
结构体指针是指向结构体的指针变量,允许间接访问和操作结构体的成员,它提供了一
种方便的方式来处理结构体数据。
声明结构体指针的语法格式:

struct 结构体名 *结构体指针变量名;

(2)声明结构体指针

通常需要先定义一个结构体变量,再创建结构体指针,并取结构体变量的地址作为结构
体指针的值。

// 声明结构体
struct Student
{
    int id; // 学号
    int age; // 年龄
    char *name; // 姓名
    char gender; // 性别
    char *address; // 家庭住址
};
    // 声明结构体变量
struct Student stu;
// 声明结构体指针并初始化
struct Student *ptr = &stu;

(3)通过结构体指针访问成员

结构体指针可以通过“->” 操作符访问结构体的成员。

#include <stdio.h>
int main()
{
// 结构体
    struct Student
   {
     char *name;
     int age;
     char gender;
  };
// 结构体变量
  struct Student s = {"张三", 20, 'M'};
// 通过结构体变量访问成员
  printf("name=%s,age=%d,gender=%c \n", s.name, s.age, s.gender);
// 声明结构体指针
  struct Student *ps = &s;
// 结构体指针通过解引用访问成员
  printf("name=%s,age=%d,gender=%c\n", (*ps).name, (*ps).age,(*ps).gender);
// 结构体指针使用->访问成员
  printf("name=%s,age=%d,gender=%c\n", ps->name, ps->age,ps->gender);

 return 0;
}

name=张三,age=20,gender=M
name=张三,age=20,gender=M
name=张三,age=20,gender=M

总结:如果指针变量 p 指向一个结构体变量 stu,以下 3 种用法等价:
(1)stu.成员名
(2)(*p).成员名
(3)p->成员名

13.2.7 综合案例

(1)小狗案例
        1)编写一个 Dog 结构体,包含 name(char *)、age(int)、weight(double)属性。
        2)编写一个 say 函数,返回字符串,方法返回信息中包含所有成员值。                                          3)在 main 函数中,创建 Dog 结构体变量,调用 say 函数,将调用结果打印输出。

#include <stdio.h>
// 定义 Dog 结构体
struct Dog
{
    char *name;
    int age;
    double weight;
};
//  say函数,返回字符串,信息中包含所有成员值
 schar *say(struct Dog dog)ay
{
     // 将这个信息放入到一个字符串(字符数组)
     static char info[50]; // 局部静态变量
     sprintf(info, "name=%s age=%d weight=%.2f", dog.name, dog.age,
     dog.weight);
     dog.name = "小花";
     return info;
}
int main()
{
   // 测试
   // 定义结构体变量
    struct Dog dog;
    char *info = NULL;
    dog.name = "小黄";
    dog.age = 1;
    dog.weight = 3.4;
    info = say(dog); // 结构体变量默认是值传递
    printf("小狗信息:%s \n", info);
    printf("main 中小狗名字:%s \n", dog.name);

    return 0;
}

(2)盒子案例

     1)编程创建一个 Box 结构体,在其中定义三个成员表示一个长方体的长、宽和高,
长宽高可以通过控制台输入。
   2)定义一个函数获取长方体的体积(volume)。                                                                             3)创建一个结构体指针,打印给定尺寸的长方体的体积。

#include <stdio.h>
// 定义 Box 结构体
struct Box
{
    double length;
    double width;
    double height;
};
// 获取立方体体积的函数
double getVolume(struct Box *box)
{
    return box->length * box->width * box->height;
}

int main()
{
/ 创建结构体变量
    struct Box box;
// 创建结构体指针
    struct Box *cube = &box;

    printf("Enter length: ");
    scanf("%lf", &cube->length);

    printf("Enter width: ");
    scanf("%lf", &cube->width);

    printf("Enter height: ");
    scanf("%lf", &cube->height);
// 调用函数获取体积并打印
    printf("Volume is: %.2f\n", getVolume(cube));

    return 0;
}

3)景区门票案例

 1)一个景区根据游人的年龄收取不同价格的门票。
 2)请编写游人结构体(Visitor),根据年龄段决定能够购买的门票价格并输出。                           3)规则:年龄>18,门票为 20 元,其它情况免费。
 4)可以循环从控制台输入名字和年龄,打印门票收费情况,如果名字输入 n,则退
出程序。

#include <stdio.h>
#include <string.h>
// 定义结构体
struct Visitor
{
    char name[10];
    int age;
    double pay; // 应付票价
}
// 编写函数处理业务
void ticket(struct Visitor *visitor)
{
// 判断
    if (visitor->age > 18)
    {
        visitor->pay = 20;
    }
    else
    {
        visitor->pay = 0;
    }
}

int main()
{
// 测试
// 创建结构体变量(创建一个游客)
    struct Visitor visitor;
// 循环的输入名字和年龄
    while (1)
    {
        printf("\n 请输入游客名字:");
        scanf("%s", visitor.name);
// 判断如果名字输入 n ,则退出程序
    if (!strcmp("n", visitor.name))
    {
    break;
    }    
    printf("\n 请输入游客年龄:");
    scanf("%d", &visitor.age);
// 调用函数 ticket , 获取应付的票价
    ticket(&visitor);
    printf("\n 该游客应付票价:%.2f\n", visitor.pay);
}

    printf("退出程序");

    return 0;
}

13.2.8 总结

区分三个概念:结构体、结构体变量、结构体变量的成员。
结构体是自定义的数据类型,表示的是一种数据类型。结构体变量代表一个具体变量。
类比

int num1; // int 是数据类型, 而 num1 是一个具体的 int 变量
struct Car car1; // Car 是结构体数据类型,而 car1 是一个 Car 变量

13.3 共用体

有时需要一种数据结构,不同的场合表示不同的数据类型。比如,如果只用一种数据结
构表示学生的“成绩”,这种结构就需要有时是整数(80、90),有时是字符('A'、'B'),
有时是浮点数(80.5、60.5)。
C 语言提供了共用体类型(Union 结构),用来自定义可以灵活变更的数据结构。它内
部可以包含各种属性,但同一时间只能有一个属性,因为所有属性都保存在同一个内存地址,
后面写入的属性会覆盖前面的属性。这样做的最大好处是节省空间。
“共用体”与“结构体”的定义形式相似,但它们的含义是不同的。
(1)结构体变量所占内存长度,可以认为是各成员占的内存长度的叠加;每个成员分
别占有其自己的内存单元。
(2)共用体变量所占的内存长度等于最长的成员的长度;几个成员共用一个内存区。

13.3.2 声明共用体

(1)格式:

union 共用体类型名称
{
    数据类型 成员名 1;
    数据类型 成员名 2;
    …
    数据类型 成员名 n;
};

(2)举例:

union data
{
    int m;
    float x;
    char c;
};

上例中,union 命令定义了一个包含三个属性的数据类型 data。虽然包含三个属性,但
是同一时间只能取到一个属性。最后赋值的属性,就是可以取到值的那个属性。

13.3.3   声明共用体变量   

  ( 1)方式 1:先定义共用体类型,再定义共用体变量

// 声明共用体类型
union data
{
    short m;
    float x;
    char c;
};
// 声明共用体变量
union data a, b;

(2)方式 2:定义共用体类型的同时定义共用体变量

union data
{
    short m;
    float x;
    char c;
} a, b;

3)方式 3:在定义时也可以不给出共用体名

union
{
    short m;
    float x;
    char c;
} a, b;

13.3.4 共用体内存分析


  以上一节方式 2 中共用体变量 a 为例,它由 3 个成员组成,分别是 m、x 和 c,系统会
按照最长的成员为它分配内存,由于成员 x 的长度最长,它占 4 个字节,所以共用体变量 a
的内存空间也为 4 个字节。                                                                                                                                                            

13.3.5 成员的获取和赋值                                                                                                   

同结构体一样,共用体也使用点号.获取单个成员,可以进行赋值和取值。
                                                                                                                                                           

//方式一:
union data a;
a.c = 4;
//方式二:声明共用体变量的同时,给任一成员赋值
union data a = {.c = 4};
方式三:声明共用体变量的同时,给首成员赋值
union data a = {8};

 注意:方式 3 不指定成员名,所以只能为第一个成员进行赋值                                                                                                                   

13.3..6案例

现有一张关于学生信息和教师信息的表格。学生信息包括姓名、编号、性别、职业、
分数,教师的信息包括姓名、编号、性别、职业、教学科目:可以参考下面的表格。
请利用共用体,只使用一个结构体保存每个人的信息。

#include <stdio.h>
#define TOTAL 2 // 人员总数

// 定义了一个结构体 Person
struct Person
    {
      char name[20]; // name
      int num; // 编号
      char sex; // 性别 f => 女 m=>男
      char profession; // 职业 s=>学生 t=>老师
      union
        {
          float score;
          char course[20];
        } sc; // sc 是一个共用体变量
    };

int main()
{
int i;
struct Person persons[TOTAL]; // 定义了一个结构体数组

// 输入人员信息
    for (i = 0; i < TOTAL; i++)
    {
        printf("Input info: ");
        scanf("%s %d %c %c", persons[i].name, &(persons[i].num), &(persons[i].sex), &(persons[i].profession));
        if (persons[i].profession == 's')
         { 
           // 如果是学生
            printf("请输入该学生成绩:");
            scanf("%f", &persons[i].sc.score);
        }
        else
        {
             // 如果是老师
            printf("请输入该老师课程:");
            scanf("%s", persons[i].sc.course);
        }
        fflush(stdin); // 刷新
}

    // 输出人员信息
    printf("\nName\t\tNum\tSex\tProfession\tScore / Course\n");

     for (i = 0; i < TOTAL; i++)
      {
         // 如果是学生
        printf("%s\t\t%d\t%c\t%c\t\t%f\n", persons[i].name,persons[i].num, persons[i].sex, persons[i].profession,persons[i].sc.score);
      }
      else
      { 
            // 如果是老师
        printf("%s\t\t%d\t%c\t%c\t\t%s\n", persons[i].name,
        persons[i].num, persons[i].sex, persons[i].profession,
        persons[i].sc.course);
        }
    }

   return 0;
}

13.4 typedef 

13.4.1 typedef 介绍

C 语言允许为一个数据类型起一个新的别名,就像给人起“绰号”一样。
起别名的目的不是为了提高程序运行效率,而是为了编码方便。例如,有一个结构体的
名字是 student,定义一个结构体变量 stu1,代码如下:

struct student stu1;

struct 看起来就是多余的,但不写又会报错。如果为 struct student 起了一个别名 Student,
书写起来就简单了

Student stu1;

这种写法更加简练,意义也非常明确,不管是在标准头文件中还是以后的编程实践中,
都会大量使用这种别名。

13.4.2 typedef 应用场景

用 typedef 声明数组类型、指针类型,结构体类型、共用体类型等,使得编程更加方便。

(1)为某个基本类型起别名

        typedef 命令用来为某个类型起别名。

typedef 类型名 别名;

习惯上,常把用 typedef 声明的类型名的第 1 个字母用大写表示,以便与系统提供的标
准类型标识符相区别。

代码示例:

typedef int Integer;//用 Integer 作为 int 类型别名,作用与 int 相同
Integer a,b;
a=1;
b=2;

typedef unsigned char Byte;//为类型 unsign char 起别名 Byte
Byte c = 'z';

注意:使用 typedef 可以为基本类型一次起多个别名。

typedef int chocolate, doughnut, mushroom; //一次性为 int 类型起了三个别名

(2)为结构体、共用体起别名

为 struct、union 等命令定义的复杂数据结构创建别名,从而便于引用

struct Treenode
{
    // ...
};

typedef struct Treenode Tree;//Tree 是 struct Treenode 的别名

typedef 也可以与 struct 定义结构体的命令写在一起。

typedef struct Treenode
{
    char *name;
    int legs;
    int speed;
} Tree;

上例中,自定义数据类型时,同时使用 typedef 命令,为 struct Treenode 起了一个别名
Tree。

这种情况下,C 语言允许省略结构体名。

typedef struct
{
    char *name;
    int legs;
    int speed;
} Tree;

上例相当于为一个匿名的结构体起了别名 Tree,进而:

// 使用 typedef 之前
struct Treenode tr;

// 使用 typedef 之后
Tree tr;

再举例:typedef 命令可以为共用体起别名。

typedef union
{
    short count;
    float weight;
    float volume;
} Quantity;

上例中,union 命令定义了一个包含三个属性的数据类型,typedef 命令为它起别名为
Quantity。

(3)为指针起别名
typedef 可以为指针起别名。

typedef int *intptr;
int a = 10;
intptr x = &a;

上例中,intptr 是 int*的别名。不过,使用的时候要小心,这样不容易看出来,变量 x
是一个指针类型。
再举例:

typedef char *String;
char *str1 = "hello"; // 之前的写法
String str2 = "hello"; // 现在的写法

为字符指针起别名为 String,以后使用 String 声明变量时,就可以轻易辨别该变量是字
符串。
(4)为数组类型起别名
typedef 也可以用来为数组类型起别名。

/ 举例 1 给 int[5] 取别名 fiveInts
    typedef int fiveInts[5];
    fiveInts x = {11, 22, 33, 44, 55}; // 相当于 int x[5] = {11, 22, 33, 44,55};

// 举例 2 给 int[100] 取别名 Num
typedef int Num[100]; // 声明 Num 为整型数组类型名
Num a;        // 相当于 int a[100];

举例,使用 typedef 为数组指针取别名。

// 为 int (*)[5] 取别名为 IntArrayPointer
    typedef int (*IntArrayPointer)[5];
// 定义数组
    int arr[5] = {1, 2, 3, 4, 5};
// 使用别名定义数组指针
    IntArrayPointer ptr = &arr; // 使用别名指向数组

13.4.3 综合使用演示

#include <stdio.h>
// 给字符指针取别名
typedef char *String;

// 给结构体取别名
typedef struct
{
    int id;
    String name;
    String profile;
} User;
int main()
{
// 声明一个结构体变量
    User u;

    // 初始化结构体变量的属性赋值
    u.id = 101;
    u.name = "张三";
    u.profile = "一个纯粹的人,一个高尚的人,一个脱离了低级趣味的人。";

    // 打印结构体变量的属性
    printf("id:%d\n", u.id);
    printf("name:%s\n", u.name);
    printf("profile:%s\n", u.profile);
    
    return 0;
}

id:101
name:张三
profile:一个纯粹的人,一个高尚的人,一个脱离了低级趣味的人。

内网(极空间)搭建gitlab跳板机转发端口及域名配置 然后,回头尝试用内网地址+15022 clone,成功,用公网的ip+15222 clone失败,那就是定位到时nginx转发的问题了。首先想到的就是 git clone是通过ssh的22端口进行下载的,那就需要打通22端口,则又配置22端口的nginx转发。然后,我通过ssh命令,做一个端口转发,以实现内网穿透,将服务端口链接到跳板机上。然后穿透到阿里云服务器跳板机的端口,只能内网访问,需要用nginx做个转发,才能用公网ip进行访问。然后,如上,我的80端口,映射15080,22端口映射15022。 阅读详情

相关推荐

从理论到实践:基于Zemax的高分辨率生物显微镜光学系统仿真与优化指南

本文详细介绍了基于Zemax的高分辨率生物显微镜光学系统仿真与优化全流程。从阿贝分辨率公式、柯勒照明等理论基础出发,逐步讲解Zemax建模、像差优化、制造可行性分析等核心步骤,并提供常见问题解决方案。通过实际案例展示如何将理论设计转化为可制造的优化方案,帮助工程师掌握从仿真到实际应用的关键技术。

weixin_29229989的博客 482

嵌入式之 9天掌握C语言(1)Linux环境搭建

安装完虚拟机后就可以进行远程开发了。 点击创建虚拟机 选择 ->典型 确定 稍后安装操作系统 选择客户机操作系统: linux 版本: Ubuntu 下一步 虚拟机的名称 自己命名(英文) 虚拟机位置: 必须新建一个文件夹,必须有10G的空间来存放虚拟机 下一步 指定磁盘容量:最大磁盘大小 20G 将虚拟机磁盘拆分成多个文...

weixin_38787597的博客 364

Win10下ISE14.7安装避坑全记录:从License加载失败到ChipScope连不上,我踩过的雷都在这了

本文详细记录了在Win10系统下安装ISE14.7时遇到的常见问题及解决方案,包括License加载失败、IMPACT闪退、ChipScope连接故障等。通过实际案例和步骤解析,帮助用户避开安装陷阱,确保FPGA开发工具顺利运行。特别针对license问题提供了兼容性设置和文件修改的实用技巧。

weixin_42683394的博客 225

嵌入式学习之路(九)——C语言学习(4)

嵌入式学习之路(九)——C语言学习(4) 1.接着我们上次的讲:每个字节有自己的地址,不同的字节地址不同,变量的地址就是它所对应的字节中最前边的那个字节的地址。 2.sizeof关键字可以用来计算一个变量或一个数据类型到底占多少个字节,它只是一个关键字不是函数,sizeof可以用来计算一个变量或者一个数据类型到底占多少个字节

紫瞳标的专栏 794

保姆级教程:在树莓派4B上用V4L2驱动USB摄像头(附完整代码)

本文提供树莓派4B上使用V4L2驱动USB摄像头的完整教程,涵盖环境配置、V4L2架构解析、代码实现及问题排查。通过详细步骤和完整代码示例,帮助开发者快速掌握嵌入式Linux下的摄像头驱动开发,解决实际应用中的兼容性和性能问题。

weixin_30312563的博客 382

Blender SMPL-X 插件安装

Blender XMPL-X 插件安装

heleneveryday的专栏 5358

10天学会嵌入式技术之C语言-day-5

手把手入行嵌入式之10天学会C语言day-5

2301_80748708的博客 1426

TVS 管击穿电压与钳位电压的工程解析

TVS二极管的核心参数击穿电压(VBR)和钳位电压(VC)常被混淆,但二者具有本质区别。VBR是

硬核科技 480

10天学会嵌入式技术之C语言-day-2

手把手入行嵌入式之10天学会C语言day-2

2301_80748708的博客 947

Orange3实战教程:文本挖掘---主题建模

主题建模通过LDA、LSI或HDP算法分析文档集合,自动发现隐含主题结构。组件输入为文档语料库,输出包括带主题权重的语料库、主题词分布及完整主题数据。不同算法特性各异:LSI允许正负权重但解释性较弱,LDA更易解释,HDP参数复杂需谨慎设置。结果可结合词云、热力图等可视化工具分析主题特征及分布。示例显示如何通过预处理文本、选择算法(如提取5个LDA主题),并利用MDS和箱线图探索主题间关系及关键词分布。

err2008的专栏 362

《C++等级认证CCF-GESP真题解析》专栏总目录

❤️ 专栏名称:《C++等级认证CCF-GESP真题解析》🌸 专栏介绍:中国计算机学会GESP《CCF编程能力等级认证》C++编程(1~8级)历届真题解析。🚀 订阅专栏:订阅后可阅读专栏内所有真题解析,真题持续更新中,欢迎订阅!

人生就是一个不断学习的过程 6288

10天学会嵌入式技术之51单片机-day-1

手把手入行嵌入式之10天学会51单片机day-1

2301_80748708的博客 1332

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

5天学会Linux C高级

软件名_版本号.次版本号-修订次数_架构.后缀函数是一个完成特定功能的代码模块,其程序代码独立变量名=值val=10注:等号两边都不能有空格。CC=gcc取shell变量的值:$变量名在shell编程中通常定义的变量名用大写,变量的调用:$变量名Linux Shell/bash从右向左赋值如:Y=yyX=$Yecho $X //输出yy使用unset命令删除变量的赋值如:X=xxunset Xecho $X //没有任何输出。

qq_52049228的博客 1590

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

5天零基础通关嵌入式C语言:敲开万亿IoT与工业嵌入式赛道的核心大门

与 const。

从零开始,掌握网络安全。提供全面的网络安全教程、攻防演练技巧和行业动态。 269

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain&#39;s apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath(&#39;DeepLearnToolbox&#39;));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand(&#39;state&#39;,0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W&#39;); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand(&#39;state&#39;,0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = &#39;sigm&#39;;%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, &#39;Too big error&#39;);```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand(&#39;state&#39;,0)sae = saesetup([784 100]);sae.ae{1}.activation_function = &#39;sigm&#39;;sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)&#39;)% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = &#39;sigm&#39;;nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, &#39;Too big error&#39;);```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x&#39;,28,28,60000))/255;test_x = double(reshape(test_x&#39;,28,28,10000))/255;train_y = double(train_y&#39;);test_y = double(test_y&#39;);%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you&#39;ll get around 1.2% errorrand(&#39;state&#39;,0)cnn.layers = { struct(&#39;type&#39;, &#39;i&#39;) %input layer struct(&#39;type&#39;, &#39;c&#39;, &#39;outputmaps&#39;, 6, &#39;kernelsize&#39;, 5) %convolution layer struct(&#39;type&#39;, &#39;s&#39;, &#39;scale&#39;, 2) %sub sampling layer struct(&#39;type&#39;, &#39;c&#39;, &#39;outputmaps&#39;, 12, &#39;kernelsize&#39;, 5) %convolution layer struct(&#39;type&#39;, &#39;s&#39;, &#39;scale&#39;, 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, &#39;Too big error&#39;);```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, &#39;Too big error&#39;);%% ex2 neural net with L2 weight decayrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex3 neural net with dropoutrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex4 neural net with sigmoid activation functionrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.activation_function = &#39;sigm&#39;; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex5 plotting functionalityrand(&#39;state&#39;,0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = &#39;softmax&#39;; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand(&#39;state&#39;,0)nn = nnsetup([784 20 10]); nn.output = &#39;softmax&#39;; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

21天学会C++_Day1----C++的发展史

C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(object oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。

金哥的博客 896

C语言30天实战:从零基础到项目驱动,掌握核心生产力与接单能力

C语言作为计算机编程的基石,其核心价值在于对底层内存管理和系统资源的直接控制能力。通过理解指针、内存分配等基础原理,开发者能够构建高效的软件系统,尤其在嵌入式开发、操作系统和性能敏感领域具有不可替代的技术优势。掌握C语言不仅能够培养扎实的编程思维,还能为从事系统级开发和高性能应用打下坚实基础。本文以项目驱动和问题解决为导向,通过构建学生信息管理系统等实战案例,帮助学习者将语法知识转化为解决实际问题的能力,并自然融入动态内存管理和文件操作等关键热词,为初学者提供一条清晰的学习路径和就业准备指南。

weixin_30247781的博客 457

C语言30天速通:零基础到项目实战与就业接单指南

C语言作为一门经典的编程语言,其核心价值在于提供了对计算机底层内存和硬件的直接控制能力,是理解计算机系统原理和进行系统级开发的基石。从语法基础到指针、内存管理等核心概念,其学习路径遵循从基础到进阶的工程实践逻辑。掌握C语言不仅能构建扎实的编程思维,更是进入嵌入式开发、操作系统、高性能计算等核心领域的关键。对于初学者而言,一套结构清晰、注重实战的学习方案至关重要。本文聚焦于【30天速通】与【实战项目】两大核心,提供了一条从零基础到具备完成控制台应用、管理文件数据、进行动态内存分配等能力的系统化路径。该路径通过

weixin_30820077的博客 423

面试最新经典100题,10天学会kotlin DAY5 初始化块,腾讯android面试题社招

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。最后针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!本文已被。

2401_83977554的博客 1019

嵌入式C语言指针核心解析:从内存地址到寄存器操作

内存地址是C语言中连接软件与硬件的关键抽象。指针作为地址的直接载体,决定了程序如何访问数据、传递参数以及控制硬件资源。在嵌入式开发中,寄存器操作、数组遍历、函数传参等都离不开指针的准确运用。从基础的内存模型出发,解析指针的定义、步长、与数组的关系,并结合GPIO控制、位带操作等实际场景,说明如何通过指针直接读写物理寄存器。理解指针背后的地址运算与类型语义,是编写高效驱动和调试底层异常的前提。最后以函数指针和const限定为例,展示指针在工程中的高级用法,帮助开发者从语法层面深入到底层逻辑。

weixin_28744423的博客 231

【0基础嵌入式学习日志】Day08:配置头文件 config.h、阈值宏管理与消除魔法数字

所谓魔法数字,就是直接写在代码里的固定数字。这里的60.0f是什么意思?过温故障判断阈值这里的9.5f表示模拟传感器电压值,但是如果没有命名说明,代码可读性就比较差。1. 可读性差:不知道数字代表什么含义;2. 修改麻烦:后期要改参数时,需要在多个 .c 文件里查找;3. 容易出错:多个位置写同一个参数时,可能漏改或改错。因此,在工程中更推荐使用有意义的宏名来代替这些数字。理解了什么是魔法数字;理解了魔法数字会降低代码可读性和可维护性;学会了使用config.h统一管理工程配置参数;

duhong2026的博客 302

28天 从0开始学Java Day1 第1章 Java概述

Java诞生于SUN(Stanford University Network),09年SUN被Oracle(甲骨文)收购。Java之父是詹姆斯.高斯林(James Gosling)。Java大约26岁,我们使用的版本是Java8,最新版本Java19,最新的长期支持版本(可以用于开发的版本)是Java17.发行版本发行时间备注Java1995.05.23Sun(Stanford University Network)公司在Sun world会议上正式发布Java和HotJava浏览器。

leader_song的博客 972

C语言入门后如何实践:从语法到项目开发的思维跃迁

C语言作为一门经典的过程式编程语言,其核心价值在于培养开发者贴近机器的思考方式和问题拆解能力。理解其基本原理,如指针的本质是内存地址的导航、程序从编译到链接的完整工作流,是掌握系统编程和底层开发的关键。这种能力在嵌入式开发、操作系统内核及高性能服务等场景中具有不可替代的技术价值。本文聚焦如何将C语言基础转化为工程实践,通过具体项目如命令行工具和终端小游戏的开发,深化对内存管理、字符串处理及模块化编程的理解,帮助学习者跨越从“认识语法”到“解决实际问题”的鸿沟。

weixin_33874713的博客 484

写给三弟的 C语言编程 快速入门

三弟,你要的C语言快速入门,已整理好 请接收。

码刀攻城 3935

嵌入式学习Day5(流程控制)

Tip:刚开始学习嵌入式的宝子要在这个阶段学会画流程图,这对我们锻炼代码思维有很大的帮助;一.选择结构(if语句/switch语句)1.选择时应有的判断条件关系运算(>/>=/</<=/==/!=)关系成立 --- 关系真;关系不成立 --- 关系假逻辑运算:将多个表达式关联起来,反映表达式与表达式之间的逻辑关系与(&&) 运算规则:一假则假: a&&b特性:截断特性,运算顺序一定是先执行左边的,若左边已判断为假,则不继续执行右边的表达式。

qq_65055202的博客 375

苏嵌学习日志day1

Day1 name:钱成杰 date:2018.9.10 今日学习任务 先安装了软件,初步学习了嵌入式开发环境,复习C语言指针,数组字符串的相关知识。 今日任务完成情况 上课时基本能跟上老师教学进度,完成程序的编写。完成老师所布置的课后作业。今日开发中出现的问题汇总 ,对C语言还不够熟练,很多函数用法不会用, 今日开发中出现的问题汇总 跟着老师学习编简单的程序,还是有一...

Q_patience的博客 215

C语言:结构体

结构体的定义使用structint age;float gpa;注意:上面的代码只是定义了一个“模板”,只是一种类型,比如int,char等只是一个类型。

2501_93249729的博客 378
上一篇: 10天学会嵌入式技术之c语言-Day-8
下一篇: 10天学会嵌入式技术之c语言-Day-10
昊昊昊昊昊明
博客等级 码龄3年 285粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值