typedef用法结- -
q两天在看程序的时?发现很多地方都用到typedef,在结构体定义,q有一些数l等地方都大量的用到.但是有些地方q不是很清楚,今天下午,想好好研究一?上网搜了一?有不资?归纳一? 来源一:Using typedef to Curb Miscreant Code Typedef 声明有助于创建^台无关类型,甚至能隐藏复杂和难以理解的语法。不怎样Q?typedef 能ؓ代码带来意想不到的好处,通过本文你可以学习用 typedef 避免~欠Q从而代码更健壮?br>typedef 声明Q简U?typedefQؓ现有cd创徏一个新的名字。比如h们常怋?typedef 来编写更观和可ȝ代码。所谓美观,意指 typedef 能隐藏笨拙的语法构造以及^台相关的数据cdQ从而增强可UL性和以及未来的可l护性。本文下面将竭尽全力来揭C?typedef 强大功能以及如何避免一些常见的陷阱?br>如何创徏q_无关的数据类型,隐藏W拙且难以理解的语法? 使用 typedefs 为现有类型创建同义字?br>定义易于记忆的类型名 typedef 使用最多的地方是创建易于记忆的cd名,用它来归档程序员的意图。类型出现在所声明的变量名字中Q位?''typedef'' 关键字右辏V例如: typedef int size; 此声明定义了一?int 的同义字Q名字ؓ size。注?typedef q不创徏新的cd。它仅仅为现有类型添加一个同义字。你可以在Q何需?int 的上下文中?sizeQ?br>void measure(size * psz); size array[4]; size len = file.getlength(); std::vector vs; typedef q可以掩饰符合类型,如指针和数组。例如,你不用象下面q样重复定义?81 个字W元素的数组Q?br>char line[81]; char text[81]; 定义一?typedefQ每当要用到相同cd和大的数组Ӟ可以q样Q?br>typedef char Line[81]; Line text, secondline; getline(text); 同样Q可以象下面q样隐藏指针语法Q?br>typedef char * pstr; int mystrcmp(pstr, pstr); q里带我们到达W一?typedef 陷阱。标准函?strcmp()有两?#8216;const char *'cd的参数。因此,它可能会误导Z象下面这样声?mystrcmp()Q?br>int mystrcmp(const pstr, const pstr); q是错误的,按照序Q?#8216;const pstr'被解释ؓ‘char * const'Q一个指?char 的常量指针)Q而不?#8216;const char *'Q指向常?char 的指针)。这个问题很Ҏ解决Q?br>typedef const char * cpstr; int mystrcmp(cpstr, cpstr); // 现在是正的 CQ不什么时候,只要为指针声?typedefQ那么都要在最l的 typedef 名称中加一?constQ以使得该指针本w是帔RQ而不是对象?br>代码?br> 上面讨论?typedef 行ؓ有点?#define 宏,用其实际cd替代同义字。不同点?typedef 在编译时被解释,因此让编译器来应付超预处理器能力的文本替换。例如: typedef int (*PF) (const char *, const char *); q个声明引入?PF cd作ؓ函数指针的同义字Q该函数有两?const char * cd的参C及一?int cd的返回倹{如果要使用下列形式的函数声明,那么上述q个 typedef 是不可或~的Q?br>PF Register(PF pf); Register() 的参数是一?PF cd的回调函敎ͼq回某个函数的地址Q其|名与先前注册的名字相同。做一ơ深呼吸。下面我展示一下如果不?typedefQ我们是如何实现q个声明的: int (*Register (int (*pf)(const char *, const char *))) (const char *, const char *); 很少有程序员理解它是什么意思,更不用说q种费解的代码所带来的出错风险了。显Ӟq里使用 typedef 不是一U特权,而是一U必需。持怀疑态度的h可能会问Q?OKQ有会写q样的代码吗Q?Q快速浏览一下揭C?signal()函数的头文g Q一个有同样接口的函数?br>typedef 和存储类关键字(storage class specifierQ?br> q种说法是不是有点o人惊Ӟtypedef 像 autoQexternQmutableQstaticQ和 register 一P是一个存储类关键字。这q是?typedef 会真正媄响对象的存储Ҏ;它只是说在语句构成上Qtypedef 声明看v来象 staticQextern {类型的变量声明。下面将带到W二个陷阱: typedef register int FAST_COUNTER; // 错误 ~译通不q。问题出在你不能在声明中有多个存储类关键字。因为符?typedef 已经占据了存储类关键字的位置Q在 typedef 声明中不能用 registerQ或M其它存储cd键字Q?br>促进跨^台开?br> typedef 有另外一个重要的用途,那就是定义机器无关的cdQ例如,你可以定义一个叫 REAL 的Q点类型,在目标机器上它可以i获得最高的_ֺQ?br>typedef long double REAL; 在不支持 long double 的机器上Q该 typedef 看v来会是下面这P typedef double REAL; q且Q在q?double 都不支持的机器上Q该 typedef 看v来会是这P?br>typedef float REAL; 你不用对源代码做M修改Q便可以在每一U^C~译q个使用 REAL cd的应用程序。唯一要改的是 typedef 本n。在大多数情况下Q甚臌个微的变动完全都可以通过奇妙的条件编译来自动实现。不是吗? 标准库广泛地使用 typedef 来创Lq_无关cdQsize_tQptrdiff ?fpos_t 是其中的例子。此外,?std::string ?std::ofstream q样?typedef q隐藏了镉K的,难以理解的模板特化语法,例如Qbasic_stringQallocator> ?basic_ofstream>?br>作者简?br> Danny Kalev 是一名通过认证的系l分析师Q专?C++ 和Ş式语a理论的Y件工E师?997 q到 2000 q期_他是 C++ 标准委员会成员。最q他以优异成l完成了他在普通语a学研I方面的士论文。业余时间他喜欢听古兔R乐,阅读l多利亚时期的文学作品,研究 Hittite、Basque ?Irish Gaelic q样的自然语a。其它兴包括考古和地理。Danny 时常C?C++ 论坛q定期ؓ不同?C++ |站和杂志撰写文章。他q在教育机构讲授E序设计语言和应用语a评?br>来源二:(http://www.ccfans.net/bbs/dispbbs.asp?boardid=30&;id=4455) C语言中typedef用法 1. 基本解释 typedef为C语言的关键字Q作用是ZU数据类型定义一个新名字。这里的数据cd包括内部数据cdQint,char{)和自定义的数据类型(struct{)?br> 在编E中使用typedef目的一般有两个Q一个是l变量一个易C意义明确的新名字Q另一个是化一些比较复杂的cd声明?br> 至于typedef有什么微妙之处,请你接着看下面对几个问题的具体阐q?br> 2. typedef & l构的问?br> 当用下面的代码定义一个结构时Q编译器报了一个错误,Z么呢Q莫非C语言不允许在l构中包含指向它自己的指针吗Q请你先猜想一下,然后看下文说明: typedef struct tagNode { char *pItem; pNode pNext; } *pNode; {案与分析: 1、typedef的最单?br>typedef long byte_4; l已知数据类型long起个新名字,叫byte_4?br> 2?typedef与结构结合?br>typedef struct tagMyStruct { int iNum; long lLength; } MyStruct; q语句实际上完成两个操作Q?br> 1) 定义一个新的结构类?br>struct tagMyStruct { int iNum; long lLength; }; 分析QtagMyStructUCؓ“tag”Q即“标签”Q实际上是一个时名字,struct 关键字和tagMyStruct一P构成了这个结构类型,不论是否有typedefQ这个结构都存在?br> 我们可以用struct tagMyStruct varName来定义变量,但要注意Q用tagMyStruct varName来定义变量是不对的,因ؓstruct 和tagMyStruct合在一h能表CZ个结构类型?br> 2) typedef个新的结构v了一个名字,叫MyStruct?br>typedef struct tagMyStruct MyStruct; 因此QMyStruct实际上相当于struct tagMyStructQ我们可以用MyStruct varName来定义变量?br> {案与分?br> C语言当然允许在结构中包含指向它自q指针Q我们可以在建立链表{数据结构的实现上看到无数这L例子Q上qC码的Ҏ问题在于typedef的应用?br> Ҏ我们上面的阐q可以知道:新结构徏立的q程中遇CpNext域的声明Q类型是pNodeQ要知道pNode表示的是cd的新名字Q那么在cd本nq没有徏立完成的时候,q个cd的新名字也还不存在,也就是说q个时候编译器Ҏ不认识pNode?br> 解决q个问题的方法有多种Q?br> 1)?br>typedef struct tagNode { char *pItem; struct tagNode *pNext; } *pNode; 2)?br>typedef struct tagNode *pNode; struct tagNode { char *pItem; pNode pNext; }; 注意Q在q个例子中,你用typedefl一个还未完全声明的cdh名字。C语言~译器支持这U做法?br> 3)、规范做法: struct tagNode { char *pItem; struct tagNode *pNext; }; typedef struct tagNode *pNode; 3. typedef & #define的问?br> 有下面两U定义pStr数据cd的方法,两者有什么不同?哪一U更好一点? typedef char *pStr; #define pStr char *; {案与分析: 通常Ԍtypedef要比#define要好Q特别是在有指针的场合。请看例子: typedef char *pStr1; #define pStr2 char *; pStr1 s1, s2; pStr2 s3, s4; 在上q的变量定义中,s1、s2、s3都被定义为char *Q而s4则定义成了charQ不是我们所预期的指针变量,Ҏ原因在?define只是单的字符串替换而typedef则是Z个类型v新名字?br> #define用法例子Q?br>#define f(x) x*x main( ) { int a=6Qb=2QcQ?br> c=f(a) / f(b)Q?br> printf("%d \\n"Qc)Q?br>} 以下E序的输出结果是: 36?br> 因ؓ如此原因Q在许多C语言~程规范中提C?define定义Ӟ如果定义中包含表辑ּQ必M用括P则上q定义应该如下定义才对: #define f(x) (x*x) 当然Q如果你使用typedef没有这L问题?br> 4. typedef & #define的另一?br> 下面的代码中~译器会报一个错误,你知道是哪个语句错了吗? typedef char * pStr; char string[4] = "abc"; const char *p1 = string; const pStr p2 = string; p1++; p2++; {案与分析: 是p2++出错了。这个问题再一ơ提醒我们:typedef?define不同Q它不是单的文本替换。上qC码中const pStr p2q不{于const char * p2。const pStr p2和const long x本质上没有区别,都是对变量进行只读限Ӟ只不q此处变量p2的数据类型是我们自己定义的而不是系l固有类型而已。因此,const pStr p2的含义是Q限定数据类型ؓchar *的变量p2为只读,因此p2++错误?br> #define与typedef引申?br> 1) #define宏定义有一个特别的长处Q可以?#ifdef ,#ifndef{来q行逻辑判断Q还可以使用#undef来取消定义?br> 2) typedef也有一个特别的长处Q它W合范围规则Q用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内Q取决于此变量定义的位置Q,而宏定义则没有这U特性?br> 5. typedef & 复杂的变量声?br> 在编E实践中Q尤其是看别Z码的时候,常常会遇到比较复杂的变量声明,使用typedef作简化自有其价|比如Q?br> 下面是三个变量的声明Q我想用typdef分别l它们定义一个别名,请问该如何做Q?br>>1Qint *(*a[5])(int, char*); >2Qvoid (*b[10]) (void (*)()); >3. doube(*)() (*pa)[9]; {案与分析: 对复杂变量徏立一个类型别名的Ҏ很简单,你只要在传统的变量声明表辑ּ里用cd名替代变量名Q然后把关键字typedef加在该语句的开头就行了?br>>1Qint *(*a[5])(int, char*); //pFun是我们徏的一个类型别?br>typedef int *(*pFun)(int, char*); //使用定义的新cd来声明对象,{h于int* (*a[5])(int, char*); pFun a[5]; >2Qvoid (*b[10]) (void (*)()); //首先Z面表辑ּ蓝色部分声明一个新cd typedef void (*pFunParam)(); //整体声明一个新cd typedef void (*pFun)(pFunParam); //使用定义的新cd来声明对象,{h于void (*b[10]) (void (*)()); pFun b[10]; >3. doube(*)() (*pa)[9]; //首先Z面表辑ּ蓝色部分声明一个新cd typedef double(*pFun)(); //整体声明一个新cd typedef pFun (*pFunParam)[9]; //使用定义的新cd来声明对象,{h于doube(*)() (*pa)[9]; pFunParam pa; |
#define S(s) printf("%s\n", #s); s
typedef struct _TS1{
int x, y;
} TS1, *PTS1, ***PPPTS1; // TS1是结构体的名UͼPTS1是结构体指针的名U?/span>
// 也就是将l构?/span>struct _TS1 命名?/span>TS1,
// ?/span>struct _TS1 * 命名?/span> PTS1
// ?/span>struct _TS1 *** 命名?/span> PPPTS1
typedef struct { // struct后面的结构体说明也可以去?/span>
int x, y;
} TS2, *PTS2;
typedef PTS1 *PPTS1; // 定义PPTS1是指?/span>PTS1的指?/span>
typedef struct _TTS1{
typedef struct ITTS1 {
int x, y;
} iner;
iner i;
int x, y;
} TTS1;
//l构体内部的l构体也一样可以定?/span>
typedef TTS1::ITTS1 ITS1;
void test_struct()
{
// 基本l构体重定义的?/span>
TS1 ts1 = {100, 200};
PTS1 pts1 = &ts1; // 完全{h?/span>TS1* pts1 = &ts1;
PPTS1 ppts1 = &pts1; // 完全{h?/span>TS1** ppts1 = &pts1;
PPPTS1 pppts1 = &ppts1; // 完全{h?/span> TS1*** pppts1 = &ppts1;
TS2 ts2 = {99, 88};
PTS2 pts2 = &ts2; // 完全{h?/span> TS2* pts2 = &ts2;
TTS1 itts1 = {{110, 220}, 10, 20};
Its1* rits1 = &itts1.i;
ITS1* &its1 = rits1; // {h?/span> TTS1::ITTS1 *its1 = &(itts1.i);
printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"
"**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",
ts1.x, ts1.y, pts1->x, pts1->y,
(**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);
printf("ts2\t = (%d, %d)\n*pts2\t = (%d, %d)\n\n",
ts2.x, ts2.y, pts2->x, pts2->y);
printf("itts1\t = [(%d, %d), %d, %d]\n*its1\t = (%d, %d)\n\n",
itts1.i.x, itts1.i.y, itts1.x, itts1.y, its1->x, its1->y);
S(pts1->x = 119);
S(pts2->y = 911);
S(its1->x = 999);
printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"
"**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",
ts1.x, ts1.y, pts1->x, pts1->y,
(**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);
printf("ts2\t = (%d, %d)\n*pts2\t = (%d, %d)\n\n",
ts2.x, ts2.y, pts2->x, pts2->y);
printf("itts1\t = [(%d, %d), %d, %d]\n*its1\t = (%d, %d)\n\n",
itts1.i.x, itts1.i.y, itts1.x, itts1.y, its1->x, its1->y);
S((*ppts1)->y = -9999);
printf("ts1\t = (%d, %d)\n**ppts1\t = (%d, %d)\n\n",
ts1.x, ts1.y, (*ppts1)->x, (*ppts1)->y);
S((**pppts1)->x = -12345);
S((***pppts1).y = -67890);
printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"
"**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",
ts1.x, ts1.y, pts1->x, pts1->y,
(**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);
}
#include <vector> void assign( size_type num, const TYPE& val ); void assign( input_iterator start, input_iterator end );
The assign() function either gives the current vector the values from start to end, or gives it num copies of val.
This function will destroy the previous contents of the vector.
For example, the following code uses assign() to put 10 copies of the integer 42 into a vector:
vector<int> v;
v.assign( 10, 42 );
for( int i = 0; i < v.size(); i++ ) {
cout << v[i] << " ";
}
cout << endl;
The above code displays the following output:
42 42 42 42 42 42 42 42 42 42
The next example shows how assign() can be used to copy one vector to another:
vector<int> v1;
for( int i = 0; i < 10; i++ ) {
v1.push_back( i );
}
vector<int> v2;
v2.assign( v1.begin(), v1.end() );
for( int i = 0; i < v2.size(); i++ ) {
cout << v2[i] << " ";
}
cout << endl;
When run, the above code displays the following output:
0 1 2 3 4 5 6 7 8 9
Vector constructorsSyntax:#include <vector> vector(); vector( const vector& c ); vector( size_type num, const TYPE& val = TYPE() ); vector( input_iterator start, input_iterator end ); ~vector();The default vector constructor takes no arguments, creates a new instance of that vector.
The second constructor is a default copy constructor that can be used to create a new vector that is a copy of the given vector c.
The third constructor creates a vector with space for num objects. If val is specified, each of those objects will be given that value. For example, the following code creates a vector consisting of five copies of the integer 42:
vector<int> v1( 5, 42 );The last constructor creates a vector that is initialized to contain the elements between start and end. For example:
// create a vector of random integers
cout << "original vector: ";
vector<int> v;
for( int i = 0; i < 10; i++ ) {
int num = (int) rand() % 10;
cout << num << " ";
v.push_back( num );
}
cout << endl;
// find the first element of v that is even
vector<int>::iterator iter1 = v.begin();
while( iter1 != v.end() && *iter1 % 2 != 0 ) {
iter1++;
}
// find the last element of v that is even
vector<int>::iterator iter2 = v.end();
do {
iter2--;
} while( iter2 != v.begin() && *iter2 % 2 != 0 );
// only proceed if we find both numbers
if( iter1 != v.end() && iter2 != v.begin() ) {
cout << "first even number: " << *iter1 << ", last even number: " << *iter2 << endl;
cout << "new vector: ";
vector<int> v2( iter1, iter2 );
for( int i = 0; i < v2.size(); i++ ) {
cout << v2[i] << " ";
}
cout << endl;
}When run, this code displays the following output:
original vector: 1 9 7 9 2 7 2 1 9 8
first even number: 2, last even number: 8
new vector: 2 7 2 1 9All of these constructors run in linear time except the first, which runs in constant time.
The default destructor is called when the vector should be destroyed.