3

悄悄地学C语言,一不小心就成了万字长文道尽字符串、分支语句和循环语句

 2 years ago
source link: https://blog.csdn.net/Yxh666/article/details/119361828
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、字符串、转义字符、注释

1、字符串

"hello world"
这种由双引号引起来的一串字符称为字符串字面值,或者简称字符串
注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算做字符串内容。

//字符串例子
#include<stdio.h>
int main()
{
    "csdn";
    ""; //空字符串
    return 0;
}

那我们既然创建了字符串,但是应该存到哪里,这就涉及一个名为数组的概念,这里就不做太多解释,我会在以后介绍,它就是一个存储数据的结构

#include<stdio.h>
int main()
{
    char arr1[] = "csdn"; //创建数组存入字符串
    printf("%s\n", arr1);
    return 0;
}

在这里插入图片描述

那我们同样在创建另一个数组,但是存放的字符串是这样的

#include<stdio.h>
int main()
{
    char arr1[] = "csdn"; //创建数组存入字符串
    char arr2[] = {'a','b','c'}; //存放在字典里面的
    printf("%s\n", arr1);
    printf("%s\n", arr2);
    return 0;
}

输出出来却是这样的:

在这里插入图片描述

那我们来调试一下看看,按F10,进入main函数
先把两个数组创建起来

会在下面打开监视,如果没有打开直接Ctrl+Shift+D如下面:

然后我们输入arr1arr2看一下数组的内容都是什么
在这里插入图片描述

可以看到arr1中有4个元素,arr2有3个元素,这两个数组的差异好像就是差了一个0,就导致输出的结果不一样了

那我们这样,也给arr2一个0,然后我们运行程序

在这里插入图片描述

结果是和上面的一样了,那这样能不能说明一个问题呢,那我们分析一下两种的区别

第一种的话是把字符串csdn放到arr1里面,第二种只是把三个字符放到了arr2

以字符串放进数组,它还会包含一个0,如果以单个元素a、b、c放进数组,是没有0的,那么就是因为这个0,导致结果的不同

其实 “csdn” 拆分出来就是 ------> “c”,“s”,“d”,“n”,"\0" 它会在末尾偷偷的隐藏一个 \0 ,那么这个 \0 的值就是 0,那么这个 \0 就是 字符串的结束标志,所以输出完数组的字符串之后就不会在输出别的了

那在看第二个数组,存入三个字符,但是没有结束标志 \0 ,所以它打印完输出后,还会继续输出,这个输出的就是一个随机值

同样的我们上面也说了, \0 不作为字符长度,就是说它跟随字符串存入,不过是没有长度的

因为我们的字符串都是有一个值的,这个值怎么看,给大家推荐一个表就是,ASCII码表,这个直接百度就可找到

那么我们看下这两个数组的长度

#include<stdio.h>
int main()
{
	char arr1[] = "csdn";
	char arr2[] = {'a', 'b', 'c'};
	printf("%d\n", strlen(arr1));  //strlen --> string length 计算字符串长度
	printf("%d\n", strlen(arr2));
	return 0;
}

在这里插入图片描述

那我们看这里为什么是这样的长度,第一种csdn字符串,是一个一个算的,那么算到n之后,再到后面就是 \0\0是不计入字符串长度的

第二种计算字符a、b、c的长度完成之后,是没有 \0 的,所以产生一些随机值,这些随机值也要统计长度,只要是没有遇到 \0 就一直统计,直到找到一个 \0 才结束

2、转义字符

什么是转义字符,简单理解就是转变原来的意思

这个的输出打印不换行

#include<stdio.h>
int main()
{
    printf("abc");
    return 0;
}

在这里插入图片描述

#include<stdio.h>
int main()
{
    printf("abc\n");
    return 0;
}

在这里插入图片描述

这个 \n ,单凭一个n来说就是普通字符的意思,但是加了一个 \ 它的意思就变成了换行

那我们在来写代码,这次我想输出我的c盘下的某某某个文件

#include<stdio.h>
int main()
{
    printf("c:\test\nwe_file\readme.c");
    return 0;
}

在这里插入图片描述

输出的结果和我们预想的不一样啊,实际上输出这句话里面仍然用到了转义字符,比如:

t本身就是一个普通的字符,但是加上 \,变成了 \t,那这个含义就是一个table,就是空格的意思,在键盘Q的左边就是这个table

