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

本文介绍了C语言的基本概念,包括字符串的处理(转义字符和注释)、分支结构(if、switch)、以及循环语句(while、for、do...while)。通过实例演示,探讨了字符串长度计算、转义字符的作用以及不同循环结构的用法和注意事项。
摘要由CSDN通过智能技术生成

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

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

3、注释

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

  • /*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

  • 75
    点赞
  • 274
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 40
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论 40
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨旭华 

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值