1. 程式人生 > >計算機專案部第一次培訓總結

計算機專案部第一次培訓總結

計算機專案部第一次培訓總結

此次部門培訓的內容是codeblocks的分步除錯的相關操作,探究遞迴的思想,回顧陣列與字串知識。開始初步瞭解指標及相關操作,最後的時間引入了面向物件程式設計的思想,引申出類與物件的基本概念。
*計項部的小狗熊們要認真看喲 *

一、cb的分佈除錯

一串小程式碼:

//輸入一個數,輸出這個數到1之間的數
#include <iostream>
#include <stdio.h>
using namespace std;

void test(int n){
    if(n==0)
        return ;
    cout<<n<<" ";
    test(n-1);
}
int main(void){
    int n;
    cin>>n;
    test(n);
    return 0;
}

除錯
快捷欄紅圈標示,如果沒有,在view下找到Toolbars,把那些東西勾選對號即可。

首先把游標放在int n上,然後按F4(因為版本的不同,有些同學的cb是ctrl shift F7),或者

表示 run to cursor
然後按F7即可單步執行,或者

表示next line(下一步)
這裡需要輸入n的值

下面是一個test函式,如果再按F7,就會直接到return 0,如果想看test函式的執行過程,兩個方法:
①設定斷點(F5)

為了方便檢視相關變數的變化,我們可以開啟watches,下圖中的紅圈,點選選擇watches即可。

②step into ,step out


這個step into可以跳入函式,如果想跳出則點選step out就行了。
退出除錯

二、遞迴思想

1、基本思想
所謂遞迴,就是有去有回
遞迴的基本思想,是把規模較大的一個問題,分解成規模較小的多個子問題去解決,而每一個子問題又可以繼續拆分成多個更小的子問題。
最重要的一點就是假設子問題已經解決了,現在要基於已經解決的子問題來解決當前問題;或者說,必須先解決子問題,再基於子問題來解決當前問題。

或者可以這麼理解:遞迴解決的是有依賴順序關係的多個問題。
我們假設一個抽象問題有兩個時間點要素:開始處理,結束處理
那麼遞迴處理的順序就是,先開始處理的問題,最後才能結束處理。
假設如下問題的依賴關係:
【A】----依賴---->【B】----依賴---->【C】


我們的終極目的是要解決問題A,
那麼三個問題的處理順序如下:
開始處理問題A;
由於A依賴B,因此開始處理問題B;
由於B依賴C,開始處理問題C;
結束處理問題C;
結束處理問題B;
結束處理問題A。

2、廣義遞迴
從函式呼叫看廣義遞迴
對於軟體來說,函式的呼叫關係就是一個廣義遞迴的過程,如下,

func_A()
{
func_B();
}
func_B()
{
func_C();
}
func_C()
{
/////
}

呼叫函式A;
呼叫函式B;
呼叫函式C;
函式C返回;
函式B返回;
函式A返回;

3、狹義遞迴
有一種特例,就是處理問題A/B/C的方法是一樣的,這就是產生了狹義的“遞迴函式“,即函式內又呼叫函式自身。
從上述分析看,遞迴對問題的處理順序,是遵循了先入後出(也就是先開始的問題最後結束)的規律。
先入後出?
沒錯,廣義遞迴問題的處理,需要用棧來解決。經典的例子就是函式呼叫,就是依靠棧來實現的。
在這裡插入圖片描述
4、遞迴與棧

  • 在入棧之前,通常需要完成三件事。
    1、將所有的實參、返回地址等資訊傳遞給被調函式儲存
     2、為被調函式的區域性變數分配儲存區
     3、將控制轉移到北調函式入口。

-當 一個函式完成之後會進行出棧操作,出棧之前同樣要完成三件事。
1、儲存被調函式的計算結果。
  2、釋放被調函式的資料區。
  3、依照被調函式儲存的返回地址將控制轉移到呼叫函式
測試程式碼

#include <stdio.h>
void recurrence(int num)
{
        if ( num < 0 )
        return;
       printf("%d\n", num);
       recurrence(num - 1); 
    printf("%d\n", num);
}
 int main(void) 
{ 
       recurrence(5); return 0; 
}

圖解
在這裡插入圖片描述

三、資料及字串回顧

題目檢測:
複習相關知識後)
有一個3*4矩陣,請你編寫程式早找出每一行中最大值一次輸出來
(用函式和指標相關知識解決)

四、神奇的指標

1、對指標變數的型別說明包括三個內容:
(1)指標型別說明,即定義變數為一個指標變數;
(2)指標變數名
(3)變數值(指標)所指向的變數的資料型別。
其一般形式為: 型別說明符 *變數名;

