一、typedef用法详解

C语言允许为一个数据类型起一个新的别名,就像给人起“绰号”一样。

起别名的目的不是为了提高程序运行效率,而是为了编码方便。例如有一个结构体的名字是 stu,要想定义一个结构体变量就得这样写:

struct stu stu1;

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

STU stu1;

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

1、使用关键字typedef可以为类型起一个新的别名。typedef 的用法一般为:

typedef oldName newName;

oldName 是类型原来的名字,newName 是类型新的名字。例如:

typedef int INTEGER;
INTEGER a, b;
a = 10;
b = 20;

INTEGER a, b;等效于int a, b

typedef 还可以给数组、指针、结构体等类型定义别名。先来看一个给数组类型定义别名的例子:

typedef char ARRAY20[20];

表示 ARRAY20 是类型char [20]的别名。它是一个长度为 20 的数组类型。接着可以用 ARRAY20 定义数组:

ARRAY20 a1, a2, s1, s2;

它等价于:

char a1[20], a2[20], s1[20], s2[20];

注意,数组也是有类型的。例如char a1[20];

2、定义了一个数组 a1,它的类型就是 char [20]。

又如,为结构体类型定义别名:

typedef struct stu{
char name[20];
int age;
char sex;
} STU;

3、STU 是 struct stu 的别名,可以用 STU 定义结构体变量:

STU body1,body2;

它等价于:

struct stu body1, body2;

再如,为指针类型定义别名:

typedef int (*PTR_TO_ARR)[4];

表示 PTR_TO_ARR 是类型int * [4]的别名,它是一个二维数组指针类型。接着可以使用 PTR_TO_ARR 定义二维数组指针:

PTR_TO_ARR p1, p2;

按照类似的写法,还可以为函数指针类型定义别名:

typedef int (*PTR_TO_FUNC)(int, int);
PTR_TO_FUNC pfunc;

4、【示例】为指针定义别名。

#include <stdio.h>

typedef char(*PTR_TO_ARR)[100];

typedef int(*PTR_TO_FUNC)(int, int);

int max(int a, int b) {

return a > b ? a : b;

}

char str[6][100] = {0};

int main()

{

PTR_TO_ARR parr = str;

PTR_TO_FUNC pfunc = max;

int i;

printf("max: %d\n", (*pfunc)(10, 20));

for (i = 0; i < 6; i++)

{

printf("str[%d]: %s\n", i, *(parr + i));

}

return 0;

}

4、运行结果如下:

需要强调的是,typedef 是赋予现有类型一个新的名字,而不是创建新的类型。为了“见名知意”,请尽量使用含义明确的标识符,并且尽量大写。

typedef 和 #define 的区别

typedef 在表现上有时候类似于 #define,但它和宏替换之间存在一个关键性的区别。正确思考这个问题的方法就是把 typedef 看成一种彻底的“封装”类型,声明之后不能再往里面增加别的东西。

1) 可以使用其他类型说明符对宏类型名进行扩展,但对 typedef 所定义的类型名却不能这样做。如下所示:

#define INTERGE int
unsigned INTERGE n; //没问题

typedef int INTERGE;
unsigned INTERGE n; //错误,不能在 INTERGE 前面添加 unsigned

2) 在连续定义几个变量的时候,typedef 能够保证定义的所有变量均为同一类型,而 #define 则无法保证。例如:

#define PTR_INT int *
PTR_INT p1, p2;

经过宏替换以后,第二行变为:

int *p1, p2;

这使得 p1、p2 成为不同的类型:p1 是指向 int 类型的指针,p2 是 int 类型。

相反,在下面的代码中:

typedef int * PTR_INT
PTR_INT p1, p2;

p1、p2 类型相同,它们都是指向 int 类型的指针。

二、const用法详解

有时候我们希望定义这样一种变量,它的值不能被改变,在整个作用域中都保持固定。例如,用一个变量来表示班级的最大人数,或者表示缓冲区的大小。为了满足这一要求,可以使用const关键字对变量加以限定:

const int MaxNum = 100; //班级的最大人数

这样 MaxNum 的值就不能被修改了,任何对 MaxNum 赋值的行为都将引发错误:

MaxNum = 90; //错误,试图向 const 变量写入数据

我们经常将 const 变量称为常量(constant)。创建常量的格式通常为:

const type name = value;

const 和 type 都是用来修饰变量的,它们的位置可以互换,也就是将 type 放在 const 前面:

type const name = value;

但我们通常采用第一种方式,不采用第二种方式。另外建议将常量名的首字母大写,以提醒程序员这是个常量。

由于常量一旦被创建后其值就不能再改变,所以常量必须在定义的同时赋值(初始化),后面的任何赋值行为都将引发错误。一如既往,初始化常量可以使用任意形式的表达式,如下所示:

#include <stdio.h>

int getNum()

{

return 10000;

}

int main()

{

int n = 90000;

const int MaxNum1 = getNum(); //运行时初始化

const int MaxNum2 = n; //运行时初始化

const int MaxNum3 = 80000; //编译时初始化

printf("%d, %d, %d\n", MaxNum1, MaxNum2, MaxNum3);

return 0;

}

运行结果如下:

1、const 和指针

const 也可以和指针变量一起使用,这样可以限制指针变量本身,也可以限制指针指向的数据。const 和指针一起使用会有几种不同的顺序,如下所示:

const int *p1;
int const *p2;
int * const p3;

在最后一种情况下,指针是只读的,也就是 p3 本身的值不能被修改;在前面两种情况下,指针所指向的数据是只读的,也就是 p1、p2 本身的值可以修改(指向不同的数据),但它们指向的数据不能被修改。

当然,指针本身和它指向的数据都有可能是只读的,下面的两种写法能够做到这一点:

const int * const p4;

int const * const p5;

const 和指针结合的写法多少有点让初学者摸不着头脑,大家可以这样来记忆:const 离变量名近就是用来修饰指针变量的,离变量名远就是用来修饰指针指向的数据,如果近的和远的都有,那么就同时修饰指针变量以及它指向的数据。

2、const 和函数形参

在C语言中,单独定义 const 变量没有明显的优势,完全可以使用#define 命令代替。const 通常用在函数形参中,如果形参是一个指针,为了防止在函数内部修改指针指向的数据,就可以用 const 来限制。

在C语言标准库中,有很多函数的形参都被 const 限制了,下面是部分函数的原型:

size_t strlen ( const char * str );
int strcmp ( const char * str1, const char * str2 );
char * strcat ( char * destination, const char * source );
char * strcpy ( char * destination, const char * source );
int system (const char* command);
int puts ( const char * str );
int printf ( const char * format, ... );

我们自己在定义函数时也可以使用 const 对形参加以限制,例如查找字符串中某个字符出现的次数:

#include <stdio.h>

#include <string.h>

size_t strnchr(const char *str, char ch)

{

int i, n = 0, len = strlen(str);

for (i = 0; i<len; i++)

{

if (str[i] == ch)

{

n++;

}

}

return n;

}

int main()

{

char *str = "C语言经典编程100例实战-学习视频教程-腾讯课堂";

char ch = 't';

int n = strnchr(str, ch);

printf("%d\n", n);

return 0;

}

运行结果如下:

根据 strnchr() 的功能可以推断,函数内部要对字符串 str 进行遍历,不应该有修改的动作,用 const 加以限制,不但可以防止由于程序员误操作引起的字符串修改,还可以给用户一个提示,函数不会修改你提供的字符串,请你放心。

3、const 和非 const 类型转换

当一个指针变量 str1 被 const 限制时,并且类似const char *str1

这种形式,说明指针指向的数据不能被修改;如果将 str1 赋值给另外一个未被 const 修饰的指针变量 str2,就有可能发生危险。因为通过 str1 不能修改数据,而赋值后通过 str2 能够修改数据了,意义发生了转变,所以编译器不提倡这种行为,会给出错误或警告。

也就是说,const char *char *是不同的类型,不能将const char *类型的数据赋值给char *类型的变量。但反过来是可以的,编译器允许将char *类型的数据赋值给const char * 类型的变量。

这种限制很容易理解,char *指向的数据有读取和写入权限,而const char *指向的数据只有读取权限,降低数据的权限不会带来任何问题,但提升数据的权限就有可能发生危险。

C语言标准库中很多函数的参数都被 const 限制了,但我们在以前的编码过程中并没有注意这个问题,经常将非 const 类型的数据传递给 const 类型的形参,这样做从未引发任何副作用,原因就是上面讲到的,将非 const 类型转换为 const 类型是允许的。

四、const与#define相比及优势

1、区别
(1)就起作用的阶段而言: #define是在编译的预处理阶段起作用,而const是在 编译、运行的时候起作用。
(2)就起作用的方式而言: #define只是简单的字符串替换,没有类型检查。而const有对应的数据类型,是要进行判断的,可以避免一些低级的错误。
(3)就存储方式而言:#define只是进行展开,有多少地方使用,就替换多少次,它定义的宏常量在内存中有若干个备份;const定义的只读变量在程序运行过程中只有一份备份。
(4)从代码调试的方便程度而言: const常量可以进行调试的,define是不能进行调试的,因为在预编译阶段就已经替换掉。

2、const优点

(1)const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。

(2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。

(3)const可节省空间,避免不必要的内存分配,提高效率。

C语言高频率--typedef和const用法详解相关推荐

  1. php const用法详解

    php const用法详解 在编程中,我们一般用常量来定义那些在运行时不能被改变的常数值,下面让我们来看看php中的const吧,这个东西其 实没有什么好说的,只是为了知识的完善而随便说下吧.在定义一 ...

  2. c语言数据类型int的用法,C语言基本数据类型:整型(int)用法详解|C语言学习

    C语言基本数据类型:整型(int)用法详解 1. 整型 int C 语言提供了很多整数类型(整型),这些整型的区别在于它们的取值范围的大小,以及是否可以为负.int 是整型之一,一般被称为整型.以后, ...

  3. C语言中const用法详解

    C语言中const用法详解 const修饰普通变量 const作用在于定义一个常量,比如const int a = 10,代表a的值不能被直接修改了,是一个常量,但仍可以通过指针的方式间接修改,如下图 ...

  4. c枚举类型enum例题_C语言--enum,typedef enum 枚举类型详解

    原文:http://z515256164.blog.163.com/blog/static/32443029201192182854300/ 有改动 C语言详解 - 枚举类型 注:以下全部代码的执行环 ...

  5. C++ const用法详解

    const 是C++中常用的类型修饰符,常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的. 目录 一.const的作用 二.const修饰普通类型的变量 三.cons ...

  6. C语言const用法详解(带实例)

    const与define区别 在C语言中const常用来定义常量,表示这个常量是不可以被修改的.define宏定义也可以用来表示一个常量.那么他们有那些区别呢! 1.预编译指令只是对值进行简单的替换, ...

  7. java中finaljava中this_Java中this,static,final,const用法详解

    一.this 用类名定义一个变量的时候,定义的应该只是一个引用,外面可以通过这个引用来访问这个类里面的属性和方法,那们类里面是够也应该有一个引用来访问自己的属性和方法纳?JAVA提供了一个很好的东西, ...

  8. C++ static与const用法详解

    目录 static的作用: 对普通变量: 1.局部变量: 2.全局变量 对类中变量: 1.成员变量 2.成员函数 const的作用: static的作用: 对普通变量: 1.局部变量: 在局部变量之前 ...

  9. c语言iota函数,C++ iota函数用法详解

    定义在 numeric 头文件中的 iota() 函数模板会用连续的 T 类型值填充序列.前两个参数是定义序列的正向迭代器,第三个参数是初始的 T 值.第三个指定的值会被保存到序列的第一个元素中.保存 ...

最新文章

  1. zookeeper都有哪些使用场景
  2. 2020计算机考研初试考试先后顺序,【图片】2020考研,老学长教你如何规划!【计算机考研吧】_百度贴吧...
  3. 【Linux】43.ubuntu18.04安装搜狗输入法不能正常使用
  4. POJ2942 Knights of the Round Table 点双连通分量 二分图判定
  5. PostBox使用小记
  6. Spark入门(十五)之分组求最小值
  7. linux tar 大小不同,linux – 如何在使用tar时设置bzip2块大小?
  8. 多项目晶圆(MPW)服务
  9. c语言利用fun求最小值,c语言:请编写函数fun(),他的功能是:求f(0)到f(50)的最小值,已知:f(0)=f(1)=1,f(2)=0,f...
  10. Servlet打印HTML页面乱码问题
  11. 计算机基础知识第三章测试,计计算机应用基础第三章测试题
  12. 图像下采样 matlab_MATLAB--数字图像处理 图像的采样与量化
  13. 面试题之数据库事务隔离级别
  14. Unity Qualcomm 3D音频插件
  15. 致敬科比:科比投篮数据可视化
  16. linux下载flink安装包
  17. Microsoft Dynamics 365咨询服务研究报告-Microsoft Dynamics 365咨询服务生产基地、总部、竞争对手及市场地位
  18. C++ for_each函数
  19. 平均指标指数与平均数指数的区别
  20. 【NBA之路】启蒙—to—詹皇—to—保罗乔治

热门文章

  1. 播放4K视频需要什么样的配置
  2. Vmware 安装时提示directory ezboot not found解决办法
  3. 电子信息工程——学习资料(更新.........)
  4. CSS3 - 使用弹性盒子(Flex Box)实现完美居中、栅格系统及响应式布局
  5. 当我们再谈AI芯片,有些东西已经变了
  6. 微信小程序:星座运势,周公解梦流量主微信小程序
  7. 并查集解决朋友圈问题
  8. 可以说:未来10年这个行业依然值得进,天花板很高,月薪至少3W
  9. 凭借徽商精神,他创办的公司成为国家级电子商务示范企业
  10. windows7利用EasyBCD安装centos6.3双系统