c语言中多样的循环控制语句
循环语句是c语言重要的基础语法之一
常见的循环控制语句for, while, do-while
因为do-while与while区别仅在于是否至少执行一次的代码有区别,故对前者不作讨论
c/c++的真值变量
- 在c/c++中,作为真值的变量为数字,判断条件自认为比较方便。
非0为真,0为假,控制循环语句的执行与否
if (1) printf("1\n");
if (2) printf("2\n");
if (0) printf("0\n");
还可以放赋值语句:
if (n = 3) printf("3\n");
输出值3。
简单过一下基础
for循环基础结构
for (初始化表达式; 条件表达式; 更新表达式) {
// 循环体
}
最常用的形式
for (int i = 0; i < n; i++) {
printf("Hello, world!\n");
}
while循环基础结构
while (条件表达式) {
// 循环体
}
- 条件表达式:判断是否执行下一次循环,若是,则执行循环体内代码,反之退出循环
最常用的形式
while (n需要满足的条件) {
if (条件) {
n自增或自减
}
}
循环控制语句
-
break语句
跳出最内层的循环,针对所在的内层循环 -
continue语句
跳过此次循环未执行部分,重新开启下一次循环,针对所在的内层循环 -
其它语句loop-goto
用于转到标记的语句
循环语句的变体,灵活地选择合适的循环结构
结合break, continue, goto,return(特别是while循环)可以使程序更加灵活
变量标记法(文章中记为flag)
使语句可以执行有限次
比如一次:
int flag = 1;
int n = 5;
while (n--) {
if (flag) {
flag = 0;
printf("if内\n");
}
printf("if外\n");
}
输出:
改变程序下一步执行方向
int flag = 1;
for (; 1/*具体条件*/;) {
while (1/*具体条件*/) {
while (1/*具体条件*/) {
if (flag) {
// 示例执行代码
printf("hello\n");
} else {
// 示例执行代码
printf("world\n");
}
}
}
}
结束特定循环
int flag = 1;
for (; 1/*具体条件*/;) {
while (flag) {
while (1/*具体条件*/) {
if (1/*具体条件*/) {
// 示例执行代码
flag = 0;
printf("hello\n");
} else {
// 示例执行代码
printf("world\n");
}
}
}
}
// 或者:
int flag = 1;
for (; flag;) {
while (1/*具体条件*/) {
while (1/*具体条件*/) {
if (1/*具体条件*/) {
// 示例执行代码
flag = 0;
printf("hello\n");
} else {
// 示例执行代码
printf("world\n");
}
}
}
}
特别是在获取正确用户输入时非常有用:
int mineClear(char innerBoard[LENGTH][LENGTH], char outerBoard[LENGTH][LENGTH]) {
int x = 0, y = 0;
int flag = 1; <-----------------标记变量
int status = 0;
while (flag) { <-----------------标记变量控制的循环
printf("PLease input your coordinate: \n");
scanf("%d %d", &x, &y);
x--;
y--;
if (!(x >= 0 && x < LENGTH && y >= 0 && y < LENGTH)) {
printf("Illegal input.Please input again.\n");
} else {
if (outerBoard[x][y] != ' ') {
printf("Explored!!");
continue;
} else {
if (innerBoard[x][y] == '*') {
system("cls");
showBoard(innerBoard);
Sleep(1000);
printf("==================================================\n");
printf("You died!!!\n");
++status;
} else {
extendSize(innerBoard, outerBoard, x, y);
if (residue == 0) {
system("cls");
showBoard(innerBoard);
Sleep(1000);
printf("==================================================\n");
printf("You win!!!\n");
status = 2;
}
}
}
flag = 0; <-----------------用户正确输入置为0,结束循环
}
}
return status;
}
for循环进阶用法
- 空的初始化语句
int i = 0;
// 中间对i进行处理,i的值会变得未知,示例:
i = 3; // 比如重新设置i的值
int x = 2;
while(--x) { // 比如在循环中操作它
i++;
}
for (;i < 10; i++) {
// 执行循环体
printf("%d\n", i);
}
- 空的条件语句
int i = 10;
while(1) {
// todo something (内含跳出语句break,goto或return)
i--;
}
比如以上代码可重写为:
for (int i = 10;;i--) {
// todo something (内含跳出语句break,goto或return)
}
- 空的迭代语句
可以选择性迭代i的值
for (int i = 0; i < 10;) {
// 满足某条件,如:
int sum = 0;
sum++;
if (sum % 2) {
// 迭代i的值
i++;
}
}
比如接收正确的数据(如用户输入)才能迭代:
int x = 0;
for (int i = 0; i < 10;) {
scanf("%d", &x);
// x满足某条件,如:
if (x > 0) {
// 迭代i的值
i++;
}
}
只要你想,你可以用for替代while:
for (; n--;) {
// todo something
printf("%d\n", n);
}
while (n--) {
// todo something
printf("%d\n", n);
}
(油饼)
- 双变量操作
比如实现数组逆序:
void reserve(int *arr, int len) {
// 同时对两个变量操作,提升性能
for (int i = 0, j = len - 1; i < j; ++i, --j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
void print(int* arr, int len) {
printf("[");
for (int i = 0; i < len; ++i) {
printf(i == len - 1 ? "%d]" : "%d, ", arr[i]);
}
}
int main() {
int arr[10] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 0
};
// 逆序数组
int len = sizeof(arr) / sizeof(int);
reserve(arr, len);
print(arr, len);
}
loop-goto与循环的结合
通过合理放置loop,结合也可实现类似循环的效果
看下列代码
int flag = 10;
loop :
printf("Hello, world!\n");
if (flag) {
flag--;
goto loop;
}
这与
for (int i = 0; i < 10; i++) {
printf("Hello, world!\n");
}
的输出结果一样。
从深层次的循环中退出到指定位置,比continue,break更加灵活
看下列代码:
loop1 :
while (1/*具体条件*/) {
loop2 :
while (1/*具体条件*/) {
// 其它代码
while (1/*具体条件*/) {
// 其它代码
if (1/*具体条件*/) {
// 其它代码
goto loop1;
} else if (2/*具体条件*/) {
// 其它代码
goto loop2;
} else if (3/*具体条件*/) {
// 其它代码
goto loop3;
}
// 其它代码
}
}
// 其它代码
loop3 :
// 其它代码
}
灵活性给足了,但也因为灵活度太高,容易出bug。其超高的灵活性,通常被认为是降低代码可读性的语句,不推荐大量使用,但是见到了也要知道,说不定什么地方可以起到出奇不意的效果。
在一些面向对象语言中,也有实现类似循环的效果
对象在创建时会初始化,这时如果有一个静态的成员变量,可以在每次创建一个对象时,更改变量的值,那么一次性创建多个对象就可以实现一个变量的不断增加。
怎样方便的一次性创建多个对象呢,创建一个该对象的数组就可以实现。
比如在c++中:
class A {
static int a;
public:
A() {
a++;
}
[[nodiscard]] static int getA() {
return a;
}
};
int A::a = 0;
int main() {
A* test = new A[10];
std::cout << A::getA() << std::endl;
}
输出a的值为
在Java中:
package day_05_;
public class A {
private static int a = 0;
public A() {
a++;
}
public int getA() {
return a;
}
}
class B {
public static void main(String[] args) {
A[] arr = new A[5];
// 显式初始化对象A数组
for (int i = 0; i < arr.length; i++) {
arr[i] = new A();
}
System.out.println(arr[0].getA());
}
}
注意:
Java:创建对象数组时,数组中的元素默认为 null,需要显式初始化。
C++:创建对象数组时,数组中的每个元素都会被自动初始化。
你是说我创建一个对象数组就为了改变一个值?
当然不仅仅是变量,各种数据结合某一特定业务场景这种有实际需求的时候,才可能认为它有用,在创建对象时当然也可以处理多组数据,这不妨是一个新的思路。
综合应用
虽然是Java代码,但在循环方面除了真值变量与c区别不大,而且c是其它语言的基础,所以主要理解循环控制就行
public static boolean logIn(ArrayList<User> usersList) {
if (usersList.isEmpty()) {
System.out.println("No user found. Please register first.");
return false;
}
System.out.println("Logging in");
Scanner sc = new Scanner(System.in);
System.out.print("Enter your username: ");
String username = sc.nextLine();
System.out.println("Enter 1 to continue, 2 to find password, 0 to exit");
for (int i = 0; i < 1; ) { <---------------空迭代语句
int input = sc.nextInt();
sc.nextLine();
if (input == 1) {
i++; <------------只有用户名正确才会进行迭代
System.out.println("Enter your password: ");
String password = sc.nextLine();
for (int j = 0; j < usersList.size(); j++) {
if (usersList.get(j).login(username, password)) {
System.out.println("Logged in successfully.");
return true;
}
System.out.println("Invalid username or password.");
}
} else if (input == 2) {
findPassword(usersList);
return false;
} else if (input == 0) {
System.out.println("Exiting.");
return false;
} else {
System.out.println("Invalid input. Please try again.");
}
}
return false;
}
public static void addStuInfo(ArrayList<Student> list) {
Student stu = new Student();
Scanner sc = new Scanner(System.in);
boolean flag = true;
loop: <-----------------从深层循环中跳出
while (flag) { <================正确输入结束当前输入才能结束
System.out.print("Enter id: ");
stu.setId(sc.next());
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getId().equals(stu.getId())) {
System.out.println("id already exists.");
System.out.println("Please enter another id.");
continue loop; <------------------java形式的跳转语句,等价与c的goto
}
}
System.out.print("Enter name: ");
stu.setName(sc.next());
try {
System.out.print("Enter age: ");
stu.setAge(sc.nextInt());
}catch(NumberFormatException e){
System.out.println("Invalid input.");
continue;
}
System.out.print("Enter from: ");
stu.setFrom(sc.next());
list.add(stu);
System.out.println("Add studentInfo successfully");
flag = false; <=============相当于c语言的flag = 0,合法时输入才能结束
}
}
public static void signIn(ArrayList<User> list) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter username: ");
String username = sc.next();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getUsername().equals(username)) {
boolean flag = true; <============== 设置变量,相当于c语言的flag = 1
loop: <--------------- 同上
while (flag) { <============== 同上
System.out.println("Enter 1 to input password, 2 to find password.");
String choice = sc.next();
if (choice.equals("1")) {
System.out.println("Enter password: ");
String password = sc.next();
if (list.get(i).getPassword().equals(password)) {
System.out.printf("Welcome %s\n", username);
Test_in.main(null);
} else {
System.out.println("Invalid password.");
continue;
}
flag = false; <============== 同上
} else if (choice.equals("2")) {
System.out.println("Enter id: ");
String id = sc.next();
System.out.println("Enter phone number: ");
String phoneNum = sc.next();
if (list.get(i).getId().equals(id) && list.get(i).getPhoneNum().equals(phoneNum)) {
System.out.println("Have sent your verification code.");
System.out.println("Enter verification code: ");
//TODO: send verification code
String code = Code.createCode();
System.out.printf("Your verification code is %s\n", code);
if (sc.next().equals(code)) {
System.out.println("Please enter your new password");
boolean flag2 = true; <=========== flag的多层嵌套
while (flag2) { <============== 同上
System.out.println("Enter password: ");
list.get(i).setPassword(sc.next());
System.out.println("Enter password again: ");
String password = sc.next();
if (!list.get(i).getPassword().equals(password)) {
System.out.println("password not same");
System.out.println("Please enter again");
continue;
}
flag2 = false; <============== 同上
System.out.println("Please sign in again.");
continue loop; <------------------- 同上
}
}
}else{
System.out.println("id or phone number is not valid");
System.out.println("Please enter again");
}
} else {
System.out.println("Please enter a valid choice");
}
}
}
}
System.out.println("No user");
}
下面这位才是多级嵌套(屎山)
public static void register(ArrayList<User> list) {
User user = new User();
Scanner sc = new Scanner(System.in);
boolean flag = true; <============== 同上
loop: <------------------ 同上
while (flag) { <============== 同上
boolean flag5 = true; <============== 同上
while(flag5){ <============== 同上
System.out.println("Enter username: ");
user.setUsername(sc.next());
if(user.getUsername().length()>10){
System.out.println("username is too long");
System.out.println("Please enter again");
}else{
flag5 = false; <============== 同上
}
}
boolean flag2 = true; <============== 同上
while (flag2) { <============== 同上
System.out.println("Enter password: ");
user.setPassword(sc.next());
System.out.println("Enter password again: ");
String password = sc.next();
if (!user.getPassword().equals(password)) {
System.out.println("password not same");
System.out.println("Please enter again");
continue;
}
flag2 = false; <============== 同上
}
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getUsername().equals(user.getUsername())) {
System.out.println("username already exists"); // 用户名重复,重新输入
continue loop; <-------------------- 同上
}
}
boolean flag3 = true; <============== 同上
while(flag3){ <============== 同上
System.out.println("Enter phone number: ");
String phoneNum = sc.next();
if(phoneNum.length()!=11||!isNumber(phoneNum,11)){
System.out.println("phone number is not valid");
System.out.println("Please enter again");
}else{
flag3 = false; <============== 同上
user.setPhoneNum(phoneNum);
boolean flag4 = true; <============== 同上
while(flag4){ <============== 同上
System.out.println("Enter id: ");
String id = sc.next();
if(id.length()!=18||!isNumber(id,17)){
if(id.charAt(18)!='x'||id.charAt(18)!='X'||id.charAt(18)>'9'||id.charAt(18)<'0'){
System.out.println("id is not valid");
System.out.println("Please enter again");
}
}else{
flag4 = false; <============== 同上
user.setId(id);
System.out.println("register successfully");
}
}
}
}
list.add(user);
System.out.println("register successfully");
flag = false; <============== 同上
}
}
当然实际开发不会这样写,但是这是练习代码,我学习路上的拉的,这里主要讲的是循环的灵活运用。
希望对你有用
END