變量和基本類型(基於c++)
1. 基本內置類型
算術類型
: 字符、整數、布爾值、浮點數空類型
:不對應具體的值,用於特殊場合
1.1 算術類型
- 整型(布爾,字符)
- 浮點型
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kqLVeZ2O-1582781339653)(算術類型.png)]
1.1.1 存儲
- 字節佔8比特
- 字佔32或64,也就是4~8字節
每個字節與一個數字(地址)關聯
浮點型的第一個字節是ISO-Latin-1字符集,則就是分號,所以可以知道是浮點型
- 浮點型
- float 32比特
- double 64比特
- long double 96~128比特
- 字符型
- char 8比特
- signed char 8比特
- unsigned char 8比特
- char 8比特
1.2 類型轉換
unsigned char c = -1; // c =255
signed char c = 256; //c2 未定義
-
含無符號的表達式
-
例如:整數和無符號的運算會自動轉化成無符號
unsigned u = 10; int i = -42; cout << i+i << endl; cout << u+i << endl; //-84 //4294967264 32位
-
無符號的負數時爲取模後的值
-
1.3 字面值
20
十進制
024八進制
0x14十六進制
-
字符串的組成是字符數組(字符串的末尾多一個‘\0’)
//分開字符串寫法 std::cout << "你好" "NO" << std::endl; // 你好NO
1.4 轉義序列
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rYyXVvIc-1582781339659)(轉義.png)]
-
也可以用
\x 十六進制
\八進制
-
數值對應的字符集[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AWvPvoHn-1582781339661)(image-20200226084101078.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-bSmDEumQ-1582781339663)(image-20200226084332828.png)]
UL 會根據數值決定是unsigned long 還是unsigned long long
- 前綴爲字符
- 後綴爲整型或浮點型
- aen的後面數值表示a*10n
2. 變量
何爲對象?
對象
:是指一塊能存儲數據並具有某種類型的內存空間。對象也叫變量,而值是隻讀數據
2.1 初始值
///a 先被定義然後賦值, 隨後用於初始化b
double a = 1.1, b = a*2;
- 列表初始化 int a{0};
2.2 變量聲明和定義
C++語言支持分離式編譯
機制,可分成若干個文件獨立運行。
- 聲明:變量聲明規定了變量的類型和名字,不分空間
- 定義:申請存儲空間,也可能給變量賦初始值
extern int i; // 聲明i並非定義i
int j; //聲明j並定義j
變量只能被定義一次,但可以聲明很多次
2.3 表示符
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-HueBUExx-1582781339664)(image-20200226103919393.png)]
2. 4 名字的作用域
- 全局作用域
- 塊作用域
2.4.1 外層作用域
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
int reused = 42;//全局
int main(){
int unique = 0; // 塊
cout << reused << " " << unique << endl;
int reused = 0;
cout << reused << endl; //局部覆蓋了全局
cout << ::reused << endl; //全局
{
int reused = 5;
cout << reused <<endl; //局部覆蓋局部
cout << ::reused <<endl; //全局
}
return 0;
}
3. 複合類型
一條聲明語句由一個人基本
基本數據類型
和一個聲明符
列表組成
3.1 引用
c++11添加的
右值引用
- 定義:爲對象起另外一個名字,引用類型引用另一種類型通過將聲明符寫成&d的形式。
- 引用必須初始化
- 引用並非對象
int i, &ri = i;
i = 5; ri = 10;
cout << i << " " << ri << endl; //10 10
int &r = 0; //錯誤 不能是值
3.2 指針
指針是“指向”另外一種類型的複合類型。實現了間接訪問。
指針存放的是變量地址
int i;
int *pi = &i;
int *p = pi;
指針的四個狀態
- 指向一個對象
- 指向緊鄰對象所佔的空間的下一個位置
- 空指針
- 無效指針
在指針前面加*號得到指針p得對象。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BNIvwbhU-1582781339666)(image-20200226125751785.png)]
空指針
int *p1 = nullptr;//c++11得特殊字面值
int *p2 = 0;
int *p3 = NULL; //include <cstdlib>
注意不能給指針賦int變量。
3.2.1 void* 指針
void *是一種特殊的指針,可以存放任意對象的地址
double obj = 3.14, *pd = &obj;
void *pv = &obj;
pv = pd;
- void* 指針只能比較
- 作爲函數的輸入輸入輸出
- 做另一個void*指針賦值
- 其他不能操作
3.2.2 指向指針的指針
理解看法:
- 把變量名和前面的分開
- 如 int **p;
- 可以看出 int * 類型的指針* 變量名爲p
3.3 複合類型
-
聲明
例子:
int* p1, p2; //p1是指向int的指針,p2是int int ival = 11; int *pi = &ival; //指向ival的指針 int **ppi = π //指向指針的指針
按我的理解聲明可以從右向左看問題,它是什麼就看變量前一個字符,如果是*它指針 其他前面的東西都是它的類型,如果是&那它就是引用,其他前面的都是類型
例如:
int i = 42; int *p; int *&r = p; ///它是引用,是int指針型的 r = &i; *r = 0;
4 const 限定符
有時我們希望, 定義一個值不會改變的變量
const int buf = 512; //常量
const int i = get_size(); //正確
const int k; //錯誤
int f = 9;
const int c = f; //正確
-
const 對象一旦創建就不能改變,所以一定要初始化
-
const 對象只能再自身文件內使用,多文件的情況下不能共享// 但我的嘗試發現可以共用的。。
-
但是也有解決辦法如下:
-
不管是聲明還是定義都添加extern關鍵字
//file.cc 定義並初始化一個常量,可以給其他文件訪問 extern const int buf = 5; //file.h 頭文件 extern const int buf; //與file.cc 中的buf一樣
-
-
const 引用
const int k = 5; const int *p = &k; int i = 42; const int &r1 = i; //常量引用是允許綁定普通int對象,但不能返過來 const int &r2 = 5; int &r4 = r1*2; //錯誤 double dval = 3.14; const int &r5 = &dval; ///3 相當於const int tem = dval;const int &r5 = tem; //這就是臨時量
- const引用的作用
int i = 42; int &r1 = i; const int &r2 = i; r1 = 0; //正確 r2 = 0; //錯誤 ,不能通過r2進行更改,但r2可以訪問i;
4.1 指針和const
指向常量的指針
const double pi = 3.1;
double *ptr = π //錯誤和引用一樣類型不對,不能返過來。但常指針可以指向普通double
const double *cp = π //正確
4.1.1 const 指針
-
指針是對象引用不是
-
常量指針必須初始化
-
把*放在const 前說明指針是一個常量,不變的是指針本身的那個值而不是非指向的那個
int err = 0; int *const cur = &err; //cur一直指向err 但它能操作err的值 const double pi = 3.1; const double *const pip = π //指向常量的常指針
4.1.2 頂層const
頂層
表示指針本身是個常量底層
表示指針所指的對象是着常量
int i = 0; //const的類型
int *const p1 = &i; //不能改變p1的值,頂層
const int ci = 42; //不能改變ci的值, 頂層
const int *p2 = &ci //允許改變p2的值,底層
const int *const p3 = p2; //靠右的是頂層,靠左的是底層
const int &r = ci; //用聲明引用的都是底層
- 一般非常量可以換常量,反之不可
4.2 constexpr 和常量表達式
常量表達式
指值不會改變,且在編譯過程中能得到計算結果的表達式
const int max_files = 20; // 是常量表達式
const int limit = max_files+1; // 是
int i = 27; //不是
const int sz = get_size(); //不是,直到運行才能獲得的不是
c++11的新規定, constexpr類型是驗證是否是常量表達式的,聲明constexpr肯定式個常量,且必須式常量表達式
constexpr int mf = 20; // 是
constexpt int sz = size(); // 只有當size是個constexpr函數是才正確
4.2.1 指針和constexpr
必須明確一點,constexpr只對指針有效,對所指的變量不影響
const int *p = nullptr; //p是一個指向整型常量的指針
constexpr int *q = nullptr; //q是一個指向整數的常量指針
//且它所指向的必須要在函數體外
5. 處理類型
5.1 類型別名
是一個人名字,爲了讓複雜的名字變得簡單明瞭
兩種方法:
typedef double wages; //同義詞
typedef wages base, *p; //base 是double的同義詞,p是double*的同義詞
c++11的新規則:
別名聲明定義類型的別名
using SI = Sales_item; //SI 與Sales_item同義詞
5.1.1 一些複雜複合例子
typedef char *pstring;
const pstring cstr = 0; //cstr 是指向char類型的常量指針
const pstring *ps; //ps 是一個指針,它的對象是指向char的常量指針
- 以上可以看出不能完全安照原來的樣子去用
5.2 auto 類型說明符
編程時常常需要給表達式的值賦給變量,這就要求變量清楚知道表達式的類型
所以c++11引入auto類型說明符,能通過初始值推算變量類型。
- auto變量必須有初始值
auto item = val1+val2; //item初始化爲相加的結果
auto i = 0, *p = &i; //正確:i是整數、p是整數指針
auto sz = 0, pi = 3.14; //錯誤兩個的類型不同
int as[3][4];
auto (&row)[4] = as[1]; //錯誤auto 對於auto 默認查找到的返回值是指向as[1][0] 的指針;引用不能是數組,只能是數組類型的引用,因爲爲引用不是對象
auto &row = as[1]; //這樣就是可以的。
5.2.1 複合、常量、auto
當編譯器推斷出來的auto類型有時候和初始值不完全一樣,會事到改變結果類型,使其符合
int i = 0, &r = i;
auto a = r; //a是一個整數(r是別名)
- auto 會忽略頂層const,同時底層const會保留。(個人理解就是相當於它的變量都不是常量,都可以修改)
const int ci = i, &cr = ci;
auto b = ci; //是整數頂層被忽略了
auto c = cr; //是整數ci本身是頂層的
auto d = &i; //是一個整數指針
auto e = &ci; //是一個指向整數常量的指針
-
如果希望是頂層const ,指明就行
-
還可以引用
const auto f = ci; auto &g = ci; //是一個整數常量的引用
5.3 decltype 類型指示符
c++11 新標準引入的第二種類型說明符 decltype
- 作用是選擇並返回操作數的數據類型
- 編譯器飯分析表達式並得到他的類型,卻不實際計算值
decltype(f()) sum = x; //sum的類型就是函數f的返會類型
-
decltype 處理頂層const 和引用的方式與auto有些不同
const int ci = 0, &cj = ci; decltype(ci) x = 0; //x的類型是const int decltype(cj) y = x; //y的類型是const int&, y綁定到變量x decltype(cj) z; //錯誤引用必須初始化 int i = 42, *p = &i, &r = i; decltype(r+0) b; //正確了加法的返回時是int型 decltype(*p) c; //錯誤:c是int &,要初始化
- 有些表達式返回引用類型(之後再細講)
- 這裏的因爲*指針的結果其實就是 int& 而並非int,它相當於別名
-
表達式里加上括號也可能會有所不同
-
變量是一種作爲賦值語句左值的特殊表達式。加上括號就是引用類型了
decltype((i)) d; //錯誤引用,要初始化 decltype((i+5)) e; //正確
- 變量加兩層括號就是引用
6. 定義數據結構
c++允許自定義數據類型,而庫類型,也是以類的形式定義的。
struct Sales_data {
std::string str;
unsigned un = 0;
double do = 0.0;
};
- 內部定義的名必須唯一與外部可重複跟局部變量類似
struct Sales{...} a, *c;
Sales kk, *ks;
跟c語言種的結構體類似。
c++11新規定。可以爲數據成員提供一個類內初始值。
6.1 編寫自己的頭文件
爲了確保各個文件中類的定義一致,類通常定義再頭文件中,頭文件和類名一樣。
- 頭文件也能用其他頭文件的功能。
- 使用用過其他頭文件的頭文件,也需要再一次包含它所用過的頭文件
預處理器:
#include
: 指定頭文件
#define
:預處理變量
頭文件保護符用於檢測預處理變量:
#ifdef //當且僅當變量已定義時爲真,
#ifndef //當且僅當變量未定義時爲真
當檢測爲真時,則後續操作到 #endif爲止
#ifndef STATUS_H
#define STATUS_H
#include <string>
struct sda{
std::string bo;
unsigned un = 0;
double re = 0.0;
};
#endif
- 如果爲真繼續執行
- 如果爲假ifndef到endif之間的部分將略過
注意用多文件的時候有些軟件需要導入路徑
參考文獻:C++ Primer第五版