c語言進階6-指針

指針是c語言的一個重要組成部分

是c語言的核心、精髓所在,用好指針能夠在c語言編程中起到事半功倍的效果。一方面,能夠提升程序的編譯效率和執行速度以及實現動態的存儲分配;另外一方面,使用指針可以使程序更靈活,全球表示各類數據結構,編寫高質量的程序。編程

指針是c語言顯著的優勢之一,其使用起來十分靈活並且能提升某些程序的效率,可是若是使用不當則很容易形成系統錯誤。許多程序「掛死「每每都是因爲錯誤地使用指針形成的windows

1、       地址與指針

系統的內存就比如是帶有編號的小房間,若是想使用內存就須要獲得房間編號。圖1定義了一個整型變量i,整型變量須要4個字節,因此編譯器爲變量i分配的編號爲1000~1003.數組

什麼是地址?地址就是內存區中對每一個字節的編號,如圖1所示的1000/1001/1002和1003就是地址,爲了進一步說明來看圖2.數據結構

內存地址函數

內容oop

 

1000字體

0ui

變量ispa

1004指針

1

變量j

1008

2

 

1012

3

 

1016

4

 

1020

5

 

 

圖2所示的1000、1004等就是內存單元的地址,而0、1就是內存單元的內容,換種說法就是基本整型變量i在內存中的地址從1000開始。由於基本整型佔4個字節,因此變量j在內存中的起始地址爲1004,變量i的內容是0.

那麼指針又是什麼呢?這裏僅將指針看做是內存中的一個地址,多數狀況下,這個地址就是內存中另外一個變量的位置,如圖3所示。

 

在程序中定義了一個變量,在進行編譯時就會給該變量在內存中分配一個地址,經過訪問這個地址能夠找到所需的變量,這個變量的地址稱爲該變量的「指針」。圖3所示的地址1000是變量i的指針。

 

2、       變量與指針


變量的地址是變量和指針兩者之間鏈接的紐帶,若是一個變量包含了另外一個變量的地址,則能夠理解成第一個變量指向第二個變量。
所謂「指向」就是經過地址來體現的,由於指針變量是指向一個變量的地址,因此講一個變量的地址賦給這個指針變量後,這個指針變量就「指向」了該變量。例如,將變量i的地址存放到指針變量p中,p就指向i

在程序代碼中是經過變量名對內存單元進行存取操做的,可是代碼通過編譯後已經將變量名轉換爲該變量在內存中的存放地址,對變量值的存取都是經過地址進行的。如對圖2所示的變量i和變量j進行以下操做;

其含義時:根據變量名與地址的對應關係,找到變量i的地址1000,而後從1000開始讀取4個字節數據放到cpu寄存器中,再找到變量j的地址1004,從1004開始讀取4個字節的數據放到cpu的另外一個寄存器中,經過cpu的加法中斷計算出結果。

在低級語言的彙編語言中都是直接經過地址來方位內存單元的,在高級語言中通常使用變量名訪問內存單元,但c語言做爲高級語言提供了經過地址來訪問內存單元的方式。

1、       指針變量

因爲經過地址能訪問指定的內存存儲單元,能夠說地址「指向」該內存單元。地址能夠形象地稱爲指針,意思是經過指針能找到內存單元。一個變量的地址稱爲該變量的指針。若是一個變量專門用來存放另外一個變量的地址,它就是指針變量。在c語言中有專門用來存放內存單元地址的變量類型,即指針類型。下面將針對如何定義一個指針變量,如何爲一個指針變量賦值及如何引用指針變量這3方面內容加以介紹。

  1. 1.   指針變量的通常形式

若是一個變量專門用來存放另外一變量的地址,則它成爲指針變量。圖4所示的p就是一個指針變量。若是一個變量包含指針(指針等同於一個變量的地址),則必須對它進行說明。定義指針變量的通常形式以下;

類型說明  *變量名

其中「*」表示該變量是一個指針變量,變量名爲定義的指針變量名,類型說明表示本指針變量所指向的變量的數據類型。

  1. 2.   指針變量的賦值