2、其中,表示這是一個指標變數,變數名即為定義的指標變數名,型別說明符表示本指標變數所指向的變數的資料型別。

例如: int *p1;表示p1是一個指標變數,它的值是某個整型變數的地址。 或者說p1指向一個整型變數。至於p1究竟指向哪一個整型變數, 應由向p1賦予的地址來決定。
應該注意的是,一個指標變數只能指向同類型的變數(基型別),如P3 只能指向浮點變數,不能時而指向一個浮點變數, 時而又指向一個字元變數

3、取地址運算子&

取地址運算子&是單目運算子,其結合性為自右至左,其功能是取變數的地址。在scanf函式及前面介紹指標變數賦值中,我們已經瞭解並使用了&運算子。

4、取內容運算子*
取內容運算子是單目運算子,其結合性為自右至左,用來表示指標變數所指的變數。在運算子之後跟的變數必須是指標變數。需要注意的是指標運算子和指標變數說明中的指標說明符 不是一回事。在指標變數說明中,“”是型別說明符,表示其後的變數是指標型別。而表示式中出現的“”則是一個運算子用以表示指標變數所指的變數。

感受程式碼:

int main()
{
    int b=2,a=1,*pa,*pb;
    pa=&a;
    pb=&b;
    //pa=pb;
    cout<<a<<endl<<b<<endl;
    cout<<*pa<<endl<<*pb;
    return 0;
}

引發問題的操作:

int main(void)//危險的不合適的操作,指標變數p未賦予地址,就對其取值。
{
    int   i=10;
    int   *p;
    *p=i;
    cout<<*p;
}

指標的算術運算:

int main()//指標的算術運算
{

    int b[5]= {12,23,34,45,65};
    int *p=&b[0];
    p++;
    cout<<"*p="<<*p<<endl;
    cout<<"p="<<p<<endl;
    *p++;
    cout<<"*p="<<*p<<endl;
    cout<<"p="<<p<<endl;
    (*p)++;
    cout<<"*p="<<*p<<endl;
    cout<<"p="<<p<<endl;
    *++p;
    cout<<"*p="<<*p<<endl;
    cout<<"p="<<p<<endl;
    ++*p;
    cout<<"*p="<<*p<<endl;
    cout<<"p="<<p<<endl;
    return 0;
}

傳值傳址*的區別(重要):
如下三個swap只有第一個產生實際作用,因為它沒有對形參(這裡是指標變數)進行直接變動操作,而是利用指標變數改變了它指向的值。其餘兩個函式不能發揮作用,因為他們對形參進行了直接變化,這個變化不可以傳遞到main函式中。

int main()//指標變數做引數,交換a與b的值
{
//    void swap(int *p1,int *p2);
    void swap(int,int);
    int *pointer1,*pointer2,a,b;
    cin>>a>>b;
    pointer1 = &a;
    pointer2 = &b;
    if(a<b)
        swap(a,b);
    cout<<"max="<<a<<" "<<"min="<<b<<endl;
    return 0;
}

void swap(int *p1,int*p2)//可行的利用指標交換指向的內容,繞過了“單項傳遞”,達到交換值的目的
{
    int temp;
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}


void swap(int x,int y)//暴力膜不可取,直接換是不行的,實參到形參為單項傳遞,形參值的變化無法傳給實參
{
    int temp;
    temp = x;
    x=y;
    y= temp;
}

void swap(int *p1,int*p2)//也是不可取的,形參實參為指標變數,試圖改變指標變數是無法對實參的指標變數產生影響。
{
    int *temp;
    temp = p1;
    p1 = p2;
    p2 = temp;
}

5、指標與陣列:

int a[10], *pa; pa=a;  pa =&a[0]; //等價

引用一個數組元素,有3種方法:
(1)下標法: a[i]
(2)陣列名地址法: *(a+i)
(3)指標法: ①指標地址法: *(pa+i) ②指標下標法: pa[i]

int main()//練習用不同的方法表示二維陣列的元素
{

    int a[3][4]= {{5,6,7,8},{9,10,11,12},{13,14,15,16}};
    int i,j , (*p)[4];
    for(i=0; i<3; i++)
    {
        p=&a[i];
        cout<<(*p)[0]<<(*p)[1]<<(*p)[2]<<(*p)[3]<<'\n';
    }
    p=a;
    for(i=0; i<3; i++)
        for(j=0; j<4; j++)
        {
            cout<<*(*(p+i)+j)<<*(p[i]+j)<<*(*(a+i)+j)<<'\n';
        }

}

在這裡插入圖片描述**加粗樣式
指標陣列:

int main()//指標陣列舉例
{

    float a[ ] = {100,200,300,400,500};
    float *p[5] = {&a[0],&a[1],&a[2],&a[3],&a[4]};
    int i;
    for(i = 0; i < 5; i++)
        cout << *p[i] << '\t';

}

