一、对 while 循环 的补充
错误代码:
int main()
{
int ret = 0;
char password[20] = { 0 };
scanf("%s", &password);
printf("请确认密码(Y/N):");
int input = getchar(); 这里有问题,始终获取的都是:回车
if ('Y' == input)
{
printf("密码正确\n");
}
else
{
printf("放弃确认\n");
}
return 0;
}
回车键 ‘\n’ 的ASCII 的值就是:10
代码纠正改进一(更好的方法在下面):
int main()
{
int ret = 0;
char password[5] = { 0 };
scanf("%s", &password);
printf("请确认密码(Y/N):");
int jiejue = getchar(); 去除 回车键'\n'
int input = getchar();
if ('Y' == input)
{
printf("密码正确\n");
}
else
{
printf("放弃确认\n");
}
return 0;
}
其中重要的代码:
int jiejue = getchar();
去除 回车键 ‘\n’
int main()
{
int ret = 0;
char password[5] = { 0 };
scanf("%s", &password);
printf("请确认密码(Y/N):");
getchar(); (这样子也可以) 去除 回车键'\n'
int input = getchar();
if ('Y' == input)
{
printf("密码正确\n");
}
else
{
printf("放弃确认\n");
}
return 0;
}
当 scanf 输入时,scanf 不能接受 空格,Tab键,回车键
int main()
{
int ret = 0;
char password[5] = { 0 };
scanf("%s", &password);
printf("请确认密码(Y/N):");
getchar(); 去除 回车键'\n'
int input = getchar();
if ('Y' == input)
{
printf("密码正确\n");
}
else
{
printf("放弃确认\n");
}
return 0;
}
空格键
Tab 键盘
代码纠正改进二:
int main()
{
int ch = 0;
int input = 0;
int ret = 0;
char password[5] = { 0 };
printf("请输入密码:");
scanf("%s", &password);
while ((ch=getchar()) != '\n') 消除 密码 中的 空格,Tab键,回车等
{
;
}
printf("请确认密码(Y/N):");
input = getchar();
if ('Y' == input)
{
printf("密码正确\n");
}
else
{
printf("放弃确认\n");
}
return 0;
}
其中最重要的代码:
while ((ch=getchar()) != '\n') 消除 密码 中的 空格,Tab键 等
{
; 什么都不做,就是消除空格键,Tab键
}
1.补充:gets 函数
C语言gets函数详解
在前面从键盘输入 字符串 是使用 scanf 和 %s 。其实还有更简单的方法,即使用 gets() 函数。该函数的原型为:
#include<stdio.h>
char *gets(char *str)
这个函数很简单,只有一个参数。参数类型为 char* 型,即 str 可以是一个字符指针变量名,也可以是一个 字符数组名。
gets() 函数的功能是从输入缓冲区中读取一个字符串存储到字符指针变量 str 所指向的内存空间。
下面将前面中使用 scanf 输入字符串 的程序改一下:
int main()
{
char str[20] = { 0 };
printf("请输入字符串:");
gets(str);
printf("字符串输出:%s",str);
return 0;
}
可见,gets() 函数不仅比 scanf 简洁,而且,就算输入的字符串中有空格键也可以直接输入,不用像 scanf 那样要定义多个字符数组。也就是说:
gets(str);
完全可以取代:
scanf("%s",string);
不仅代码更简洁,而且可以直接输入带空格的字符串。同样,前面的章节中,对字符指针变量所指向的内存单元进行初始化也可以使用gets(),下面将那个程序也改一下,将 scanf 换成 gets() ;
int main()
{
char str[20] = { 0 };
char* string = str; 一定要先将 指针变量 初始化
printf("请输入字符串:");
gets(string); 也可以写成 gets(str)
printf("输出字符串:%s",string); 输出参数是已经定义好的“指针变量名”
return 0;
}
printf(“输出字符串:%s”,string); 输出参数是已经定义好的“指针变量名”
注意:这里不用解引用符号 *
解为什么不需要在printf(“输出字符串:%s”,string);中加上解引用符号*。
原因如下:
char* string = str;这行代码将指针string指向了数组str,因此string指向了str的首地址,可以直接通过string来访问str中的内容。因此,在printf(“输出字符串:%s”,string);中,string是一个指向字符串的指针,直接使用string即可输出字符串。
如果你将printf(“输出字符串:%s”,string);写成printf(“输出字符串:%s”,string);则会发生错误。因为string表示指针string所指向的内存地址上的值,而不是字符串本身。
在这种情况下,*string会被解释为第一个字符的ASCII码值,而不是整个字符串。
因此,在输出字符串时,应该直接使用指针变量string,而不需要加上解引用符号*。这样可以正确输出整个字符串,而不是单个字符的ASCII码值。
此外:关于使用 gets() 函数需要注意:
使用 gets() 时,系统会将最后 “敲” 的换行符从缓冲区中取出来,然后丢弃,所以缓冲区中不会遗留换行符。经过学习发现,其实gets是将‘\n’变成了’\0’ 。
这就意味着,如果前面使用过gets(),而后面又要从键盘给字符变量赋值的话就不需要吸收回车清空缓冲区了,因为缓冲区的回车已经被 gets()函数 取出来扔掉了。
下面写一个程序验证以下:
int main()
{
char str[20] = { 0 };
char input = 0;
printf("请输入字符串:");
gets(str);
printf("输出字符串:%s\n",str);
printf("请输入一个字符:");
scanf("%c", &input);
printf("输出一个字符:%c\n",input);
return 0;
}
我们看到,没有清空缓冲区照样可以输出 ’y‘ ,因为 gets() 已经将缓冲区中的回车取出来丢掉了。如果前面使用的不是gets() 而是 scanf,那么通过键盘给 ch 赋值前就必须使用 getchar() 清空缓冲区。
2.补充:什么是 空白符
空格,制表符,换行符 ,统称为:空白符。
它们只能占位,没有实际的内容。
制表符也称 缩进,就是 Tab键,默认占用 4 个空格的位置,你也可以在编辑器中修改。
puts()函数的功能是在puts输出一串字符串后,会自动换行,不需要再加一个 ‘\n’。
将字符串输出到终端,puts函数一次只能输出一个字符串,字符串中可以包括转义字符。
puts()函数的作用与语句printf(“%s\n”,s)的作用。
int main()
{
puts("C语言");
puts
("C语言中文网");
puts
(
"C语言中文网"
)
;
puts("C语言中文网");
return 0;
}
看到输出结果,说明代码没有错误,以上几种 puts 的用法正确的。
puts 和()之间,“ ”和()之间可以有任意的空白符,它们会被编译器忽略,编译器不认为它们是代码的一部分,它们的存在只是在编译器中呈现一定的格式,让程序员阅读方便。
注意:字符串中的 空格 和 制表符 不会被省略,它们会被输出到控制台上。并且字符串中不能有换行符,否则会产生编译错误。请看下面的代码:
int main()
{
puts("C语 言 中文网");
puts("C语言 错误
中文网"); 错误
return 0;
}
第5~6行代码错误:
字符串必须在一行内结束,不能换行。
int main()
{
puts("C语 言 中文网");
return 0;
}
程序员要善于利用空白符:缩进(制表符) 和 换行 可以让代码结构更加清晰,空格可以让代码看起来不那么拥挤。
专业的程序员同样追求专业的代码格式,大家在以后的学习中可以慢慢体会。
3. puts 函数
int puts ( const char * str );
/* puts example : hello world! */
#include <stdio.h>
int main ()
{
char string [] = "Hello world!";
puts (string);
}
4.补充:scanf函数 输出 空白符
下面介绍如何用 scanf 输出 空格等 空白符:
(1) %[ ]
意义:读入一个字符集合。
[ ] :是个集合的标志,因此
%[ ] :特指读入此集合所限定的那些字符,比如
%[ A-Z]:输入大写字母,一旦遇到不在此集合的字符便停止。
如果集合的 第一个字符 ‘^’ :
这说明读取不在 ’^‘ 后面集合的字符,即:
遇到 ‘^’ 后面的字符便停止。
而此时读入的字符串是可以含有空格的。
(2) %[^]
如果集合的 第一个字符 ‘^’ :
这说明读取不在 ’^‘ 后面集合的字符,即:
遇到 ‘^’ 后面的字符便停止。
而此时读入的字符串是可以含有空格的。
(3) 举例
1.只输出 A~Z 中的字符串,遇到别的便停止
int main()
{
char str[20] = { 0 };
scanf("%[A-Z]", str);
printf("%s\n", str);
return 0;
}
2.遇到 ‘^’ 后面的字符,便停止
int main()
{
char str[20] = { 0 };
scanf("%[^ABCD]", str);
printf("%s\n", str);
return 0;
}
(4) 用 scanf 来输出 空格键
int main()
{
char str[20] = { 0 };
scanf("%[^\n]",str); 遇到回车键,就停止,所以可以输出 空格键
printf("%s\n", str);
return 0;
}
二、for 循环
使用for循环的原因:在while 循环中依然存在循环的三个必要条件,但是由于while循环的风格问题,使得三个部分很可能偏离较远,这样查找修改就不够集中和方便。所以,for循环的风格更胜一筹。for循环的使用频率也最高。
1.语法
for(表达式1;表达式2;表达式3)
{
循环语句;
}
表达式1:初始化部分,用于初始化循环变量
表达式2:条件判断部分,用于判断循环时候终止
表达式3:调整部分,用于循环条件的调整
2.举例
(1)在屏幕上循环打印 1~10
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
printf("i=%d\n", i);
}
return 0;
}
3.break 和 continue 在 for循环 中
总结:我们发现在 for循环中也可以出现 break 和 continue,它们的意义和在 while 中是一样的。
但是还是有些差异的:
F10逐过程 -> 调试 -> 窗口 -> 监视 -> F11逐语句
(1) break
在循环中只要遇到 break ,就停止后期的所有循环,直接终止循环。
所以:while 中的 break 是用于永久终止循环的。
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (5 == i)
break;
printf("i = %d\n",i );
}
return 0;
}
与 while 中的 break 进行比较出:细微的差别
int main()
{
int i = 0;
while (i <= 10)
{
if (5 == i)
break;
printf("i=%d\n", i);
i += 1;
}
return 0;
}
(2) continue
总结:continue 是用于终止本次循环的,也就是本次循环中 continue 后边的代码不会再执行,进行下一次循环的入口判断。
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (5 == i)
continue;
printf("i = %d\n",i );
}
return 0;
}
与 while 中的 continue 进行比较出:细微的差别
输出结果:1.2.3.4 然后一直死循环下去
原因:continue 后面的代码直接跳过,变量 i 的值无法改变
int main()
{
int i = 0;
while (i <= 10)
{
if (5 == i)
continue;
printf("i=%d\n", i);
i += 1;
}
return 0;
}
4. 一些建议
(1)不可在 for循环 体内修改循环变量,防止 for 循环失去控制。
(2)建议 for 语句的循环控制变量的取值采用“前闭后开区间”的写法。
(1) 建议(一):不要在循环体内调整循环变量,容易失去控制
int main()
{
int i = 0;
for (i = 0; i <= 10; i++)
{ i = 5;
if (i = 5) 这里是给 变量i 赋值为 5
printf("haha\n");
printf("hehe\n"); 输出结果:haha 一直死循环 下去
}
return 0;
}
输出结果:haha 一直死循环 下去
if (i = 5)
这是经典的 错误之处
if (5 == i) 这样就可以有效的避免错误
(2) 建议(二):控制变量的取值采用“前闭后开区间”的写法
“前闭后开区间”: 左闭右开(告诉你:这是 “10” 次循环,“10”个参数)
for(i = 0; i < 10; i++) 左闭右开(告诉你:这是 10 次循环,10 个参数)
5. 一些 for循环的变种
(1)变种1:“初始化;判断;调整”均可以省略
“ 判断部分的省略 “,即” 判断部分恒为 真值 “,会陷入 死循环
int main()
{
int i = 0;
for (; ;)
{
printf("gege\n");
}
return 0;
}
(2)变种2
int main()
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
printf("i=%d,j=%d,haha\n",i,j);
}
}
return 0;
}
这就是随便调整位置的不良后果
int main()
{
int i = 0;
int j = 0;
for (; i < 10; i++)
{
for (; j < 10; j++) 没有给 变量j 重新赋值为 0
{
printf("i=%d,j=%d,haha\n",i,j);
}
}
return 0;
}
(3)变种3
int main()
{
int x = 0;
int y = 0;
for (x = 0, y = 0; x < 2 && y < 5; ++x, y++)
{
printf("hehe\n");
}
return 0;
}
输出结果为:
通过 F10 -> 调试 -> 窗口 -> 监视 -> F11 ,来了解程序是怎么进行
第一步:x=0 , y=0
输出:hehe
第二步:x=1 , y=1
输出:hehe
第三步:x=2 , y=2
判断条件:x < 2 && y < 5,由于不满足条件,所以结束程序
6. 一道经典的 笔试题
问:请问循环要循环多少次?
答:循环0次
解释:
首先,是”判断部分“,k = 0;
其次,k 被赋值为 0,而不是”0 == k“,
最后,”k = 0“是假,所以一次都不执行,
即:循环 0 次
int main()
{
int i = 0;
int k = 0;
for (i = 0, k = 0; k = 0; i++, k++) k = 0
k++;
return 0;
}
三、do…while() 循环
1.语法
do
循环语句;
while(表达式);
2.do语句 的特点
循环至少执行一次,使用的场景有限,所以不是经常使用。
int main()
{
int i = 10;
do
{
printf("%d\n",i);
} while (i < 10);
return 0;
}
3.break 和 continue 在 do…while()循环 中
(1) break
int main()
{
int i = 1;
do
{
if (5 == i)
break;
printf("%d\n", i);
i++;
} while (i < 10);
return 0;
}
(2) continue
int main()
{
int i = 1;
do
{
if (5 == i)
continue;
printf("%d\n", i);
i++;
} while (i < 10);
return 0;
}
输出结果:1.2.3.4 然后一直死循环
当 i== 5 时,
运行到 continue 后,会跳过
printf("%d\n",i);
i++;
但仍会运行
while(i <= 10)