指針變量同普通變量同樣,使用以前不只須要定義,並且必須賦予具體的值,未經賦值的指針變量不能使用。給指針變量所賦的值與給其餘變量所賦的值不一樣,給指針變量的賦值只能賦予地址,而不能賦予任何其餘數據,不然將引發錯誤。c語言中提供了地址運算符&來表示變量的地址。其通常形式爲:

&變量名;

如&a表示變量a的地址,&b表示變量b的地址。給一個指針變量賦值能夠有如下兩種方法。

(1)      定義指針變量的同時就進行賦值,例如:

int  a;

int *p=&a;

(2)      先定義指針變量以後再賦值,例如:

int  a;

int *p;

p=&a;

從鍵盤中輸入兩個數,利用指針的方法將這兩個數輸出

#include "stdio.h"

void main()

{

    int a,b;

    int *ipointer1,*ipointer2;  /*聲明兩個指針變量*/

    scanf("%d,%d",&a,&b);   /*輸入兩個數*/

    ipointer1=&a;

    ipointer2=&b;   /*將地址賦給指針變量*/

    printf("the number is :%d,%d\n",*ipointer1,*ipointer2);

}

經過實例1能夠發現程序中採用的賦值方式是上述第二種方法,即先定義再賦值。

這裏強調一點,即不容許把一個數賦予指針變量,例如:

int *p;

p=1002;

這樣寫是錯誤的。

  1. 3.   指針變量的引用

 引用指針變量是對變量進行間接訪問的一種形式。對指針變量的引用形式以下;

*指針變量

其含義時引用指針變量所指向的值

利用指針變量實現數據的輸入和輸出。

#include "stdio.h"

void main()

{

    int *p,q;

    printf("please input:\n");

    scanf("%d",&q);   /*輸入一個整型數據*/

    p=&q;

    printf("the number is:\n");

    printf("%d\n",*p);  /*輸出變量的值*/

}

可將上述程序修改爲以下形式;

#include "stdio.h"

void main()

{

    int *p,q;

    p=&q;

    printf("please input:\n");

    scanf("%d",p);   /*輸入一個整型數據*/   

    printf("the number is:\n");

    printf("%d\n",*p);  /*輸出變量的值*/

}

 

  1. 4.   「&」和「*」運算符

 在前面介紹指針變量的過程當中用到了「&」和「*」兩個運算符,運算符&是一個返回操做數地址的單目運算符,叫作取地址運算符,例如:

p=&i;

就是將變量i的內存地址賦給p,這個地址是該變量在計算機內部的存儲位置。

運算符「*」是單目運算符,叫作指針運算符,做用是返回指定的地址內的變量的值。如前面提到過p中裝有變量i的內存地址,則

q=*p;

就是將變量i的值賦給q,假如變量i的值是5,則q的值也是5.

 

  1. 5.   「&」 和「&」的區別

若是有以下語句:

int a;

p=&a;

 下面經過以上兩條語句來分析「&」和「&」的區別,&」和「*」的運算符優先級別相同,按自右向左的方向結合。所以「&*p先進行「*」運算,「*p」至關於變量a;再進行「&」運算,「&*p就至關於取變量a的地址。「*&a」先進行「&」運算,「&a」就是取變量a的地址,而後執行「*」運算,「*&a」就至關於取變量a所在地址的值,實際就是變量a

2、       指針自加自減運算

指針自加自減運算內不一樣於普通變量的自加自減運算,也就是說並不是簡單地加1減1,這裏面經過下面的實例進行具體分析。

ACM【例5】整型變量地址輸出

#include "stdio.h"

void main()

{

    int i;

    int *p;

    printf("please input the number:\n");

    scanf("%d",&i);  

    p=&i;      /*將變量i的地址賦給指針變量*/   

    printf("the result1 is:%d\n",p);

    p++;      /* 地址加1,這裏的1並不表明一個字節*/

    printf("the result2 is:%d\n",p);

}

若將實例5改爲:

#include "stdio.h"

void main()

{

    short i;

    short *p;

    printf("please input the number:\n");

    scanf("%d",&i);  

    p=&i;      /*將變量i的地址賦給指針變量*/   

    printf("the result1 is:%d\n",p);

    p++;      /* 地址加1,這裏的1並不表明一個字節*/

    printf("the result2 is:%d\n",p);

}

