注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。
测试环境:Ubuntu 10.10
GCC版本:4.4.5
一、遭人遗弃的goto
1)高手潜规则:禁用goto
2)项目经验:程序质量与goto的出现次数成反比
3)最后的判决:将goto打入冷宫
实例分析
goto副作用分析
8-1.c
#include <stdio.h>
#include <malloc.h>
void func(int n)
{
int* p = null;
if(n < 0)
{
goto STATUS;
}
p = (int*)malloc(sizeof(int) * n);
STATUS:
p[0] = n;
free(p);
}
int main()
{
printf("begin...\n");
printf("func(1)\n");
func(1);
printf("func(-1)\n");
func(-1);
printf("end...\n");
return 0;
}
操作:
1) gcc 8-1.c -o 8-1.out编译正确,打印结果:
begin...
func(1)
func(-1)
Segmentation fault(core dumped) 段错误
分析:
执行到func(-1)的free(p)由于没有申请堆内存,释放时NULL报错,产生段错误。
二、void的意义
1)void修饰函数返回值和参数
- 如果函数没有返回值,那么应该将其声明为void
- 如果函数没有参数,应该声明其参数为void
void修饰函数返回值和参数是为了表示“无”
#include <stdio.h>
f()
{
}
int main()
{
int i = f(1,2,3);
return 0;
}
编译正常,无任何输出
2)不存在void变量
- C语言没有定义void究竟是多大内存的别名
没有void的标尺,无法在内存中裁剪出void对应的变量
#include <stdio.h>
int main()
{
void var; // error
void array[5]; // error
void* pv; // OK
return 0;
}
3)小贴士
- ANSIC:标准C语言的规范
- 扩展C:在ANSIC的基础上进行了扩充
#include<stdio.h>
int main()
{
printf("%d\n",sizeof(void));
return 0;
}
gcc编译
打印结果:
1
上面的代码在ASNIC编译器中无法通过编译(比如VS2013),但是对于支持GUN标准的gcc编译器而言是合法的。
4)void指针的意义
- C语言规定只有相同类型的指针才可以相互赋值
- void* 指针作为左值用于"接收"任意类型的指针
- void* 指针作为右值使用时需要进行强制类型转换(比如malloc)
int* pI = (int*)malloc(sizeof(int))
char* pC = (char*)malloc(sizeof(char))
void* p = NULL;
int* pni = NULL;
char* pnc = NULL;
指针类型
p = pI; // ok void* = int*
pni = p; // error int* = void*
p = pC; // ok
pnc = p; // error
实例分析
通过void* 实现MemSet函数
8-2.c
#include <stdio.h>
void MemSet(void* src, int length, unsigned char n)
{
unsigned char* p = (unsigned char*)src;//强制类型转换,得到的是
//数组a[]的首地址,因此有p[i]
int i = 0;
for(i=0; i<length; i++)
{
p[i] = n; //用数组形式赋值,代替了*p
}
}
//数组退化为指针
int main()
{
int a[5];
int i = 0;
MemSet(a, sizeof(a), 0);
for(i=0; i<5; i++)
{
printf("%d\n",a[i]);
}
return 0;
}
操作:
1) gcc 8-2.c -o 8-2.out编译正确,打印结果:
0
0
0
0
0
小结
1) 现在软件工程中禁用goto语句
2) void是一种抽象的数据类型
3) void类型不能用于定义变量
4) void类型用于声明函数无参数(函数)
5) void类型不用声明函数无返回值(函数)
6) 可以定义void* 类型的指针
7) void* 类型的指针可以接受任意类型的指针值