6、指標與函式:

int f1(int x,int y)//指向函式的指標舉例,p指向函式的入口地址
{
    int z;
    z=(x>=y)?x:y;
    return z;
}
int f2 (int a,int b)
{
    return (a+b);
}
int  main()
{
    int (*p)(int,int);
    int c,d;
    p=f1;
    c=p(5,10);
    p=f2;
    d=p(8,10);
    cout<<c<<'\t'<<d;
}

五. 面向物件程式設計基本概念

1、面向過程的普遍特點對比面向物件的特點:
(面向過程)
①以功能為核心,以解決問題的過程和步驟為指導進行設計;
② 函式是構成程式的基本部分,也是軟體複用的基本單位;
③ 函式之間相互獨立,可以互相呼叫;
④ 程式結構清晰,模組化思想便於分工合作、提高開發效率;
⑤ 程式流程在編碼時已經確定,使用者不能更改;
⑥ 操作與資料相互分離,難以對資料和操作模組進行修改。
⑦ 設計者難以在開始就對需要解決的問題有比較全面的瞭解;
⑧ 難以進行程式功能擴充套件和維護
(面向物件)
① 強調程式中的物件以及物件之間的關係能夠如實地反映問題
域中的事物及其關係。
② 整個源程式程式碼主要由若干個類構成;
③ 可以按需確定程式流程,通過物件之間相互發送訊息建立各
物件之間的聯絡,完成整個程式的功能;
④ 具有抽象性、封裝性、繼承性和多型性的特徵;
⑤ 類的大量載入會犧牲系統性能,降低執行速度。
2、面向物件基本概念
• 物件是具有一定的特徵和行為的實體;
• 類是為了描述一組物件在結構和行為上的共性所建立的抽 象資料型別;是對具有相同或相似性質的物件的抽象描述;
• 類是建立物件的模板,從一個類例項化的每個物件具有相 同結構和行為;
• 一旦定義了一個類,程式設計師就可以從一個類建立這個類的 任意數目的物件,然後操作這些物件
3、封裝
封裝是將一組相關的概念聚集在一個單元內,並 且用單獨的一個名字來引用。
面向物件的封裝是將操作和表示狀態的屬性包裝 在一個物件型別中,從而使狀態只能通過封裝體 提供的介面來訪問和修改。
4、繼承
繼承允許在已有類的基礎上定義新類(派生類),
派生類自動擁有已有類(基類)的屬性和操作
5、派生類可以增加自己特有的功能,也可以修改繼
承得到的功能(覆蓋)。

6、多型
多型性是一種機制,指一個操作名或屬性名可在多個程式 單元中定義,且在各個程式單元中有不同的實現。
• 類的多型性是指在一般類中定義的屬性或行為,被特殊類 繼承之後,可以具有不同的資料型別或表現出不同的行為。
• 分為兩個方面:
靜態多型:通過函式過載運算子過載模板實現
動態多型:通過類的繼承關係虛擬函式機制實現。
封裝和資訊隱藏
類把資料和對資料的操作封裝在一個結構中;
• 資料一般被限定為私有的,在類的外部只能通過公有的接 口訪問私有的資料。
• 類的宣告和類的實現一般放到不同的兩個檔案中;
• 為了隱藏實現的細節,類的實現檔案以目標檔案的方式提 供;
• 為了隱藏資料成員,在實現檔案中定義資料結構體,在類 的宣告中通過指標訪問資料結構體

7、優勢:
– 加強了類的安全性一致性
– 類的改變可不影響使用該類的程式的正常執行
– 對於使用者,不需要了解過多的細節就可以使用物件, 降低了操縱該型別的複雜程度;
– 對於設計者,有利於保護類的內部設計不被破壞或竊取
8、類的定義

class <類名> 
{ 
public: <資料成員或成員函式的宣告>
protected: <資料成員或成員函式的宣告> 
private: <資料成員或成員函式的宣告> 

};
程式碼示例:
#include <iostream>

using namespace std;


class Rectangle
{
private:
    int left , top , right , bottom ;
public:
    Rectangle(int l, int t, int r,int b)
    {
        left=l ;
        top=t ;
        right=r ;
        bottom=b;

    }
    Rectangle()
    {
        left=0 ;
        top=0 ;
        right=0 ;
        bottom=0 ;

    }
    void print()
    {
        cout<<left<<" "<<top<<" " ;
        cout<<right<<" "<<bottom<<'\n';
    }
};
int  main()
{
    Rectangle r1(100,200,300,400);
    r1.print();
    Rectangle r2;
    r2.print();
    return 0;
}