\r,就是换行,可以看到打印到eadme.c 的时候是换行输出了

两个 \\ 的意思就是防止它被解释为一个转义序列符,通俗讲就是两个 \\ 保证一个 \ 是正常的,可以当成正常使用的,是不被当转义符的,如果我解释的还不都透彻,那就直接看看我的代码

那我们就是想要输出要打印的的意思呢?可以这样,在每个 \ 之前再加一个 \ ,它就可以输出了

#include<stdio.h>
int main()
{
    printf("c:\\test\\nwe_file\\readme.c");
    return 0;
}

在这里插入图片描述

我们再来看一个转义的字符

#include<stdio.h>
#include<string.h> //strlen()需要用的头文件
int main()
{
    printf("%d\n",strlen("c:\test\32\readme.c"));
    return 0;
}

这段代码就是打印字符串的长度,先不看结果,你可以在心里自己算算这个字符串的长度

结果是这个,你算对了嘛

在这里插入图片描述

那我们看这个代码 c:\test\32\readme.c ,首先 \t、\r 是转义字符,都看成是1个长度,然后其实 \32 也是一个转义字符,这是一个八进制转义数字

那针对这个进制转义字符有两个 \ddd、\xdd

  • \dddddd表示1-3个八进制数字。如 :\130 X
  • \xdddd 表示2个十六进制数字。如:\x30 0

那我们看这个 \32 ,这是八进制转义数字,然后转成十进制数字是 2626 在ASCII表上表示的向右的箭头,那么这样也就符合我们刚刚打印的结果了

同样我们打印一个十六进制的转义字符看一下

#include<stdio.h>
int main()
{
    printf("%c\n",'\x70');
    return 0;
}

这个 \x70 先转换为十进制数字112,在转换成ASCII码表就是小写p

这个没有什么太多可解释的,注释风格有两个

  • /*xxxxxxx*/      c语言注释风格
    - 缺点是不能嵌套注释

  • List item

  • //xxxxxx     c++注释风格
    - 可以注释一行或多行

注释的作用就是有两种

  1. 这段代码先不执行,所以先注释掉
  2. 给这段代码写点信息,不管是别人看代码,或者是我在以后看代码,看不明白这段代码的意思

二、分支语句

分支语句:

1、if语句

什么是语句?
在c语言中由 ; 号隔开的就是一条语句
比如:return 0;,这就是一条语句,它使用 ; 作为结束,这就称为一条语句
当然只有一个 ; 这也算一个语句,什么都不写,只有一个 ; 这也被叫做空语句

当然不可以不加,也不能乱加,否则会报错的

语法结构:

//第一种
if(表达式)
    语句;

//第二种
if(表达式)
    语句1;
else
    语句2;
    
//第三种多分支
if(表达式1)
    语句1;
else if(表达式2)
    语句2;
else
    语句3;

我们分别看这三种的意思都是什么:
第一种,如果表达式为非0,即为真,那就执行语句,如果为假,什么都不执行

第二种,如果表达式为真,执行语句1,否则执行语句2

第三种,如果如表达式1为真,就执行语句1,另外如果表达式2成立,就执行语句2,否则就执行语句3,而且else if是可以有很多个的,但不管有几个,这第三种多分支语句都是只能执行一个语句

//单分支语句
#include<stdio.h>
int main()
{
    int age = 20;
    if(age<18)
        printf("未成年...\n");
    return 0;
}

在这里插入图片描述

我们看这样他不符合我的判断条件,是什么都不输出的

//双分支语句
#include<stdio.h>
int main()
{
    int age = 20;
    if(age<18)
        printf("未成年...\n");
    else
        printf("已经成年了\n");
    return 0;
}

在这里插入图片描述

//多分支语句
#include<stdio.h>
int main()
{
    int age = 18;
    if(age<18)
        printf("未成年...\n");
    else if(age>=18 && age<35)
        printf("青年\n");
    else if(age>=35 && age<60)
        printf("中年\n");
    else
        printf("老年\n");
    return 0;
}

还可以这样写:

//多分支语句2
#include<stdio.h>
int main()
{
    int age = 18;
    if(age<18)
        printf("未成年...\n");
    else
    {
        if(age>=18 && age<35)
            printf("青年\n");
        else if(age>=35 && age<60)
            printf("中年\n");
        else
            printf("老年\n")
    }
    return 0;
}

这样就是把一段代码分成两大块,一类是未成年,一类是成年之后的。

在这里插入图片描述

这里说明一下上面else下面的 {} ,如果你的条件成立的话,并且要执行多条语句的时候,必须要加 {},也叫代码块

#include<stdio.h>
int main()
{
	int age = 17;
	if (age < 18)
		printf("未成年...\n");
		printf("及时行乐啊~");
	else
		printf("成年人");
	return 0;
}

在这里插入图片描述

这样的话是错误的,必须要加代码块,如下

#include<stdio.h>
int main()
{
	int age = 17;
	if (age < 18)
	{
		printf("未成年...\n");
		printf("及时行乐啊~");
	}
	else
		printf("成年人");
	return 0;
}

接下来,解释一下悬空else

在这里插入图片描述
就先看最左边的代码,你自己先猜猜它会输出什么

其实什么都不会输出吧,为什么?我们是不是在理解上,认为,定义的a=0,但是它进不去if判断语句,就会执行else,其实思想是对的,但是代码执行不是那样的,简单明了说就是,else会匹配离它最近的if,组成一个分支语句,同时也不建议这样写代码,质量太差

2、switch语句

//语法结构
switch(整型表达式)  //必须为整型,否则报错
{
    语句项;
}

//语句项如下:
    case 整型常量表达式:  //必须为常量,不可以为变量,否则报错
        语句;

比如我现在要判断星期几,就可以用到if、else if、else 但是这样写太过于繁琐,我们要写很多的else if,所以下面就用到了,switch语句,它也是分支语句,也常用于多分支语句

#include<stdio.h>
int main()
{
    int day = 0;
    scanf("%d",&day);
    switch(day)
    {
    case 1:
        printf("星期一\n");
        break;
    case 2:
        printf("星期二\n");
        break;
    case 3:
        printf("星期三\n");
        break;
    case 4:
        printf("星期四\n");
        break;
    case 5:
        printf("星期五\n");
        break;
    case 6:
        printf("星期六\n");
        break;
    case 7:
        printf("星期日\n");
        break;
    }
    return 0;
}

在这里插入图片描述

那我们看这个代码,switch(day),这个就是判断day的是多少,假如是3吧,那我就走到case 3分支,也就是输出星期三,输出完成之后停止就是break,跳出本次分支语句,当然并不是每次都要加break停止的,比如下面这个:

#include<stdio.h>
int main()
{
    int day = 0;
    scanf("%d",&day);
    switch(day)
    {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        printf("工作日\n");
        break;
    case 6:
    case 7:
        printf("休息日\n");
        break;
    }
    return 0;
}

在这里插入图片描述

这样我们只要求到底是工作日还是休息日,那我们干脆直接删掉所有的,只留下case,因为它的流程是,不管你输入的是几 (暂不考虑以外的) , 只要是没有break,我就会一直向下执行,直到遇到break或者结束分支,才停止下来

那我们现在考虑一下,如果我这个判断工作日还是休息日,只有1到7,那你输入个8或者别的,怎么办,可以这样搞,用default判断错误,就是友好的提示一下

#include<stdio.h>
int main()
{
    int day = 0;
    scanf("%d",&day);
    switch(day)
    {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        printf("工作日\n");
        break;
    case 6:
    case 7:
        printf("休息日\n");
        break;
    default:
        printf("输入错误\n");
    }
    return 0;
}

在这里插入图片描述

三、循环语句

在开始循环语句之前,我们先说明两个跳出跳出循环语句:

  1. break
  2. continue

这个 break 我们之前用过几次,它的作用是结束循环语句,比如下面的伪代码,意思是,我定义年龄为18,循环开始,即开始打印,每循环一次就让年龄加一,等数值21,就 结束循环体 后面代码不再执行

年龄 = 18;
循环开始
{

    if age == 21
        break;
    printf("%d\n" ,age);
    年龄加1;
}

continue 是结束本次循环,看下面伪代码,这个代码就是循环开始一直走,年龄该加加,直到年龄来到14的时候会 结束本次循环及后面的代码 ,就是不会输出14,从15开始继续输出

年龄 = 10; 
循环开始
{
    年龄加1;
    if age == 14
        continue;
    printf("%d\n" ,age);

}

1、while循环

什么是循环,顾名思义就是一直的不停的,那我们就可以理解为我们每天都要睡觉,即固定的一个时间段做相同的事情,先可以这样理解

