使用typedef定义新的变量类型(指针)
一、typedef的使用
typedef
是 C 语言中用于定义新类型的关键字,可以用来为已有类型定义新的别名。它的语法如下:
typedef [原类型名] [新类型名];
在这个语句中,[原类型名]
是你要定义的原有类型的名字,[新类型名]
是你为该类型定义的新的类型名。
下面是使用 typedef
的一个例子,它将 struct student
这个结构体类型重命名为 Student
:
typedef struct student {
int id;
char name[50];
float grade;
} Student;
在上面的例子中,Student
是一个新的类型名,它是 struct student
的别名。现在可以使用 Student
来定义一个新的结构体变量,如下所示:
Student s1;
二、typedef的注意点
typedef
可以用于定义新的类型别名,也可以用于定义新的结构体类型或新的指针类型,例如:
typedef int *IntPtr;
typedef struct {
int x;
int y;
} Point;
在定义新的类型别名时,一定要确保新的类型名与已有的类型名没有冲突。如果新的类型名与已有的类型名相同,可能会导致编译错误。
- 在使用
typedef
定义新类型时,可以省略结构体类型的名称,例如:
typedef struct {
int id;
char name[50];
float grade;
} Student;
这种情况下,这个结构体类型只能被用作 typedef
定义新类型,而不能直接被实例化。如果需要在程序中定义这个结构体类型的变量,必须先定义一个结构体类型的标签名(tag name),例如:
struct student {
int id;
char name[50];
float grade;
};
typedef struct student Student;
- 当定义指向结构体类型的指针类型时,需要在
typedef
语句中使用括号(跳转到 Table-1 ),例如:
typedef struct student *StudentPtr;
如果没有使用括号,会导致语法错误。
typedef
定义的新类型可以使用const
修饰符,例如:
typedef int *IntPtr;
typedef const IntPtr ConstIntPtr;
这里的 ConstIntPtr
是一个常量指针类型,它指向一个 int
类型的常量。
typedef
可以与宏定义一起使用,定义一些复杂的类型别名,例如:
#define VECTOR(T) struct { T x; T y; T z; }
typedef VECTOR(int) IntVector;
typedef VECTOR(float) FloatVector;
这里的 VECTOR
宏定义了一个包含三个同类型元素的结构体类型。IntVector
和 FloatVector
是分别针对 int
和 float
类型定义的新的类型别名,它们都是 VECTOR
宏定义的结构体类型的别名。
- 在定义新类型时,需要注意一些细节,例如:
- 在定义结构体类型时,必须使用大括号
{}
,即使结构体内没有任何成员。 - 在定义指向结构体类型的指针类型时,需要在
typedef
语句中使用括号,例如typedef struct student *StudentPtr;
。 - 在定义数组类型时,可以使用
typedef
,但不能定义可变长度数组类型,例如typedef int arr[n];
是错误的。 - 在定义函数指针类型时,需要注意指针符号
*
的位置,例如typedef void (*FuncPtr)(int);
定义了一个指向返回值为void
、参数为int
的函数的指针类型。
总之,使用 typedef
可以让代码更加易读易懂,减少代码中的重复,提高代码的可读性和可维护性。但是,也需要注意使用 typedef
时可能遇到的一些易错点。
*关于使用括号来避免歧义
当定义指向结构体类型的指针类型时,需要在 typedef
语句中使用括号,这是因为在 C 语言中,圆括号可以起到优先级的作用,避免类型解析的歧义。
举个例子,假设有以下代码:
struct student {
int id;
char name[50];
float grade;
};
typedef struct student* StudentPtr;
这里的 StudentPtr
是指向 struct student
结构体类型的指针类型。如果省略了括号,直接写成 typedef struct student* StudentPtr;
,那么该语句将被解析为“定义一个 StudentPtr
变量,它是一个指向 struct student*
类型的指针”。这显然与我们的意图不符。
因此,为了避免这种歧义,需要在 typedef
语句中使用括号,明确指定指针类型的优先级。正确的写法应该是:
typedef struct student *StudentPtr;
或者更为严谨的写法:
typedef struct student (*StudentPtr);
这样,我们就可以清晰地表达出 StudentPtr
是指向 struct student
类型的指针类型。
在这里,*
符号是与 StudentPtr
符号结合的,表示 StudentPtr
是一个指向 struct student
结构体类型的指针类型。
struct student *
表示指向 struct student
结构体类型的指针类型,而 (*StudentPtr)
是为了将这个指针类型定义为一个新的类型名 StudentPtr
而使用的语法。
在 typedef
语句中,如果省略了括号,那么声明的语法就会变成 typedef struct student *StudentPtr
。这样虽然也能定义一个指向 struct student
结构体类型的指针类型 StudentPtr
,但是会导致一些二义性的问题。因为在 C 语言中,*
符号的优先级较高,如果不加括号的话,编译器可能会将这个语句解析为 typedef (struct student *) StudentPtr
,即将 StudentPtr
定义为一个指向 struct student
结构体类型的指针类型,而不是一个新的类型名。
因此,为了避免这种二义性的问题,(*StudentPtr)
这种语法更加清晰和易于理解。
三、使用typedef定义新的指针变量
int main() {
struct student {
int id;
char name[50];
float grade;
};
typedef struct student (*StudentPtr);
StudentPtr p = new student;
cout << p;
delete p;
return 0;
}
输出结果:0x6d2640
这段代码定义了一个名为 student
的结构体类型,并将它用 typedef
声明为指向 struct student
类型的指针类型 StudentPtr
。然后,在 main
函数中,定义了一个名为 p
的指向 struct student
类型的指针变量,使用 new
运算符动态地分配了一个 struct student
类型的对象,并将它的地址赋值给 p
。最后,打印 p
变量的值。
可以看出,这段代码的作用是使用动态内存分配来创建一个 struct student
类型的对象,并通过指针 p
来访问它的成员。其中 typedef
语句的作用是将结构体类型名 struct student
重新定义为指向结构体类型的指针类型 StudentPtr
,使得在后面使用指向结构体类型的指针更加方便。
需要注意的是,在 C++ 中使用 new
运算符来分配内存,需要使用 delete
运算符来释放内存。因此,在这段代码的最后,还需要添加 delete p;
语句来释放动态分配的内存。