基本整型變量i在內存中佔4個字節,指針p是指向變量i的地址的,這裏的p++不是簡單地在地址上加1,而是指向下一個存放基本整型數的地址。圖9所示的結果是由於變量i是基本整型,因此執行p++後,p的值增長4(4個字節);圖10所示的結果是由於i被定義成了短整型,因此執行p++後,p的值增長了2(兩個字節)。

指針都按照它所指向的數據包類型的直接長度進行增或減。

3、       數組與指針

系統需要提供必定量連續的內存來存儲數組中的各元素,內存都有地址,指針變量就是存放地址的變量,若是數組的地址賦給指針變量,就能夠經過指針變量引用數組。下面就介紹如何用指針來引用一對數組元素。

一維數組與指針

當定義一個一對數組時,系統會在內存中爲該數組分配一個存儲空間,其數組的名稱就是數組在內存中的首地址。若再定義一個指針變量,並將數組的首地址傳給指針變量,則該指針就指向了這個一維數組。

例如:

int *p,a[10];

p=a;

這裏a是數組名,也就是數組的首地址,將它賦給指針變量p,也就是將數組a的首地址賦給p,也能夠寫成以下形式;

int *p,a[10];

p=&a[0];

上面的語句是講數組a中的首個元素的地址賦給指針變量p。因爲a[0]的地址就是數組的首地址,所以兩條賦值操做效果徹底相同,如實例6所示。

ACM【例 6】 輸入數組中的元素。

#include "stdio.h"

void main()
{
    int *p,*q,a[5],b[5];
    int i;
    p=&a[0];
    q=b;
    printf("please input array a:\n");
    for(i=0;i<5;i++)
    scanf("%d",&a[i]);
    printf("please input array b:\n");
    for(i=0;i<5;i++)
    scanf("%d",&b[i]);
    printf("array a is :\n");
    for(i=0;i<5;i++)
    printf("%5d",*(p+i));
    printf("\n");
    printf("array b is :\n");
    for(i=0;i<5;i++)
    printf("%5d",*(q+i));
    printf("\n");
}

實例6中有以下兩條語句:

p=&a[0];

q=b;

分別表示輸出數組a和數組b中對應的元素。

這兩種表示方法都是講數組首地址賦給指針變量。

那麼如何經過指針的方式來引用一對數組中的元素呢?有如下語句:

int *p,a[5];

p=&a;

針對上面的語句將經過如下幾方面進行介紹

p+n與a+n表示數組元素a[n]的地址,即&a[n]。對整個a數組來講,共有5個元素,n的取值爲0~4,則數組元素的地址就能夠表示爲p+0~p+4或a+0~a+4。

表示數組中的元素用到了前面介紹的數組元素的地址,用*(p+n)和*(a+n)來表示數組中的個元素。

實例6中的語句:

printf("%5d",*(p+i));

和語句:

printf("%5d",*(q+i));

分別表示輸出數組a和數組b中對應的元素。

實例6中使用指針指向一對數組及經過指針引用數組元素的過程能夠經過圖13和圖14來表示。

 

前面提到能夠用a+n表示數組元素的地址,*(a+n)表示數組元素,那麼就能夠將實例6的程序代碼改爲以下形式:

#include "stdio.h"

void main()

{

    int *p,*q,a[5],b[5];

    int i;

    p=&a[0];

    q=b;

    printf("please input array a:\n");

    for(i=0;i<5;i++)

    scanf("%d",&a[i]);

    printf("please input array b:\n");

    for(i=0;i<5;i++)

    scanf("%d",&b[i]);

    printf("array a is :\n");

    for(i=0;i<5;i++)

    printf("%5d",*(a+i));

    printf("\n");

    printf("array b is :\n");

    for(i=0;i<5;i++)

    printf("%5d",*(b+i));

    printf("\n");

}

程序運行的結果與實例6的運行結果同樣。

表示指針的移動可使用「++」和「——」這兩個運算符

利用「++」運算符可將程序改寫成以下形式。

#include "stdio.h"

void main()

