遭人遗弃的goto:
C语言是一种面向过程的结构化语言,其中主要结构有三种,顺序执行、选择执行、循环执行。再复杂的程序也是由这三种结构组合而成的。
goto破坏了结构化特性,使程序以第四种方式执行,结构化特性被破坏的越严重程序质量越下降。
现代软件开发中很多企业禁用goto。
goto破坏结构化特性的示例:
1 #include <stdio.h> 2 #include <malloc.h> 3 4 void func(int n) 5 { 6 int* p = NULL; 7 8 if( n < 0 ) 9 { 10 goto STATUS; 11 } 12 13 14 p = (int*)malloc(sizeof(int) * n); 15 16 STATUS: 17 p[0] = n; 18 19 free(p); 20 } 21 22 int main() 23 { 24 printf("begin... "); 25 26 printf("func(1) "); 27 28 func(1); 29 30 printf("func(-1) "); 31 32 func(-1); 33 34 printf("end... "); 35 36 return 0; 37 }
程序在第10行直接跳转到第16行,则14行就得不到执行,我们在第17行赋值就会出错。当n大于0才可以正常执行。
运行结果如下:
32行的调用会导致程序崩溃。
void的意义:
函数如果没有返回值应该定义成void,否则默认为int型。不接受参数的话要定义成void,否则默认接受任意参数。因为C语言并不是一门强类型的语言。不写返回值类型C语言编译器并不认为是错的。
如果函数不接受任何参数,也没有返回值,那么一定要定义成void。
不存在void变量:void是一种抽象类型,C语言规范并没有定义void的具体大小,是一种概念上的抽象类型
虽然不可以定义void类型的变量,但是可以定义void类型的指针。因为指针类型要么四个字节要么八个字节。viod*可以在内存中确定大小。
小贴士:
ANSI没有定义void的大小,在gcc编译器中做了扩展,对void定义了大小,可以使用sizeof求void大小。
上面程序片段的执行结果如下:
上述代码在bcc编译器中会编译出错。
在写C语言时要以标准C为准。
void指针的意义:
void*是一种更大的类型,可以接受任意指针类型。
程序示例:
1 #include <stdio.h> 2 3 void MemSet(void* src, int length, unsigned char n) 4 { 5 unsigned char* p = (unsigned char*)src; 6 7 int i = 0; 8 9 for(i=0; i<length; i++) 10 { 11 p[i] = n; 12 } 13 } 14 15 int main() 16 { 17 int a[5]; 18 int i = 0; 19 20 MemSet(a, sizeof(a), 0); 21 22 for(i=0; i<5; i++) 23 { 24 printf("%d ", a[i]); 25 } 26 27 return 0; 28 }
MemSet的第一个参数是void*,我们要设置一段内存的值,并不关心这段内存是char*还是int*的,因此,第一个参数为void*类型,可以接受任意类型的指针。
执行结果如下:
小结: