1. 程式人生 > >[C]第二章--分支語句與迴圈語句(2)--實戰演練

[C]第二章--分支語句與迴圈語句(2)--實戰演練

分支語句與迴圈語句


只有在實際應用中才可以感受到分支與迴圈語句的微妙之處.
以下列舉幾個筆者練習過的比較經典的例題.

拉門簾

要求:

  • 編寫程式碼,演示多個字元從兩端移動,向中間匯聚.達到拉門簾的效果.
#include<stdio.h>
#include<stdlib.h>
#include <Windows.h>
#include <string.h>
int main(){
   char arr1[] = "I like C programming!";//被掀開的內容
   char arr2[] = "#####################";//掀開前的內容
   int left = 0;
   int right = strlen(arr1) - 1;
   printf("%s\n", arr2);
//接下面程式碼
  1. while 實現
	while (left <= right) {
		//需要包含標頭檔案<windows.h>
		Sleep(1000);//可有可無,不過加上會有動態效果

		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		++left;
		--right;
		printf("%s\n", arr2);
	}
    system("pause");
    return 0;
}
  1. for 實現
   for(left = 0,right = strlen(arr1) -
1;left <= right;++left,++right){ Sleep(1000); arr2[left] = arr1[left]; arr2[right] = arr1[right]; printf("%s\n",arr2); } system("pause"); return 0; }

ATM機登入介面

int main(){
	char pas[1024] = "";//使用者輸入的密碼
	char password[] = "123456";
	int i = 0;
	int j = 0;
	for (i = 0; i <
3; ++i) { printf("請輸入密碼:\n"); scanf("%s", pas); if (strcmp(pas, password) == 0) { break; } } //迴圈結束的情況只有兩種 //1.輸錯三次,不滿足i < 3,登入失敗. //2.輸入了正確的密碼,登陸成功. if (i == 3) { printf("輸入錯誤三次,退出\n"); } else { printf("登陸成功!\n"); } system("pause"); return 0; }

注:

  1. 字串比大小遵循的是字典序
    若第一個引數等於第二個引數,返回0.
    若第一個引數小於第二個引數,返回負數.
    若第一個引數大於第二個引數,返回正數.
    從第一個元素向後判斷.
  2. 字串比較的是兩個字串首地址是否相同,之後詳解.

折半查詢(二分查詢)

先要明晰查詢該如何實現:

int main(){
	int xiabiao;
	int num = 7;//查詢的元素
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10};
	for (int i = 0; i < 10; i++){
		if (num == arr[i]){
			xiabiao = i;//找到目標元素將下標賦值給index
		}
	}
	printf("%d\n", xiabiao);
	system("pause");
}

這樣做太過於繁瑣,需要將索引值與 陣列中所有值進行比較,直到找到那個值或者全部判斷完沒有這個值才結束,時間複雜度很大,那麼就引入了簡化的折半查詢.

函式體中的折半查詢:

int main(){
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int left = 0;
	int right = sizeof(arr) / sizeof(arr[0]) - 1;
	int to_find = 7;
	int mid = 0;
	while (left <= right) {
		mid = (left + right) / 2;
		if (arr[mid] > to_find) {
			right = mid - 1;
		}
		else if (arr[mid] < to_find) {
			left = mid + 1;

		}
		else
			break;
	}
	if (left <= right) {
		printf("找到了,下邊是%d\n", mid);
	}
	else
		printf("沒找到.\n");
    system("pause");
    return 0;
}

實現一個折半查詢的函式:(函式定義中實現)

int search(int arr[],int left,int right,int to_find){
	int mid = 0;
	while(left <= right){
		mid = (left + right) >> 1;
		//等價於mid = (left + right) / 2;
		if(arr[mid] > to_find){
			right = mid - 1;
		}
		else if(arr[mid] < to_find){
			left = mid + 1;
		}
		else
			return mid;
	}
	return -1;
	//找不到的話返回-1;	
}

其實折半查詢的思維很簡單,就是把兩側值(最大與最小值)的平均值作為中值和要找的值進行對比,

  • 如果要找的值大於中值,說明需要找的值在這個中值右邊,左半邊就不需要查找了,所以重新規劃範圍,將最左值更新為mid + 1,重新進行下一次查詢.
  • 如果要找的值小於中值,說明需要找的值在這個中值左邊,右半邊就不需要查找了,所以重新規劃範圍,將最右值更新為mid - 1,重新進行下一次查詢.

注:

  1. 整形陣列可以通過 sizeof(arr) / sizeof( arr[0] )的方式確定陣列中有多少元素.
  2. 這個查詢的陣列必為有序陣列,不然無法實現.

猜數字

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include <time.h>
void menu() {
	printf("----------------\n");
	printf("----歡迎遊戲----\n");
	printf("----開始:1-----\n");
	printf("----退出:2-----\n");
	printf("----------------\n");
	printf("----請選擇:----\n");
}
void game() {
	int random_num = rand() % 100 + 1;//保證在1~100範圍之內
	int input = 0;
	while (1) {
		printf("請輸入猜的數字:\n");
		scanf("%d", &input);
		if (input > random_num) {
			printf("猜大了!\n");
		}
		else if (input < random_num) {
			printf("猜小了!\n");
		}
		else {
			printf("猜對了,恭喜你!\n");
			break;
		}
	}
}
int main(){
	int input = 0;
	srand((unsigned)time(0));//設定隨機種子,需要包含標頭檔案<time.h>
	do {
		menu();
		scanf("%d", &input);
		switch (input) {
		case 1:
			game();//開始遊戲
			break;
		case 0://退出遊戲
			break;
		default:
			printf("輸入錯誤,重新輸入!\n");
			break;
		}
	} while (input);
    system("pause");
    return 0;
}

srand((unsigned)time(0));這句設定隨機種子的語句需要詳細解讀一下

  • srand() 函式是隨機數發生器的初始化函式,要想讓其產生隨機數,那麼裡面的引數就要是隨機值.
  • time(0) 想想現實生活中什麼是隨機的?最常見的就是時間,所以在這裡引入時間戳的概念.
    (簡單來說就是從格林威治時間1970年1月1日與現在時間的秒數之差)
    所以這個time(0)就獲取了當前時間的時間戳,引入srand函式
  • (unsigned)
    因為time(0)時間戳返回的是一個time_t,也就是long int型別的資料(64位整數),而srand返回的是32位整數,轉換時會發生精度丟失,所以這裡用一句強制型別轉換的語句unsigned (int),保證精度對齊.

random_num = rand() % 100 + 1;是如何保證取值範圍在1~100之間的呢?
rand()函式生成的隨機值與100取模就保證了資料範圍在0~99之間
再給資料集加上1,所以範圍約束在了1~100之間了

關機小程式

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main(){
	char input[10] = { 0 };
	system("shutdown -s -t 60");
again:
	printf("電腦將在1分鐘內關機,如果輸入:我是豬,就取消關機!\n請輸入:\n");
	scanf("%s", input);
	if (strcmp(input, "我是豬") == 0) {
		system("shutdown -a");
	}
	else {
		goto again;
	}
    system("pause");
    return 0;
}

一個簡單的惡搞小程式,利用goto與標籤跳轉結合的方式實現.
需要注意的是:

  • 因為這裡輸入的時候,輸入介面無法輸入漢字字元,所以只能通過複製貼上的方式實現輸入,而且不可以通過 ctrl + v的方式進行貼上,只能右鍵點選 -> 貼上.
    解決方案:可以通過讓使用者輸入i am a pig等效替代
  • 這裡運用了系統指令system( )語句,可以控制PC機開關機,是不是感覺打開了新世界的大門?其實你也可以把程式碼編輯器看做一個控制檯,這就和cmd指令控制是一樣的,其他的功能有需要的同學可以自行百度~~