{

    int *p,*q,a[5],b[5];

    int i;

    p=&a[0];

    q=b;

    printf("please input array a:\n");

    for(i=0;i<5;i++)

    scanf("%d",&a[i]);

    printf("please input array b:\n");

    for(i=0;i<5;i++)

    scanf("%d",&b[i]);

    printf("array a is :\n");

    for(i=0;i<5;i++)

    printf("%5d",*p++);
    printf("\n");
    printf("array b is :\n");
    for(i=0;i<5;i++)
    printf("%5d",*q++);
    printf("\n");
}

 

還可將上面程序再進一步改寫,運行結果仍與實例6的運行結果相同,改寫後的程序代碼以下:

#include "stdio.h"

void main()
{
    int *p,*q,a[5],b[5];
    int i;
    p=&a[0];
    q=b;
    printf("please input array a:\n");
    for(i=0;i<5;i++)
    scanf("%d",p++);
    printf("please input array b:\n");
    for(i=0;i<5;i++)
    scanf("%d",q++);
    printf("array a is :\n");
    for(i=0;i<5;i++)
    printf("%5d",*p++);
    printf("\n");
    printf("array b is :\n");
    for(i=0;i<5;i++)
    printf("%5d",*q++);
    printf("\n");
}

 

比較上面兩個程序會發現,若是在給數組元素賦值時使用了以下語句:

  printf("please input array a:\n");

    for(i=0;i<5;i++)

    scanf("%d",p++);

    printf("please input array b:\n");

    for(i=0;i<5;i++)

    scanf("%d",q++);

並且在輸出數組元素時須要使用指針變量,則需加上以下語句:

p=a;

q=b;

這兩個語句的做用是講指針變量p和q從新指向數組a和數組b在內存中的起始位置,若沒有該語句,而直接使用*p++的方法進行輸出,則此時將會產生錯誤。

4、       字符串與指針

訪問一個字符中能夠經過兩種方式,第一種方式就是前面講過的使用字符數組來存放一個字符串,從而實現對字符串的操做;另外一種方式就是下面將要介紹的使用字符指針指向一個字符串,此時可不定義數組。

ACM【例 10】 字符型指針引用。

#include "stdio.h"

void main()

{

    char *string="hello word";

    printf("%s",string);

}

程序運行結果如圖19所示。

實例10中定義了字符型指針變量string,用字符串敞亮「hello mingri」爲其賦初值,注意這裏並非把「hello mingri」中的全部字符存放到string中,只是把該字符串中的第一個字符的地址賦給指針變量string,如圖20所示。

char *string="hello word";

等價於下面兩條語句:

char *string;

string="hello word";

ACM【例 11】  輸入兩個字符串a和b,將字符串a和b鏈接起來。

#include "stdio.h"

#include "string.h"

void main()

{

    char str1[]="you are beautiful",str2[30],*p1,*p2;

    p1=str1;

    p2=str2;

    while(*p1!='\0')

    {

        *p2=*p1;

        p1++;      /*指針移動*/

        p2++;

    }

    *p2='\0';      /*在字符串的結尾加結束符*/

    printf("now the string2 is:\n");

    puts(str1);    /*輸出字符串*/

}

程序運行結果如圖21所示。

實例11中定義了兩個指向字符型數據的指針變量。首先讓p1和p2分別指向字符串a和字符串b的第一個字符的地址。將p1所指向的內容賦給p2所指向的元素,而後p1和p2分別加1,指向下一個元素,直到*p1的值爲「\0」爲止。

這裏有一點須要注意,就是p1和p2的值是同步變化的,如圖22所示。若p1處在p11的位置,p2就出在p21的位置:若p1處在p12的位置,p2就出在p2的位置。

 

5、       指向指針的指針

 

一個指針變量能夠指向整型變量、實型變量、字符類型變量,固然也能夠指向指針類型變量。當這種指針變量用於指向指針類型變量時,則稱之爲指向指針的指針變量。這種雙重指針如圖24所示。

整型變量i的地址就是&i,將其值傳遞給指針變量p1,則p1指向i:同事,將p1的地址&p1傳遞給p2,則p2指向p1.這裏的p2就是前面講到的指向指針變量的指針變量,即指針的指針。指向指針的指針變量定義以下:

類型標識符 **指針變量名;

例如:

int **p;

其含義爲定義一個指針變量p,它指向另外一個指針變量,該指針變量又指向一個基本整型變量。因爲指針運算符*是自右至左結合,因此上述定義至關於:

