您的位置:首页 > 编程语言 > C语言/C++

C语言之关键字(二) void,const

2014-05-06 19:08 211 查看
接着上一篇,继续讲述一下关键字,今天主要是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

试下下面的程序

add(int a,int b)
{
	return a+b;
}
int main(int argc, char* argv[])
{

    int a=2;
	int b=3;
	printf("%d\n",add(a,b));
    //printf("%d\n",addReturnVoid(a,b));

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

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

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

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

试下这个程序

int fun()
{
	 return 1;
}
int main(int argc, char* argv[])
{
    printf("%d\n",fun(3));
	return 0;
}
在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;注意这么是声明而不是定义哦
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: