C语言进阶——goto 和 void 的分析08

遭人遗弃的goto:

  • 高手潜规则:禁止使用goto
  • 项目经验:程序质量与goto的出现次数成反比
  • 最后的判决:将goto打入冷宫

程序示例1:(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...\n");
25     
26     printf("func(1)\n");
27     
28     func(1);
29     
30     printf("func(-1)\n");
31     
32     func(-1);
33     
34     printf("end...\n");
35     
36     return 0;
37 }

在函数中,从第8行到第16行本来是顺序执行的,可是当满组if条件的时候,就会破环这个程序原来的结构,导致出现错误。

 

goto语句就介绍到这里,下面来讲一下void:

void修饰函数返回值和参数:

  • 如果函数没有返回值,那么就应该将其声明为void
  • 如果函数没有参数,应该声明其参数为void

程序示例2:

 1 #include<stdio.h>
 2 
 3 f()
 4 {
 5     
 6 }
 7 
 8 int main()
 9 {
10     int i= f(1,2,3,4);
11     printf("%d\n",i);
12     return 0;
13 }

上面这段程序,可能会有人认为它在编译的时候会报错,其实不然:

  • 当函数没有返回值的时候,会默认返回一个int类型,也就是说你可以在这个函数里面加上一条return用于返回一个int语句,但是如果你不加的话,编译器会默认给你返回一个1。
  • 当函数的参数列表没有任何参数,且没有声明为void,默认可以接受任意多个参数

为什莫会这样呢,因为C语言不是一种强类型的语言。

程序示例3:

#include<stdio.h>

 void f(void)
{
    return 3;
}

int main()
{
    int i= f(1,2,3,4);//error
    printf("%d\n",i);
    return 0;
}

这段代码是将示例2中的代码稍加修改得到的,现在这段代码是不可以通过编译的。

 

  void的意义,有人想到,void既然是一种类型,那么我们是否可以像使用其他类型,比如说int,char 一样的使用它来创建变量呢?答案是否定的,你可以将void理解为一种抽象类型。

  不存在void普通变量(指针变量例外),C语言中没有定义void究竟是多大内存的别名,也就是说没有void标尺,无法在内存中裁剪出void对应的变量。

小贴士:

ANSIC:标准C语言规范

扩展C:在ANSIC的基础上进行了扩充

 

程序示例4:

1 #include<stdio.h>
2 
3 int main()
4 {
5     printf("%d\n",sizeof(void));
6     return 0;
7 }

上面这段代码在ANSIC编译器中无法通过编译,但是对于支持GNU标准的额gcc编译器而言是合法的。(但是我们最好是按照C语言标准来学习C语言,所以我们可以认为上面这段代码是不合法的,有的编译器生产厂家认为标准C的特性不够,是自己加上去的)

void虽然不能定义普通的变量,但是可以创建指针变量:

  • C语言规定只有相同类型的指针才可以相互赋值
  • void *  指针作为左值用于 “接受” 任意类型的指针
  • void* 指针作为右值使用时需要进行强制类型转换

程序示例5:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 int main()
 4 {
 5     int *pi = (int *) malloc(sizeof(int));
 6     char *pc = (char *)malloc(sizeof(char));
 7     void *p=NULL;
 8     int *pni=NULL;
 9     char * pnc=NULL;
10 
11     p=pi; //ok
12     pni =p; //error
13 
14     p=pc; //ok
15     pnc = p;  //error
16 
17     return 0;
18 }

在标准C语言中12 和 15 行会报错,但是有的编译器会扩展C语言规范,所以上述代码在你的编译器中有可能时通过的。

 

程序示例6:

#include <stdio.h>

void MemSet(void* src, int length, unsigned char n)
{
    unsigned char* p = (unsigned char*)src;

    int i = 0;

    for(i=0; i<length; i++)
    {
        p[i] = n;
    }
}

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;
}

MeMset这个函数用void类型的指针接受一个int(也可以接受其他类型的指针),然后将其强制转化为unsigned char 类型的指针,将其每个字节都设置为0,最后在主函数会输出 5 个0,因为每一个字节都被设置为0,所以四个为0的字节组合的一个int类型的值也是0,你也可以将他的每个自己设置为其他的数。

 

小结:

  • 现代软件工程中禁止使用goto语句
  • void是一种抽象类型的数据类型
  • void类型不能用于定义变量
  • void类型用于声明函数的无参数
  • void类型用于用于声明函数的无返回值
  • 可以定义void* 类型的指针
  • void* 类型的子真可以接受任意类型的指针值

 

posted @ 2018-06-23 09:59  清浅...忆回  阅读(314)  评论(0编辑  收藏  举报