int *(*p);

既然知道了如何定義指向指針的指針,那麼能夠將它形象地表示出來。

 

指向指針的指針應用過程這裏就不作過多講解了,也但願同窗們能夠利用業餘時間,查詢資料充實本身。

五子棋代碼3

#include <conio.h>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>



int ChessData[15][15] ={0};
int GuangbiaoData[2]={8,8};
int ChessStepData[255][2]={0};



void gotoxy(int x, int y) //指定y行,x列
{ 
 COORD c; 
 c.X=x-1; 
 c.Y=y-1; 
 SetConsoleCursorPosition (GetStdHandle(STD_OUTPUT_HANDLE), c); 
}


void GotoChess(int x,int y)
{
 x=3*x-2;y=2*y-1;
 gotoxy(x,y);
}

void color(short x)    //自定義函根據參數改變顏色 
{
    if(x>=0 && x<=15)//參數在0-15的範圍顏色
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);    //只有一個參數,改變字體顏色 
    else//默認的顏色白色
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}

 

void Move(int MoveData) //輸入參數爲用戶輸入的方向(1表示上,2表示下,3表示左,4表示右)
{
 switch (MoveData)
 {
 case 1:GuangbiaoData[1]-=1;break;
 case 2:GuangbiaoData[1]+=1;break;
 case 3:GuangbiaoData[0]-=1;break;
 case 4:GuangbiaoData[0]+=1;break;
 default:printf("Move函數出錯");
 }
 GotoChess(GuangbiaoData[0],GuangbiaoData[1]);
}


int Get(int *data) 
/*該函數的功能是用戶的按鍵,
*並轉化爲01234567
(0表示輸入錯誤,1表示上,2表示下,3表示左,
4表示右,5表示落子,6表示悔棋,7表示退出。)*/
{          //並返回輸入的用戶號碼(共同鍵返回3),錯誤則返回0
 int temp;


B: temp=getch();
   if (temp==224) 
   {
    temp=getch();
    switch (temp) 
    {
    case 72:*data=1;break;
    case 80:*data=2;break;
       case 75:*data=3;break;
       case 77:*data=4;break;
       default:goto B;
    }
       return 2;
}
   else 
   {
    switch (temp)
    {
    case 'w':
    case 'W':*data=1;return 1;break;
    case 's':
       case 'S':*data=2;return 1;break;
       case 'a':
       case 'A':*data=3;return 1;break;
       case 'd':
       case 'D':*data=4;return 1;break;
       case 13 :*data=5;return 2;break;
       case 32 :*data=5;return 1;break;
       case 8 :*data=6;break;
       case 27 :*data=7;break;
       default:*data=0 ;return 0;break;
    }
    return 3;
   }
}
void MoveToEnd()
{
 gotoxy(1,30);
}
int LogicBeOut(int a,int b)
{
 if (a==-1||a==15||b==-1||b==15) return 1;
 else return 0;
}
int win(int v)
{
 int i=1,j=1,a=0,b=0;
 while (ChessData[a=GuangbiaoData[0]-i-1][b=GuangbiaoData[1]-i-1]==v*2&&!LogicBeOut(a,b)) i++;
 while (ChessData[a=GuangbiaoData[0]+j-1][b=GuangbiaoData[1]+j-1]==v*2&&!LogicBeOut(a,b)) j++;
 if (i+j-1>=5) return 1;
 i=1,j=1,a=0,b=0;
 while (ChessData[a=GuangbiaoData[0]+i-1][b=GuangbiaoData[1]-i-1]==v*2&&!LogicBeOut(a,b)) i++;
 while (ChessData[a=GuangbiaoData[0]-j-1][b=GuangbiaoData[1]+j-1]==v*2&&!LogicBeOut(a,b)) j++;
 if (i+j-1>=5) return 1;
 i=1,j=1,a=0,b=0;
 while (ChessData[a=GuangbiaoData[0]-i-1][b=GuangbiaoData[1]-1]==v*2&&!LogicBeOut(a,b)) i++;
 while (ChessData[a=GuangbiaoData[0]+j-1][b=GuangbiaoData[1]-1]==v*2&&!LogicBeOut(a,b)) j++;
 if (i+j-1>=5) return 1;
 i=1,j=1,a=0,b=0;
 while (ChessData[a=GuangbiaoData[0]-1][b=GuangbiaoData[1]-i-1]==v*2&&!LogicBeOut(a,b)) i++;
 while (ChessData[a=GuangbiaoData[0]-1][b=GuangbiaoData[1]+j-1]==v*2&&!LogicBeOut(a,b)) j++;
 if (i+j-1>=5) return 1;
 return 0;
}


