第8课 - goto和void分析
第8课 - goto和void分析
1. 遭人嫌弃的goto
(1)高手潜规则:禁用goto
(2)项目经验:程序质量与goto的出现次数成反比;c语言是一门结构化语言,goto会破坏C语言的结构化特性。
(3)最后的判决:将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 p = (int*)malloc(sizeof(int) * n); // 当 n<0 时不执行这行 14 15 STATUS: 16 p[0] = n; // n<0 时,p为野指针,会产生段错误 17 18 free(p); 19 } 20 21 int main() 22 { 23 printf("begin...\n"); 24 25 printf("func(1)\n"); 26 func(1); 27 28 printf("func(-1)\n"); 29 func(-1); 30 31 printf("end...\n"); 32 33 return 0; 34 }
2. void的意义
2.1 void修饰函数返回值和参数
(1)void 修饰函数返回值和参数是为了表示 "无"
(2)如果函数没有返回值,那么应该将其声明为void;否则编译器默认返回值类型为int
(3)如果函数没有参数,应该声明其参数为void;否则编译器默认函数可以传递任意多个参数
1 #include <stdio.h> 2 3 /* 4 // 若函数没有返回值,编译器默认返回值为int类型 5 // 若函数没有参数,编译器默认函数可以传递任意个参数 6 f() 7 { 8 9 } 10 */ 11 12 void f(void) // 函数没有返回值,不接受参数 13 { 14 15 } 16 17 int main() 18 { 19 // int i = f(1, 2, 3); 20 21 return 0; 22 }
2.2 不存在void变量
C语言没有定义void究竟是多大内存的别名,因此没有void的标尺,无法在内存中裁剪出void对应的变量(void只是一种抽象的类型)。
1 #include <stdio.h> 2 3 int main() 4 { 5 // void var; // error 6 // void array[5]; // error 7 8 void *pv; // 指针要么为4字节,要么为8字节,可以定义void类型的指针变量 9 10 return 0; 11 }
小贴士:
ANSI C:标准C语言的规范
扩展C:编译器厂商在ANSI C的基础上进行了扩充,像我们平时使用的gcc、VS编译器就是使用的扩展C
【void在ANSI C和扩展C中的区别】
1 #include <stdio.h> 2 3 int main() 4 { 5 printf("cc sizeof(void) = %zu\n", sizeof(void)); // 在ANSI C编译器中编译无法通过 6 // 在支持GNU标准的gcc编译器中编译通过,结果为1 7 8 return 0; 9 }
bcc32编译器(使用ANSI C标准) ==> 编译失败
gcc编译器 ==> 编译通过
2.3 void指针的意义
(1)C语言规定只有相同类型的指针才可以相互赋值
(2)void *指针作为左值用于接收任意类型的指针
(3)void *指针作为右值使用时需要进行强制类型转换
【通过void*实现MemSet函数】
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]; // char a[5] double 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\n", a[i]); 25 } 26 27 return 0; 28 }