关键字 void,const

1 void a? void *p? 哪个正确?

void的字面意思是“空类型”,void *则为“空类型指针”,void *可以指向任何类型的数据。看下下面的例子

如果我们在程序中使用 void a 及void *p?  你觉得结果会是什么呢?

他会提示 void a这一行 执行 error C2182: 'a' : illegal use of type 'void' 但是 void *p确实没有问题的。

这是因为定义变量时候(是否记得声明与定义的区别,见上一篇)必须分配内存,而如果定义成空类型变量,那么他就是会不知道要分配多少了,但是定义了void *p 因为p是一个指针,是很明确的是4bytes,所以可以分配,只是现在的p还不知道他会指向哪块内存。所以不要妄想用void来定义变量。

void主要用来:(1) 对函数返回的限定;(2) 对函数参数的限定;(3)指针

下面一一道来

1.1 对函数返回值的限定——如果无返回值请一定加上void

试下下面的程序

 

 
  1. add(int a,int b)

  2. {

  3. return a+b;

  4. }

  5. int main(int argc, char* argv[])

  6. {

  7.  
  8. int a=2;

  9. int b=3;

  10. printf("%d\n",add(a,b));

  11. //printf("%d\n",addReturnVoid(a,b));

  12.  
  13. return 0;

  14. }

发现最后会输出 5,所以在C语言中,凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理而不是void。

 

如果你还不死心,如果认为他是void,那么上面的add函数就应该等价于 void add ,你把它加上后再试下会出现error C2562: 'addReturnVoid' : 'void' function returning a value

所以,为了避免混乱,如果函数不返回任何值,那么必须用void修饰

1.2 对参数的限定——如果某函数不需要参数,请将()内填入void

试下这个程序

 

 
  1. int fun()

  2. {

  3. return 1;

  4. }

  5. int main(int argc, char* argv[])

  6. {

  7. printf("%d\n",fun(3));

  8. return 0;

  9. }

在codeblocks中他会顺利的通过,打印出1.

 

所以如果函数没有参数,还是将void加上,这都是好习惯

1.3 空类型指针 void *p

首先说一下,尽管定义空类型变量不行,而空类型指针可以,但是空类型指针不能进行算法运算。

例如 void  *p;

       p++; 或者p+=1

这样都是不行的,因为我们知道,对指针类型进行加1等操作,是移动到他指向的数据类型的下一个类型,例如是int 型,他就移动4个单位,所以对空类型进行运算,他根本就不知道他要移动多少。所以这是出错的。

我们知道,如果不同类型的变量要相互赋值或者进行运算,必须经过强制转换,例如

float *pf;

int *pi;

pf= pi;

这样是会出错的,只能是pf=(float*) pi ; 这样进行强制转换

但是void*则不同,他可以直接赋值;例如

 

float *pf;

int *pi;

void *p;

p=pf;

.....

p=pi;

但要注意,其他类型的指针可以支付赋值给空类型指针。但是并不是说空类型指针可以赋值给任何类型的指针,例如

pf=p;

pi=p;

这都是出错的,可以自己体会下原因。

另外,如果函数的参数可以是任意类型指针,那么应声明其参数为void *。典型的如内存操作函数memcpy和memset的函数原型分别为:

void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );

以及像malloc这样的,而其返回类型也是void型的,所以我们平时都会在返回前进行强制类型转换 例如 int *p=(int *) malloc(100*sizeof(int))

2 const关键字——其实应该是readonly

首先,一定不能认为const修饰的是常量,注意他修饰的是变量,只是这个变量的值不能再修改,是叫只读变量。而常量在编译阶段可以被使用,但是只读变量在编译阶段是不能被使用的,因为编译器还不知道这个变量是什么内容。

例如 const int MAX=10;

        int a[MAX];

有些编译器会出错,因为我们在定义数组时候必须指定数组的大小,所以这也放映出const修饰的是变量,而不是常量

而const推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。

const是怎样消除#define缺点,继承优点?

节省空间,避免不必要的内存分配,同时提高效率.

编译器通常不为普通const变量分配存储空间,而是将他们保存在符号表中,这使得他成为编译期间的值,但没有存储与读内存的操作,使得他效率很高。

cosnt  定义的只读变量从汇编角度上来看,只是给出了对应的内存的地址,而不是像#define那样给处于了立即数,所以,const定义的只读变量在程序运行过程中只有一份拷贝,而#define定义的宏常量在内存中有若干个拷贝,#define宏在预编译阶段进行替换,而const修饰的只读变量是在编译时候确定其值,#define没有类型,而const修饰的只读变量有确定的数据类型

const修饰一般变量或数组

这种只读变量变量在定义时候,修饰符const可以用在类型说明符前,也可以用在类型说明符后,例如:

int consti= 2  或 const int i=2;都是一样

定义或说明一个只读数组可以如下:

int const a[5]={0}或者 const int a[5]={0};

const修饰指针

很多时候我们在被考察到cosnt修饰的究竟是指针不变还是指向的数据不变时候总是很迷糊,其实我们可以先忽略类型名,然后看const离谁最近就是修饰谁

const int *p //将int 去掉,const *p,可知const修饰的是*p,而不是指针变量p,所以是p可变,p指向的对象不可变

int const *p //同样, cosnt *p,与上面一致,p可变,p指向的对象不可变

int *const p  //去掉int  成* const p 所以是p指针不变,p指向的对象可变

const int *const p //去掉int 成了 const * const p.所以是p指针不变,p指向的对象也不变

const修饰函数的参数或者函数的返回值

const修饰符可以修饰函数的参数,当不希望这个参数在函数体中被意外修改时候,则可以用const修饰,例如 void fun(const int i);

同样如果希望函数的返回值不被改变,则可以用const修饰函数的返回值, const int fun(void);

而在另一个链接文件中引用const只读变量时候,用 extern const int i;注意这么是声明而不是定义哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值