void NewShow() //新棋局的開始
{
 int i,j;
 for (i=0;i<15;i++)
  for (j=0;j<15;j++)
   ChessData[i][j]=0;
  system("cls");
  for (i=1;i<=29;i++)
  {
   for (j=1;j<=43;j++)
    if(i%2==1) printf("-");
    else if (j%3==1) printf("|");
    else printf(" ");
    printf("\n");
  }
  GuangbiaoData[0]=8;GuangbiaoData[1]=8;
  MoveToEnd();
  printf("如今請用戶1下棋         \n");
  printf("用戶1使用 w,s,a,d移動光標,空格鍵落子\n");
  printf("用戶2使用各方向鍵移動光標,回車鍵落子\n");
  printf("按下Backspace鍵悔棋,按下esc返回主菜單\n");
  GotoChess(8,8);
}


int BeOut(int data)
{
 int Xiuzheng[2],New[2];
 switch (data)
 {
 case 1:Xiuzheng[0]=0;Xiuzheng[1]=-1 ;break;
 case 2:Xiuzheng[0]=0;Xiuzheng[1]=1;break;
 case 3:Xiuzheng[0]=-1;Xiuzheng[1]=0;break;
 case 4:Xiuzheng[0]=1;Xiuzheng[1]=0 ;break;
 case 5:Xiuzheng[0]=0;Xiuzheng[1]=0 ;break;
 default:printf("BeOut函數出錯");
 }
 New[0]=GuangbiaoData[0]+Xiuzheng[0];
 New[1]=GuangbiaoData[1]+Xiuzheng[1];
 if (New[0]>15||New[0]<1||New[1]>15||New[1]<1) return 1;
 else return 0; 
}


