C/C++入門學習
C++部落格
C++小白筆記:
1.簡單的c++程式
1.1簡單的C++程式helloworld
#include "iostream"
//Iostream時iostream.h的加強版本,是為了與C語言做區別去掉了.h
using namespace std; //使用名稱空間 std 標準的名稱空間 (在這個名稱空間中定義了很多標準定義)
void main01()
{
//printf(“hello….\n”); C語言實現
//cout 標準輸出 黑螢幕,
//<< 左移操作符 在c++裡面 功能的改造(增強)===>C++ 語言操作符過載
//endl = \n
cout << “hello….”<
#include<iostream>
using namespace std;//c++的名稱空間
class circle //程式掃描到這兒是初始化變數,然後會對變數直接拿值
{
public:
double r;
double pi = 3.1415926;
double area = pi*r*r;
};
// 2010編譯不通過 但是在2013編譯器能編譯通過,但是亂碼
int main()
{
circle c1;
cout << “please input your r” << endl;
cin >> c1.r;
cout << c1.area << endl; //亂碼
system("pause");
return 0;
}
分析:
總結:
從記憶體四區的角度,解釋為什麼會出現亂碼
理解為什麼需要成員函式:既然定義變數只能拿值,就定義成員函式,重新計算,呼叫啊
2程式設計方法的發展歷程
1.>面向過程的結構化程式設計方法
設計思路
–自頂向下、逐步求精。採用模組分解與功能抽象,自頂向下、分而治之。
優點:
有效地將一個較複雜的程式系統設計任務分解成許多易於控制和處理的子任務,便於開發和維護。
缺點:可重用性差、資料安全性差、難以開發大型軟體和圖形介面的應用軟體
–把資料和處理資料的過程分離為相互獨立的實體。
–當資料結構改變時,所有相關的處理過程都要進行相應的修改。
–每一種相對於老問題的新方法都要帶來額外的開銷。
–圖形使用者介面的應用程式,很難用過程來描述和實現,開發和維護也都很困難。
舉例圖形介面:比如選單,開啟有好多選項,需求隨機,天生存在,用面向過程很難完成,用c++的多型容易做
2>面向物件的方法
將資料及對資料的操作方法封裝在一起,作為一個相互依存、不可分離的整體——物件。
對同類型物件抽象出其共性,形成類。
類通過一個簡單的外部介面,與外界發生關係。
物件與物件之間通過訊息進行通訊。
面向物件的基本概念 :封裝,繼承,多型
物件:根據現實社會的事物,抽象出一個類,然後把類例項化,變成物件
類
–
封裝
也就是把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信的類或者物件操作,對不可信的進行資訊隱藏。
多型
多型是指在一般類中定義的屬性或行為,被特殊類繼承之後,可以具有不同的資料型別或表現出不同的行為。這使得同一個屬性或行為在一般類及其各個特殊類中具有不同的語義。
面向物件的軟體工程
面向物件的軟體工程是面向物件方法在軟體工程領域的全面應用。它包括:
–面向物件的分析(OOA)
–面向物件的設計(OOD)
–面向物件的程式設計(OOP)
–面向物件的測試(OOT)
–面向物件的軟體維護(OOSM)
總結:
面向過程程式設計:資料結構 + 演算法
主要解決科學計算問題,使用者需求簡單而固定
特點:
分析解決問題所需要的步驟
利用函式實現各個步驟
依次呼叫函式解決問題
問題:
軟體可重用性差
軟體可維護性差
構建的軟體無法滿足使用者需求
3 .C語言和C++語言關係
C語言是在實踐的過程中逐步完善起來的
沒有深思熟慮的設計過程
使用時存在很多“灰色地帶”
殘留量過多低階語言的特徵
直接利用指標進行記憶體操作
C語言的目標是高效
最終程式執行效率的高效
當面向過程方法論暴露越來越多的缺陷的時候,業界開始考慮在工程專案中引入面向物件的設計方法,而第一個需要解決的問題就是:高效的面嚮物件語言,並且能夠相容已經存在的程式碼。
C語言 + 面向物件方法論===》Objective C /C++
C語言和C++並不是對立的競爭關係
C++是C語言的加強,是一種更好的C語言
C++是以C語言為基礎的,並且完全相容C語言的特性
總結:
學習C++並不會影響原有的C語言知識,相反會根據加深對C的認知;
學習C++可以接觸到更多的軟體設計方法,並帶來更多的機會。
1)C++是一種更強大的C,通過學習C++能夠掌握更多的軟體設計方法
2)C++是Java/C#/D等現代開發語言的基礎,學習C++後能夠快速掌握這些語言
3)C++是各大知名軟體企業挑選人才的標準之一
問題:學出C/C++的人,做底層,容易故步自封;Java程式設計師經常呼叫,學習速度快;如果c/c++程式設計師思想轉過來,效率將特別高,勢如破竹。
簡單分析一個公司的產品開發需要的技術。
4 C++對C的加強
4.1 namespace名稱空間
1 C++名稱空間基本常識
所謂namespace,是指識別符號的各種可見範圍。C++標準程式庫中的所有識別符號都被定義於一個名為std的namespace中。
一 :和
#include "iostream"
using namespace std;//名稱空間將全域性作用域分成不同的部分
//1檔案中iostream 沒有引入標準的 std ; 需要我們程式設計師手工的寫
//2 如果不寫 using namespace std; 需要顯示的引入std
void main31()
{
std::cout<<”namespace test”<
#include <iostream>
usi//C語言中的變數都必須在作用域開始的位置定義!!
//C++中更強調語言的“實用性”,所有的變數都可以在需要使用時再定義。
void main41()
{
int i;
printf("hello...\n");
int k;
i = 10;
k = 11;
printf("i:%d k:%d \n", i, k);
system("pause");
}
4.3 register關鍵字增強
void main42()
{
register int a = 0;
printf(“&a: %d \n”, &a); //不能在暫存器變數上取地址
for (int i=0; i<1000; i++) //不使用register也可能做優化
{
printf("i:%d \n", i);
}
system("pause");
}
4.4變數檢測增強
/*
在C語言中,重複定義多個同名的全域性變數是合法的
在C++中,不允許定義多個同名的全域性變數
C語言中多個同名的全域性變數最終會被連結到全域性資料區的同一個地址空間上
int g_var;
int g_var = 1;
C++直接拒絕這種二義性的做法。
*/
int g_a = 100;
//int g_a ;
void main()
{
printf(“hello…g_a:%d \n”, g_a);
}
4.5 struct型別加強
#include <iostream>
using namespace std;
//struct 關鍵字 class關鍵字 完成的功能是一樣的
//區別後面介紹 拋磚
class c1
{
public:
protected:
private:
};
struct Teacher
{
public:
char name[32];
int age;
protected:
int a;
};
void main51()
{
Teacher t1; //
t1.age = 10;
printf(“hello…\n”);
system("pause");
}
4.6c++型別型別檢查加強
/*
C++中所有的變數和函式都必須有型別
C語言中的預設型別在C++中是不合法的
函式f的返回值是什麼型別,引數又是什麼型別?
函式g可以接受多少個引數?//特別多個
*/
/*
//更換成.cpp試試
f(i) //C語言的灰色地帶
{
printf(“i = %d\n”, i);
}
g() //C語言的灰色地帶
{
return 5;
}
int main(int argc, char *argv[])
{
f(10);
printf(“g() = %d\n”, g(1, 2, 3, 4, 5)); //C語言的灰色地帶
getchar();
return 0;
}
*/
//C語言中的這些灰色地帶在大專案中容易出錯。
4.7新增bool關鍵字
#include <iostream>
using namespace std;
void main()
{
bool b1 = true; //告訴c++編譯器給我分配 1個位元組的記憶體
bool b2, b3, b4, b5;
//
cout<<”sizeof(bool)”<
#include <iostream>
using namespace std;
//在C語言中 表示式的結果 放在什麼地方 暫存器
//1
// 在C語言中, 表示式的返回值 是變數的值不能作為左值使用
// 在C++中, 表示式返回的是變數的本身 因此可以出現在程式的任何地方
//2 如何做到的
//讓表示式返回一個記憶體空間 ..記憶體首地址 指標
//在C語言中 如何 實現 c++的效果
//3 本質
//c++編譯器 幫我們程式設計師完成了 取地址的工作
int main()
{
int a = 10;
int b = 20;
int var = 100;
var = 101;
//回一個最小數 並且給最小數賦值成3
//三目運算子是一個表示式 ,表示式不可能做左值
(a < b ? a : b )= 30;
//int z = (a < b ? a : b );
printf("a = %d, b = %d\n", a, b);
//思考:如何讓C中的三目運演算法當左值呢?
//(a < b ? &a :& b )
system("pause");
return 0;
}
5 C/C++中的const
1 const基礎知識(用法、含義、好處)
初級理解:const是定義常量==》const意味著只讀
Const好處
//合理的利用const,
//1指標做函式引數,可以有效的提高程式碼可讀性,減少bug;
//2清楚的分清引數的輸入和輸出特性
1233
using namespace std;
//0 const的基礎知識
struct Teacher
{
char name[64];
int age;
};
//指標所指向的記憶體空間,不能被修改
int operatorTeacher01(const Teacher *pT)
{
//pT->age = 10;
return 0;
}
//指標變數本身不能被修改
int operatorTeacher02( Teacher * const pT)
{
pT->age = 10;
//pT = NULL; //
return 0;
}
int operatorTeacher03( const Teacher * const pT)
{
//pT->age = 10;
//pT = NULL; //
printf(“age:%d”, pT->age);
return 0;
}
void main81()
{
// const int a;
// int const b; //第一個第二個意思一樣 代表一個常整形數
//
// const int *c; //const修飾的是指標所指向的記憶體空間,不能被修改 但是本身可以修改
// int * const d; // d 常指標(指標變數不能被修改,但是它所指向記憶體空間可以被修改)
// const int * const e ;// e一個指向常整形的常指標(指標和它所指向的記憶體空間,均不能被修改
cout<<”hello…”<
#define d 20
void main84()
{
//int a = 10;
//int b = 20;
//int array[a+b]; //linux核心裡面是成立的;原因 編譯linux核心的gcc編譯器支援.
//c和c++編譯器 不支援這種語法現象
const int c = 10;
//const int d = 20;
int array2[c+d];
system(“pause”);
}
//5 const定義的變數,由編譯器處理的,提供型別檢查和作用域檢查
void fun1()
{
#define a 10
const int b = 20;
//#undef a
//# undef
}
void fun2()
{
printf(“a = %d\n”, a);
printf(“b = %d\n”, b);
}
int main()
{
fun1();
fun2();
return 0;
}
對比加深
C++中的const常量類似於巨集定義
const int c = 5; ≈ #define c 5
C++中的const常量與巨集定義不同
const常量是由編譯器處理的,提供型別檢查和作用域檢查
巨集定義由前處理器處理,單純的文字替換
6引用專題
1引用(普通引用)
變數名回顧
變數名實質上是一段連續儲存空間的別名,是一個標號(門牌號)
程式中通過變數來申請並命名記憶體空間
通過變數的名字可以使用儲存空間
問題1:對一段連續的記憶體空間只能取一個別名嗎? 可以,就是引用
#include <iostream>
using namespace std;
//1 引用的概念
//2 屬於C++編譯器對C的擴充套件,不能用c語言的語法去思考它
void main91()
{
int a = 10;
//引用的語法:Type& name = var;
int &b = a;
b = 100; //相當於把a修改成100了.
printf(“b:%d \n”, b);
printf(“a:%d \n”, a);
a = 200;
printf(“b:%d \n”, b);
printf(“a:%d \n”, a);
cout<<"hello..."<<endl;
system("pause");
return ;
}
void main92()
{
int a = 10;
int &b = a;
//int &c ; //03普通引用 必須要初始化
system(“pause”);
}
//基礎型別的引用
void myswap(int a, int b)
{
int c = 0;
c = a;
a = b;
b = c;
}
void myswap02(int *a, int *b)
{
int c = 0;
c = *a;
*a = *b;
*b = c;
}
//04 引用作為函式引數宣告時不進行初始化
void myswap03(int &a, int &b)
{
int c = 0;
c = a;
a = b;
b = c;
}
void main93()
{
int x, y ;
x = 10;
y = 20;
myswap(x, y);
printf(“x:%d , y:%d \n”, x, y);
myswap02(&x, &y); //引用做引數宣告時不進行初始化
printf("x:%d , y:%d \n", x, y);
//a就是x的別名 b就是y的別名
myswap03(x, y);
printf("x:%d , y:%d \n", x, y);
//int &c ; //普通引用 必須要初始化
system("pause");
}
//05複雜資料型別 的引用
struct Teacher
{
char name[64];
int age ;
};
void printfT(Teacher *pT)
{
cout<age<
#include <iostream>
using namespace std;
//1 第一點 單獨定義的引用時,必須初始化;說明很像一個常量
void main01()
{
//
const int c1 = 10;
int a = 10;
int &b = a; //b很想一個常量
printf("&a:%d \n", &a);
printf("&b:%d \n", &b); //===> a 和 b就是同一塊記憶體空間的門牌號
cout<<"hello..."<<endl;
system("pause");
return ;
}
//2 普通引用有自己的空間嗎? 有
struct Teacher
{
char name[64]; //64
int age; //4
int &a; //4 0 //很像指標 所佔的記憶體空間大小
int &b; //4 0
};
//3 引用的本質
void modifyA(int &a1)
{
a1 = 100;
}
void modifyA2(int * const a1)
{
a1 = 200; //實參的地址 ,去間接的修改實參的值
}
void main1001()
{
int a = 10;
//1
modifyA(a); //指向這個函式呼叫的時候,我們程式設計師不需要取a的地址
printf("a:%d \n", a);
//
a = 10;
modifyA2(&a); //如果是指標 需要我們程式設計師手工的取實參的地址
printf("a:%d \n", a);
printf("sizeof(Teacher):%d \n", sizeof(Teacher));
system("pause");
}
void modifyA3(int *p)
{
*p = 200; //*p 3*p形參去間接修改實參的值
}
//間接賦值
void main()
{
int a = 10;
int *p = NULL; //間接賦值成立的三個條件 1 定義兩個變數
p = &a;
*p = 100;
{
*p = 200;
}
modifyA3(&a); //2 建立關聯
}
// 123 寫在一塊
// 12 3
//1 23
結論:
1)引用在實現上,只不過是把:間接賦值成立的三個條件的後兩步和二為一
//當實參傳給形參引用的時候,只不過是c++編譯器幫我們程式設計師手工取了一個實參地址,傳給了形參引用(常量指標)
2)當我們使用引用語法的時,我們不去關心編譯器引用是怎麼做的
當我們分析奇怪的語法現象的時,我們才去考慮c++編譯器是怎麼做的
7函式返回值是引用(引用當左值)
#include <iostream>
using namespace std;
int getAA1()
{
int a ;
a = 10;
return a;
}返回a的一個副本 10
//返回a的本身 就是a的地址
int& getAA2() //臨時變數,呼叫後就釋放地址
{
int a ; //如果返回棧上的 引用, 有可能會有問題
a = 10;
return a;
}
int* getAA3()
{
int a ;
a = 10;
return &a;
}
void main1101()
{
int a1 = 0;
int a2 = 0;
a1 = getAA1();
a2 = getAA2(); //10
int &a3 = getAA2(); //若返回棧變數 不能成為其它引用的初始值 ,記憶體空間的值已經釋放了,返回可能是亂碼
printf("a1:%d \n", a1);
printf("a2:%d \n", a2);
printf("a3:%d \n", a3); // *a3
cout<<"hello..."<<endl;
system("pause");
return ;
}
//變數是static 或者是 全域性變數
int j1()
{
static int a = 10;
a ++ ;
return a;
}
int& j2()
{
static int a = 10;
a ++ ;
return a;
}
//若返回靜態變數或全域性變數
// 可以成為其他引用的初始值
// 即可作為右值使用,也可作為左值使用
void main1112()
{
int a1 = 10;
int a2 = 20;
a1 = j1();
a2 = j2();
int &a3 = j2();
printf("a1:%d \n", a1);
printf("a2:%d \n", a2);
printf("a3:%d \n", a3);
system("pause");
}
//////////////////////////////////////////////////////////////////////////
//— 函式當左值
//返回變數的值
int g1()
{
static int a = 10;
a ++ ;
return a; //
}
//返回變數本身 ,
int& g2()
{
static int a = 10;
a ++ ;
printf(“a:%d \n” , a);
return a;
}
void main()
{
// g1() = 100;
//11 = 100;
g2() = 100; //函式返回值是一個引用,並且當左值
g2();
int c1 = g1(); //函式返回值是一個引用,並且當右值
int c2 = g2(); //函式返回值是一個引用,並且當右值
//a = 100;
system("pause");
}