那我们生活不止要睡觉,你想想,当你在写代码,比如写一个if判断语句,你老板说让你输出一万个句相同的话,就比如 “你好帅”,你怎么输出,复制粘贴?

这样会让你的工作效率太低,那怎么办,这时候我们就用到了循环

语法结构

while(表达式)
    循环语句;

表达式条件为真,循环语句会直执行,然后跳到表达式进行判断,只要为真就执行,反之停止
什么是为真?C语言里,非0为真,-1也是真,反之为假

include<stdio.h>
int main()
{
    while(1)
        printf("你好帅\n")
    return 0;
}

这样就写了一个死循环,千万注意不要犯这样低级的错误,

tips:只要是循环,就一定要定义停止条件

那我们写一个打印1-10数字

#include<stdio.h>
int main()
{
	int i = 1;
	while (i <= 10) //表达式里面的条件为真就执行,假如a==11了,为假就不会执行了
	{
		printf("%d\n", i);
		i++; //每打印一次就自加1  a=1 a++ --> a==2 a++ --> a==3 ...以此类推,到11就大于10,就不会输出出来了
	}
	return 0;
}

在这里插入图片描述

接下来我们看一个代码

getchar是获取一个字符相当于scanf这个输入,putchar是输出输入的字符,它等同于printf,可以看下面代码,输入一个字符,然后打印出两个来,一个是putchar,另一个是printf打印出来的

#include<stdio.h>
int main()
{
    int ch = getchar();
    putchar(ch);
    printf("%c\n",ch);
    return 0;
}

在这里插入图片描述

那么接下来我们看这个代码,加上循环的输入输出

#include<stdio.h>
int main()
{
	int ch = 0;
	while ((ch = getchar()) != EOF)
	{
		putchar(ch);
	}
	return 0;
}

那上面代码就是我获取一个字符,然后只要不是EOF那就一直输出之前输入的字符,然后我们看结果

在这里插入图片描述

这是为什么呢,当我们输入EOF这个字符的时候,第一个E的时候,getchar就马上获取到了,然后OF同样,它不是作为一起出现的,而是单个出现的,所以它是停不下来的,而要停下来是要同时获取到这个三个字符才可以的

EOF这个字符是文件结束标志符,它的值为-1,那这个有什么作用呢,接下来我们慢慢介绍

下面这段代码,是一段获取密码的代码,意思就是我输入密码,然后确认输入的密码对否,如果对,就打印成功,不对就打印不成功

#include<stdio.h>
int main()
{
    int res = 0;
    char password[20] = {0};
    printf("请输入密码:>");
    scanf("%s",password);
    printf("请确认密码(Y/N):>");
    res = getchar();
    if(res == 'Y')
    {
        printf("密码确认成功\n");
    }
    else
    {
        printf("取消确认\n");
    }
    return 0;
}

我们看运行效果

在这里插入图片描述

为什么出现下面这个情况,我们这个代码里是有两个输入字符的函数scanf、getchar,这两个函数,当我输入字符后,字符会被放到输入缓冲区

那我们看第一个输入的字符,是那个密码,输入完成后注意,我们按了一下回车,因为scanf要获取字符就得输入完字符串后按回车,但是不会获取回车这个字符也就是 \n,获取完后,这时缓冲区里面就有一个 \n,它也算我们输入的,当然也会被存到缓冲区

所以这时候,getchar获取到缓冲期的字符,也就是 \n,那么它肯定不等于Y,所以它只有继续向下执行代码,那我们是else,就输出了取消确认

那我们怎么改一下呢,我们试想一下,当我们输入的字符被scanf获取完后,缓冲区还剩一个 \n ,那就直接用getchar先给它获取一下不就拿到了吗,这样缓冲区就没有东西,就能重新获取了

#include<stdio.h>
int main()
{
    int res = 0;
    char password[20] = {0};
    printf("请输入密码:>");
    scanf("%s",password); //输入字符,存在password
    
    getchar(); //获取缓冲区的字符
    printf("请确认密码(Y/N):>");
    res = getchar();
    if(res == 'Y')
    {
        printf("密码确认成功\n");
    }
    else
    {
        printf("取消确认\n");
    }
    return 0;
}

在这里插入图片描述

这个代码还是有问题,那我们输入 123456 ABCDE 注意中间有一个空格,那scanf获取的是空格前面123456,那么getchar在获取是获取的是空格,那缓冲区还是有一个 ABCDE 这样还是存在,还是会走else,那我们就可以用上面的while循环进行解决