void UserChoose(int * choice)
{  
    int temp=0,i=0;
    system("cls");
    printf("_________________________________________________\n");
    printf("_________________________________________________\n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),3 | 8 | 224 | 64);
    printf("                1.單人遊戲                       \n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),5 | 8 | 224 | 64);
    printf("                2.雙人遊戲                       \n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),6 | 8 | 224 | 64);
    printf("                3.退出遊戲                       \n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),4 | 8 | 224 | 64);
    printf("                4.遊戲幫助                       \n");
    printf("_________________________________________________\n");
    printf("_________________________________________________\n");
    printf("                                                 \n");
    printf("                開心五子棋                     \n");
    printf("                                                 \n");
    printf("                拷貝者:Tim                    \n");
    printf("_________________________________________________\n");
 do
 { 
  if ((temp=getch())==224) 
  { 
   temp=getch();
   if (temp==72&&i!=0)
   {
    gotoxy(34,3+i);
    printf(" ");
    i--;
    gotoxy(34,3+i);
    printf("$");
    gotoxy(0,0);
   }
   else if(temp==80&&i!=3)
   {
    gotoxy(34,3+i);
    printf(" ");
    i++;
    gotoxy(34,3+i);
    printf("$");
    gotoxy(0,0);
   }   
  }
  else if (temp==13) {*choice=i+1;return;}
  else if (temp==27) {*choice=3;return;}
  else if (temp=='1'||temp=='2'||temp=='3'||temp=='4') {*choice=temp-48;return;}
 }while(1);
}
int CannotDo(int v1,int v2,int MoveData,int choice) //第一個輸入值爲按鍵的用戶號,第二個是本應該按鍵的用戶號,第三個爲按下鍵的對應值,第四個鍵表明遊戲模式。
{
 if (v1==3) return 0; //若是用戶輸入的爲共用按鍵,則CannotDo爲假


 else if (v1==0) return 1;//若是用戶輸入錯誤,則CannotDo爲真
 else if (v1!=v2&&choice==2) return 1; //若是不應此用戶輸入,而用戶進行了輸入,則CannotDo爲真


 if (BeOut(MoveData)) return 1; //若是移動出邊界則CannotDo爲真
 return 0;
}


int CannotLuozi() //判斷是否能夠落子。
{
 if (ChessData[GuangbiaoData[0]-1][GuangbiaoData[1]-1])
  return 1;
 else return 0;
}



int luozi(int v)    //玩家v落子。
{ 
 int i;
 ChessData[GuangbiaoData[0]-1][GuangbiaoData[1]-1]+=v*2;
 if (v==1) printf("O");
 else if (v==2) printf("X");
 else printf("luozi函數出錯");
 if (win(v)) {
     MoveToEnd();printf("玩家%d得到了勝利!         \n",v);
     for (i=1;i<=240;i++) printf(" ");
     GotoChess(GuangbiaoData[0],GuangbiaoData[1]);
     getch();
     return 1;
     }
 MoveToEnd();
 printf("如今請用戶%d下棋             ",v%2+1);
 GotoChess(GuangbiaoData[0],GuangbiaoData[1]);
 return 0;
}


void HuiQi(int step) //輸入的是當前的要悔的棋是第幾步
{
 GuangbiaoData[0]=ChessStepData[step-1][0];
 GuangbiaoData[1]=ChessStepData[step-1][1];
 ChessData[GuangbiaoData[0]-1][GuangbiaoData[1]-1]=0;


 GotoChess(GuangbiaoData[0],GuangbiaoData[1]);
 printf("-");
 MoveToEnd();
 printf("如今請用戶%d下棋         ",(step+1)%2+1);
 GotoChess(GuangbiaoData[0],GuangbiaoData[1]);
}


int DataGetAndChoose(int choice) 
{ 
 int MoveData=0,i=0,temp; //MoveData 0表示不可移動,1表示上,2表示下,3表示左,4表示右,5表示落子,6表示悔棋,7表示退出。
 while(1)
{
loop: while (temp=Get(&MoveData),CannotDo(temp,i%2+1,MoveData,choice));
   switch (MoveData)
   {
      case 1:
      case 2:
      case 3:
      case 4:Move(MoveData);break;
      case 7:return 0;
      case 6:
    if (i==0) {
    MoveToEnd();printf("如今沒法悔棋                         ");
    GotoChess(GuangbiaoData[0],GuangbiaoData[1]);}
    else HuiQi(i--);
    break;
   case 5:
    if (CannotLuozi()) goto loop;
    if(luozi(i%2+1)) return 0;
    ChessStepData[i][0]=GuangbiaoData[0];
    ChessStepData[i][1]=GuangbiaoData[1];
    i++;
    break;
   default:printf("DataGetAndChoose函數出錯");break;
   }
 }
 return 1;  
}


void ShowHelp()
{
 system("cls");
 printf("********************************************************************************");
    printf("********************************************************************************");
    printf("******          單人遊戲供用戶一我的本身與本身下棋研究棋局之用            ******");
    printf("******          雙人遊戲中,用戶1使用wsad控制方向,按空格落子             ******");
    printf("******               用戶2按方向鍵控制方向,回車鍵落子                    ******");
    printf("******                   遊戲過程當中按esc返回主菜單                        ******");
    printf("******                    遊戲過程當中退格鍵悔棋                            ******");
    printf("******        雙人模式中某人下棋時,另外一個用戶沒法控制光標與落子          ******");
    printf("******                                                                    ******"); 
    printf("******                             幫助                                   ******"); 
    printf("******                          按任意鍵返回                              ******"); 
    printf("********************************************************************************"); 
    printf("********************************************************************************");
    getch();
}



int main()
{
   int choice=0;
 /*  system ( "mode con cols=80 lines=28" );*/
   system("color E0");
   choose: UserChoose(&choice);
   if (choice<1||choice>4) goto choose;
   if (choice==3) {gotoxy(1,18);
   printf("\n謝謝您的使用,再見        "); getch();return 0;}
   if (choice==4) {ShowHelp(); goto choose;}
   NewShow();
   DataGetAndChoose(choice);
   main();
   return 0; 
}
相關文章
相關標籤/搜索