• C语言中 continue,goto, void(空类型),你不知道的事情 ???


    C语言中 continue,goto, void(空类型),你不知道的事情 ???

    在这里插入图片描述

    每博一文案

    一个人从满心期待,走到心灰意冷,都是由一些生活中很小的瞬间积累起来的,
    每失望一次就减一份热情,知道热情被消磨殆尽,故事就结束了,从来都没有
    顷刻之间的心灰意冷,有的,只是日积月累的看透,你以为放弃是一瞬间的决定,
    其实那个人已经在冷风中站了很久很久,当热情没有回应付出不被珍惜,真心没被善待,
    再热的心也有变冷的一刻,这世间所有的爱都是快走,所遇的人都是缘分,不要等一个人
    热情耗尽,才知道有些人一旦错过,就不在了。
                                       ——————  一禅心灵庙语
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8


    break 与 continue

    • break 表示跳出循环,
    • continue 表示跳出本次(一次循环) ,可continue 跳出循环后,又是跳出到了循环的那个位置

    continue 跳出循环后,又是跳出到了循环的什么位置处

    1. 在 while() 循环中,请看下面的代码,其中当满足条件时,continue 跳转到什么位置中 ???
    #define  _CRT_SECURE_NO_WARNINGS  1
    #include
    int main()
    {
    
    	int  i = 0;
    	while (i < 10)
    	{
    		i++;
    		if (i % 2 == 0)
    		{
    			printf("continue:\n");
    			continue; // 跳转的位置
    		}
    		printf(" %d ", i);
    		
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    是,(1)号,还是 (2)号 ,位置处, 答案: 是 跳转到 (2) 号位置(循环条件判定的位置),我们调试运行验证看看就知道了。从下面的调试结果上看,结论并没有错,跳转的位置是在 循环条件判断的位置处

    在这里插入图片描述


    1. 在 do…while( )循环中 ,请看下面的代码,其中当满足条件时,continue 又是跳转到什么位置中 ???
    int main()
    {
    	int i = 0;
    
    	do {
    		i++;
    		
    		if (i % 2 == 0)
    		{
    			printf("continue: \n");
    			continue; // 跳出位置
    		}
    		printf(" %d ", i);
    
    	} while (i < 10);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    是,(1)号,还是 (2)号 ,位置处, 答案: 同样是 跳转到 (2)号 位置(循环条件的判定),同样的,我们再通过调试运行验证看看就知道了。从下面的调试结果上看,结论并没有错,跳转的位置是在 循环条件判断的位置处

    在这里插入图片描述


    1. 在 for( ; ; ) 循环中 ,其中当满足条件时,continue 又是跳转到什么位置中 ???
    int main()
    {
    	for (int i = 0; i < 10;i++ )
    	{
    
    		if (i % 2 == 0)
    		{
    			printf(" continue: \n");
    			continue; // 跳转位置
    		}
    
    		printf(" %d ", i);
    	}
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    是,(1)号,还是 (2)号 ,位置处, 答案: 跳转到 (2) 号位置( 循环条件更新处),这里因为for( ) 循环语句的特殊处,我们调试无法直接判断是跳转的具体的位置处,所以这里我们使用另外一种方法,就是假设法
    假设我们 continue 跳转的位置是在 i < 10 (循环条件判定的位置处) 的话,根据 for( )循环语句的执行流程 : 初始化循环条件 ——> 循环条件的判定,真——> 执行循环内的语句 ——> 最后更新循环条件——> 再循环条件的判定… , 我们可以确定的是,如果 continue 跳转的的位置是循环条件的判定的话,i 将一直 是 2 , 因为 continue 的跳转,导致无限循环;
    而我们运行结果却,不是无限循环,所以可以得出的结论是 **在 for( ) 循环语句中 continue 跳转的位置是在循环条件更新处

    在这里插入图片描述

    在这里插入图片描述


    循环语句的注意点

    1. 在多重循环中,如果有可能,应当将最长的循环放在内层,最短的循环放在最外层,以减少 CPU 跨切循环的次数。如下:两个代码实例比较

    在这里插入图片描述

    1. 建议 for 循环语句的循环控制变量的取值采用 “半开半闭区间” 的写法。 半开半闭区间的写法和闭区间的写法虽然在功能作用上是相同的,但相比之下,半开半闭的写法更加直观。二者对比如下表:

    在这里插入图片描述

    1. 尽量不要在 for 循环体内修改循环变量的,防止循环失控
    for( int i = 0; i < 10 ; i++)
    {
        i = 10; // 不可,很可能违背了,你的原意
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 循环要尽可能短,要使代码清晰,一目了然
    2. for 语句的循环条件的判定不要包含任何浮点类型的对象。
      因为浮点类型存在,精度上的误差,可能会改变循环的次数 。具体原因,大家可以移步到 🔜🔜🔜 浮点数的精确度的探究_ChinaRainbowSea的博客-CSDN博客

    goto 关键字

    Linux内核代码中存在这大量的 goto语句 ,所以我们并不能太过片面的忽略掉它,如下:

    在这里插入图片描述

    一般来说,编码的水平与 goto 使用的次数成反比。有的人主张慎用但不禁用 goto 语句,但我个人主张禁用的,

    自从提倡结构化设计以来,goto 就成了有争议的语句,首先,由于 goto 语句可以灵活跳转,但如果不加以限制的话,它的确会破坏结构化的设计;其次 goto 语句经常带来错误或隐患,它可能跳过了变量的初始化,重要的计算语句等,如下:

     int * p = NULL;
    goto end;
    p = (int*)malloc(sizeof(int));   // 被 goto 语句跳转了,并没有初始化到
    end:
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    goto 语句的使用

    int main()
    {
    	goto end;
    	printf("hello 1 \n");
    	printf("hello 2 \n");
    	end:
    	printf("hello 3 \n");
    	printf("hello 4 \n");
    	printf("hello 5 \n");
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述


    goto 语句的无限循环 的使用

    int main()
    {
    	end:
    	printf("hello 1 \n");
    	printf("hello 2 \n");
    	printf("hello 3 \n");
    	goto end;
    	printf("hello 4 \n");
    	printf("hello 5 \n");
    
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述


    goto 语句实现简单的循环

    int main()
    {
    	int i = 0;
    end:
    	i++;
    	printf("%d ", i);
    
    	if (i < 10)
    	{
    		goto end;
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述


    void 类型

    void 有什么好讲的呢 ?如果你说没有,那就没有,但如果你说有,那就真的有。

    void 的字面意思是 “空类型”

    1. void不能代表一个真实的变量

    void 类型不可以定义变量:

    int main()
    {
    	void x;  
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述


    为什么 void 类型不可以定义变量

    定义变量的本质是:开辟空间,存放数据,而 void 作为空类型,在 VS 2019 中是没有开辟空间的,大小上 VS 2019 定义为了 0 ,如下: 0 自然无法存放数据,就失去了定义变量的意义了,

    在这里插入图片描述

    但是在 Linux 中的 gcc 编译器定义该 大小是 1,无论是 VS 2019 定义的 0 ,还是 Linux 中的 gcc 的 1 ,理论上是不应该开辟空间的,即使开辟了空间,也仅仅是作为一个 占位符
    所以既然无法开辟空间,那么也就无法作为正常变量使用,即无法正常使用,编译器也解释为 空类型,就强制不允许定义变量操作,

    另一种简单的说法就是,void类型的在内存中的大小不确定,无法开辟确定的空间,所以就不开辟空间的了,就无法作为正常变量使用了。


    2. void 修饰函数返回值

    在C语言中,凡是不加返回值类型的函数,就会被编译器作为 返回 int 类型处理 ,但是,有许多程序员却误认为是 void 类型 ,如下:默认是 int 类型

    fun()
    {
    	return 10;
    }
    
    int main()
    {
    	printf("%d", fun());
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述


    void 修饰 函数的返回值类型:1.作为占位符,让用户明确该函数不需要返回值,提高代码的可读性,2. 告知编译器,这个函数的返回值(不要)无法接受。

    我们在编写一个程序时,对于任何函数都必须一个不漏地指定其返回类型。返回类型是 int 虽然默认是,但也不要省略,阅读其代码的时候,是这个家伙 忘记了,还是故意偷懒省略不写呢???,
    如果函数没有返回值,那么一定要声明为 void 类型。这是程序良好可读性的需要,也是编程规范性的要求,另外,加上 void 类型声明后,也可以发挥代码的 “ 自注释” 的作用。所谓代码的 “自注释” 即代码能自己注释自己。

    void fun()
    {
    	return 10;
    }
    
    int main()
    {
    	printf("%d", fun());  // 报错, 函数 fun() 是 void返回值类型
    
    	return 0;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述


    3. void 修饰函数参数

    表示:这个函数不接受任何参数;并给予警告,

    void 充当函数的参数列表: 表示告知用户和编译器,该函数不需要传参数,强行传参数的话,不会报错,但会给予警告。而相反,如果一个函数的没有参数,也没有被 void修饰参数列表的话,强制传参数的话,不会报错,也不会发出警告 。

    所以如果一个函数没有参数的话,将函数的参数列表设置成 void 是一个好的编程习惯,可以将错误明确的提前发现。还会给予警告。

    void test1()
    {
    	printf("test1\n");
    
    }
    
    void test2(void)
    {
    	printf("test2\n");
    }
    
    
    int main()
    {
    	test1(1,2,3);  // 不会报错,也不给予警告
    	test2(1,2,3);  // 不会报错,但会给予警告
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    在这里插入图片描述


    void* 指针

    1. 为什么 void 不能定义变量可以定义 void* 指针

    因为 void* 是指针,即地址,其空间大小是可以明确出来的,32位 4 个字节,64位 8 个字节空间的大小,

    int main()
    {
    	void* p = NULL;
    
    	printf("%d",sizeof(p));
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述


    void* 类型的指针可以被任意的类型的指针接受

    int main()
    {
    
    	void* p = NULL;
    	int* x = NULL;
    	double* y = NULL;
    	
    	x = p;
    	y = p;  // void* 指针可以被任意类型的指针接受
    
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述


    同样 void* 类型的指针可以接受任何类型的指针类型

    int main()
    {
    	void* p = NULL;
    	int* x = NULL;
    	double* y = NULL;
    
    	p = x;  // void* 类型的指针可以接受任何类型的指针
    	p = y;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述


    这一点,十分的常用,如:在一些系统,接口的设计上,尽量设计成通用的接口如:

    在这里插入图片描述


    在这里插入图片描述


    c库 的网站地址如下:🔜🔜🔜 memcmp - C++ Reference (cplusplus.com)

    定义的void* 指针 类型不可以通过 ++,–,指针地址的移动 为什么呢?

    如下代码中的 p 指针地址 ++,–,操作,的实质是移动根据对应类型的所占字节的大小,移动对应的字节位数,而 void* 是空类型,在 VS 2019 中定义的类型大小为 0 个字节,移动 0 个字节数没有意义。

    int main()
    {
    	void* p = NULL;
    	p++;  // 报错
    	p--;  // 报错
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述


    void* 类型的指针式不可以被解引用的 ,

    为什么 ?? ?

    因为解引用是表示 把存放到该指针中的地址的变量,通过地址再根据类型的大小把数据取出来,而 void 空类型 ,在 VS 2019 中定义的大小为 0 ,根据类型大小 0 怎么取数据出来。

    还有一种说法就是,void 类型的大小不确定,不知道如何取出。

    int main()
    {
    	int num = 10;
    	void* p = &num;
    	printf("%d", *p);
        
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述


    正常类型是可以解引用的。

    int main()
    {
    	int num = 10;
    	int* p = &num;
    	printf("%d", *p);
    
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述


    最后:

    限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见!

  • 相关阅读:
    C# 正则表达式大全
    股票跌幅榜查询易语言代码
    pthead 创建与销毁详解 pthread_create pthread_join pthread_exit pthread_detach
    UE4 利用WEBUI插件完成UE与JS的交互 (UE4嵌入WEB)
    基础算法:大整数减法
    【Sentinel】Sentinel配置zk持久化
    C++中invoke与function的区别
    设计模式(简要,应付软考)
    基于阿里云服务实现短信验证码功能
    前缀(波兰式)、中缀、后缀(逆波兰)表达式;中缀转后缀
  • 原文地址:https://blog.csdn.net/weixin_61635597/article/details/126161892