用循环判断getchar获取到的是不是 \n,只要不是,就继续获取,直到获取到 \n结束,那循环体的代码也没有什么可执行的,就放一个 ; 空语句

#include<stdio.h>
int main()
{
    int ret = 0;
    int ch = 0;
    char password[20] = {0};
    printf("请输入密码:>");
    scanf("%s",password);
    while((ch=getchar()) != '\n')
    {
        ;
    }
    printf("请确认密码(Y/N):>");
    res = getchar();
    if(res == 'Y')
    {
        printf("密码确认成功\n");
    }
    else
    {
        printf("取消确认\n");
    }
    return 0;
}

在这里插入图片描述

2、for循环

for循环是我们平时用的最多的循环语句,它的语法如下:

for(表达式1; 表达式2; 表达式3)
    循环语句;

表达式1: 用来循环变量初始化
表达式2: 用于判断循环终止条件
表达式3: 用于循环条件调整

那为什么for循环用的最多呢,我们对比while循环它的语法

int a = 0;
while(a<10)
{
    i++;
}

单从语法上讲,它是先有一行定义初始化循环变量,对应我们for的表达式1

再有一个判断循环终止条件,也就是表达式2

最后是一个循环条件调整表达式3

就单纯感觉好繁琐,一行一句代码,那for就简单,直接在一行上写上所有的,起码清楚
那我们在想,定义变量是都要定义在上面,假如我们定义了一百个变量,然后,循环体又写了几百行代码,脑我们这时候,想换一个变量是不是还得翻阅,那这可能就一不小心就修改错误,让我们的代码跑废了,这就是while循环它的条件太分散的

而for循环就是集中的,在一行上面,也比较清楚,这是比while循环方便的一个地方

那接下来我们就写一个 for 循环,实现打印1-10的数字

#include<stdio.h>
int main()
{
    int i = 0;
    for(i=1; i<=10; i++)
    {
        printf("%d ", i);
    }
    return 0;
}

在这里插入图片描述

for 循环的执行流程为下

在这里插入图片描述
for语句的循环控制变量
建议:

  1. 不在for 循环体内修改循环变量,防止for 循环失去控制
#include<stdio.h>
int main()
{
	int i = 0;
	for (i = 1; i <= 10; i++)
	{
		if (i = 6) // 这里是赋值
		{
			printf("hahah\n");
		}
		printf("%d ", i);
	}
	return 0;
}

上面的代码会导致死循环,这里不再展示

  1. 建议for 语句的循环控制变量的取值采用前闭后开区间写法
#include<stdio.h>
int main()
{
    int i = 0;
    for(i=0; i<10; i++)  //前闭后开 这样10会表示某种意思,比如打印10次,执行10次
    {
        printf("%d ", i);
    }
    return 0;
}

当然,我们不是说所有的代码都要前闭后开区间这种写法,需要视情况而定

for循环的省略
for循环的三个表达式的部分都可以省略,但是注意,如果for循环的判断部分被省略,那么判断条件就是 恒为真

那我们接下来就看看恒为真会怎么样

#include<stdio.h>
int main()
{
	for (;;)
	{
		printf("haha\n");
	}
	return 0;
}

在这里插入图片描述
显然是一个死循环,所以我们在用这个的时候要慎重思考一下

我们看一个代码,并猜测的执行多少次

#include<stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	for (a=0,b=0;b=0;a++,b++)
	{
		b++;
		printf("haha\n");
	}
	return 0;
}

在这里插入图片描述
它是不执行的,我们看这个代码,其余的先不看,就看for循环第一个分号后面的b=0,这是判断循环终止条件语句,那这意味着什么,当判断循环终止条件为真的时候才会执行,它的执行条件是什么,必须为真,那b=0是为假,所以这个代码不会执行,判断循环终止条件为假,循环是没有意义的

3、do…while循环

do…while循环语法

do
    循环语句;
while(表达式);

还是我们先打印1-10的数字

#include<stdio.h>
int main()
{
	int i = 1;
	do
	{
		printf("%d\n",i);
		i++;
	} while (i<=10);
	
	return 0;
}

在这里插入图片描述
do…while循环可以这样理解,你可以认为这个循环,不管条件是否为真,它都至少执行一次循环体,比如你看下面代码

在这里插入图片描述
所以我们说这三种循环while、for、do…while,最常用的是for,其次是while,最后是do…while


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK