目录
1 typedef 介绍
2 为某个基本类型起别名
2.1 为 int 类型起别名 Integer
2.2 为 unsigned char 类型起别名 Byte
2.3 为基本类型一次起多个别名
3 为结构体、共用体起别名
3.1 为结构体起别名
3.1.1 分开定义结构体和别名
3.1.2 与结构体定义一起使用 typedef
3.1.3 为匿名结构体起别名
3.2 为共用体起别名
4 为指针起别名
4.1 为 int* 起别名 intptr
4.2 为 char* 起别名 String
5 为数组起别名
5.1 为数组类型起别名
5.2 为数组指针取别名
6 综合案例
1 typedef 介绍
C 语言允许为一个数据类型起一个新的别名,就像给人起“绰号”一样。起别名的目的不是为了提高程序运行效率,而是为了编码方便。例如,有一个结构体的名字是 Student,定义一个结构体变量 stu1,代码如下:
struct Student stu1;
struct 看起来多余,但不写又会报错。如果为 struct Student 起一个别名 Student,书写起来就简单了:
typedef struct Student Student;
Student stu1;
这种写法更加简练,意义也非常明确,不论是在标准头文件中还是在以后的编程实践中,都会大量使用这种别名。
2 为某个基本类型起别名
typedef 命令可以用来为某个类型起别名。
typedef 类型名 别名;
习惯上,常把用 typedef 声明的类型名的第 1 个字母用大写表示,以便与系统提供的标准类型标识符相区别。
2.1 为 int 类型起别名 Integer
#include <stdio.h>// 为 int 类型起别名 Integer
typedef int Integer;int main()
{// 声明并初始化两个 Integer 类型的变量Integer a, b;a = 1;b = 2;// 打印变量的值printf("a: %d\n", a); // a: 1printf("b: %d\n", b); // b: 2return 0;
}
2.2 为 unsigned char 类型起别名 Byte
#include <stdio.h>// 为类型 unsigned char 起别名 Byte
typedef unsigned char Byte;int main()
{// 声明并初始化一个 Byte 类型的变量Byte c = 'z';// 打印变量的值printf("c: %c\n", c); // 以字符形式打印 c: zprintf("ASCII value of c: %u\n", c); // 以无符号整数形式打印 ASCII 值 ASCII value of c: 122return 0;
}
2.3 为基本类型一次起多个别名
#include <stdio.h>// 为 int 类型一次性起三个别名
typedef int chocolate, doughnut, mushroom;// 为其他基本数据类型起别名
typedef unsigned char Byte;
typedef float Real;
typedef double Double;int main()
{// 声明并初始化 int 类型的别名变量chocolate choco = 10;doughnut donut = 20;mushroom mush = 30;// 打印变量的值printf("chocolate: %d\n", choco); // 10printf("doughnut: %d\n", donut); // 20printf("mushroom: %d\n", mush); // 30// 声明并初始化其他基本数据类型的别名变量Byte b = 'A';Real r = 3.14f;Double d = 2.71828;// 打印变量的值printf("Byte: %c\n", b); // Aprintf("Real: %f\n", r); // 3.140000printf("Double: %lf\n", d); // 2.718280return 0;
}
3 为结构体、共用体起别名
typedef 命令可以为 struct、union 等命令定义的复杂数据结构创建别名,从而便于引用。
3.1 为结构体起别名
3.1.1 分开定义结构体和别名
#include <stdio.h>// 定义结构体 Treenode
struct Treenode
{char *name; // 树的名称int legs; // 树的腿数int speed; // 树的速度
};// 为 struct Treenode 起别名 Tree
typedef struct Treenode Tree;int main()
{// 声明一个 Tree 类型的变量Tree t;// 初始化结构体变量的属性t.name = "Oak"; // 名称t.legs = 0; // 树没有腿t.speed = 0; // 树不能移动// 打印结构体变量的属性printf("Name: %s\n", t.name); // Oakprintf("Legs: %d\n", t.legs); // 0printf("Speed: %d\n", t.speed); // 0return 0;
}
3.1.2 与结构体定义一起使用 typedef
#include <stdio.h>// 定义结构体 Treenode 并同时为它起别名 Tree
typedef struct Treenode
{char *name; // 树的名称int legs; // 树的腿数int speed; // 树的速度
} Tree;int main()
{// 声明一个 Tree 类型的变量Tree t;// 初始化结构体变量的属性t.name = "Oak"; // 名称t.legs = 0; // 树没有腿t.speed = 0; // 树不能移动// 打印结构体变量的属性printf("Name: %s\n", t.name); // Oakprintf("Legs: %d\n", t.legs); // 0printf("Speed: %d\n", t.speed); // 0return 0;
}
3.1.3 为匿名结构体起别名
#include <stdio.h>// 为一个匿名结构体起别名 Tree
typedef struct
{char *name; // 树的名称int legs; // 树的腿数int speed; // 树的速度
} Tree;int main()
{// 声明一个 Tree 类型的变量Tree t;// 初始化结构体变量的属性t.name = "Oak"; // 名称t.legs = 0; // 树没有腿t.speed = 0; // 树不能移动// 打印结构体变量的属性printf("Name: %s\n", t.name); // Oakprintf("Legs: %d\n", t.legs); // 0printf("Speed: %d\n", t.speed); // 0return 0;
}
3.2 为共用体起别名
#include <stdio.h>// 为 union 起别名 Quantity
typedef union
{short count; // 计数float weight; // 重量float volume; // 体积
} Quantity;int main()
{// 声明一个 Quantity 类型的变量Quantity q;// 初始化共用体变量的属性q.count = 10; // 设置计数// 打印共用体变量的计数值printf("Count: %hd\n", q.count); // 10// 重新设置共用体变量的属性q.weight = 5.5; // 设置重量// 打印共用体变量的重量值printf("Weight: %.2f\n", q.weight); // 5.50// 重新设置共用体变量的属性q.volume = 2.718; // 设置体积// 打印共用体变量的体积值printf("Volume: %.3f\n", q.volume); // 2.718// 注意:由于共用体共享同一块内存,最后一次赋值会覆盖之前的值printf("Count (after setting volume): %hd\n", q.count); // -3146(数据溢出与补码存储原理)printf("Weight (after setting volume): %.3f\n", q.weight); // 2.718return 0;
}
4 为指针起别名
typedef 可以为指针类型起别名,使代码更加简洁和易读。然而,使用指针别名时要小心,因为这可能会使代码的可读性降低,特别是当变量类型不明显时。
4.1 为 int* 起别名 intptr
#include <stdio.h>// 为 int* 类型起别名 intptr
typedef int *intptr;int main()
{// 声明一个 int 类型的变量int a = 10;// 声明一个 intptr 类型的变量,并初始化为 a 的地址intptr x = &a;// 打印变量 a 的值printf("Value of a: %d\n", a); // 10// 打印变量 x 的值(即 a 的地址)printf("Address of a (stored in x): %p\n", (void *)x);// 通过指针 x 修改变量 a 的值*x = 20;// 再次打印变量 a 的值printf("New value of a: %d\n", a); // 20return 0;
}
intptr 是 int* 的别名。虽然这样写可以使代码更简洁,但需要注意 x 是一个指针类型,以免引起混淆。
4.2 为 char* 起别名 String
#include <stdio.h>// 为 char* 类型起别名 String
typedef char *String;int main()
{// 之前的写法char *str1 = "hello";// 现在的写法String str2 = "hello";// 打印字符串printf("str1: %s\n", str1); // str1: helloprintf("str2: %s\n", str2); // str2: helloreturn 0;
}
String 是 char* 的别名。使用 String 声明变量时,可以更容易地识别该变量是一个字符串指针。
5 为数组起别名
typedef 也可以用来为数组类型起别名,使代码更加简洁和易读。
5.1 为数组类型起别名
#include <stdio.h>// 为 int[5] 类型起别名 fiveInts
typedef int fiveInts[5];// 为 int[100] 类型起别名 Num
typedef int Num[100];// 为 double[10] 类型起别名 DoubleArray
typedef double DoubleArray[10];// 为 char[20] 类型起别名 CharArray
typedef char CharArray[20];int main()
{// 声明并初始化一个 fiveInts 类型的数组fiveInts x = {11, 22, 33, 44, 55};// 打印 fiveInts 数组的内容printf("fiveInts array x:\n");for (int i = 0; i < 5; i++){printf("%d ", x[i]); // 11 22 33 44 55}printf("\n");// 声明一个 Num 类型的数组Num a;// 初始化 Num 数组for (int i = 0; i < 100; i++){a[i] = i;}// 打印 Num 数组的部分内容printf("Num array a (first 10 elements):\n");for (int i = 0; i < 10; i++){printf("%d ", a[i]); // 0 1 2 3 4 5 6 7 8 9}printf("\n");// 声明并初始化一个 DoubleArray 类型的数组DoubleArray db = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.0};// 打印 DoubleArray 数组的内容printf("DoubleArray array db:\n");for (int i = 0; i < 10; i++){printf("%.2f ", db[i]); // 1.10 2.20 3.30 4.40 5.50 6.60 7.70 8.80 9.90 10.00}printf("\n");// 声明并初始化一个 CharArray 类型的数组CharArray ch = "Hello, World!";// 打印 CharArray 数组的内容printf("CharArray array ch: %s\n", ch); // Hello, World!return 0;
}
5.2 为数组指针取别名
#include <stdio.h>// 为 int (*)[5] 取别名为 IntArrayPointer
typedef int (*IntArrayPointer)[5];// 为 double (*)[10] 取别名为 DoubleArrayPointer
typedef double (*DoubleArrayPointer)[10];// 为 char (*)[20] 取别名为 CharArrayPointer
typedef char (*CharArrayPointer)[20];int main()
{// 定义 int 类型的数组int arr[5] = {1, 2, 3, 4, 5};// 使用别名定义数组指针IntArrayPointer ptr = &arr;// 打印 int 数组的内容printf("int array arr:\n");for (int i = 0; i < 5; i++){printf("%d ", (*ptr)[i]); // 1 2 3 4 5}printf("\n");// 定义 double 类型的数组double dbl_arr[10] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.0};// 使用别名定义数组指针DoubleArrayPointer dbl_ptr = &dbl_arr;// 打印 double 数组的内容printf("double array dbl_arr:\n");for (int i = 0; i < 10; i++){printf("%.1f ", (*dbl_ptr)[i]); // 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 10.0}printf("\n");// 定义 char 类型的数组char char_arr[20] = "Hello, World!";// 使用别名定义数组指针CharArrayPointer char_ptr = &char_arr;// 打印 char 数组的内容printf("char array char_arr: %s\n", *char_ptr); // Hello, World!return 0;
}
6 综合案例
#include <stdio.h>
#include <string.h>// 为基本数据类型起别名
typedef int Integer;
typedef float Real;
typedef char Character;
typedef char *String;// 为结构体起别名
typedef struct
{char name[50];int age;
} Person;// 为共用体起别名
typedef union
{int count;float weight;float volume;
} Quantity;// 为指针类型起别名
typedef int *IntPtr;
typedef char *CharPtr;// 为数组类型起别名
typedef int FiveInts[5];
typedef double TenDoubles[10];
typedef char TwentyChars[20];// 为数组指针类型起别名
typedef int (*IntArrayPointer)[5];
typedef double (*DoubleArrayPointer)[10];
typedef char (*CharArrayPointer)[20];int main()
{// 基本数据类型Integer i = 10;Real r = 3.14;Character c = 'A';String s = "Hello, World!";// 结构体Person p = {"Alice", 30};// 共用体Quantity q;q.weight = 5.5;// 指针类型IntPtr iptr = &i;CharPtr cptr = &c;// 数组类型FiveInts fi = {1, 2, 3, 4, 5};TenDoubles td = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.0};TwentyChars tc = "test string";// 数组指针类型int arr[5] = {10, 20, 30, 40, 50};IntArrayPointer ip = &arr;double dbl_arr[10] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.0};DoubleArrayPointer dp = &dbl_arr;char char_arr[20] = "Another test string.";CharArrayPointer cp = &char_arr;// 打印基本数据类型printf("Integer: %d\n", i); // Integer: 10printf("Real: %.2f\n", r); // Real: 3.14printf("Character: %c\n", c); // Character: Aprintf("String: %s\n", s); // String: Hello, World!// 打印结构体printf("Person: %s, %d years old\n", p.name, p.age); // Person: Alice, 30 years old// 打印共用体printf("Quantity (weight): %.2f\n", q.weight); // Quantity (weight): 5.50// 打印指针类型printf("Value at IntPtr: %d\n", *iptr); // Value at IntPtr: 10printf("Value at CharPtr: %c\n", *cptr); // Value at CharPtr: A// 打印数组类型printf("FiveInts array:\n");for (int j = 0; j < 5; j++){printf("%d ", fi[j]); // 1 2 3 4 5}printf("\n");printf("TenDoubles array:\n");for (int j = 0; j < 10; j++){printf("%.1f ", td[j]); // 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 10.0}printf("\n");printf("TwentyChars array: %s\n", tc); // TwentyChars array: test string// 打印数组指针类型printf("IntArrayPointer array:\n");for (int j = 0; j < 5; j++){printf("%d ", (*ip)[j]); // 10 20 30 40 50}printf("\n");printf("DoubleArrayPointer array:\n");for (int j = 0; j < 10; j++){printf("%.1f ", (*dp)[j]); // 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 10.0}printf("\n");printf("CharArrayPointer array: %s\n", *cp); // CharArrayPointer array: Another test string.return 0;
}