strlen函數與sizeof的區別
- 表面上都可求字符串的長度,
- 但二者卻存在着許多不同之處及本質區別。
- strlen 是一個函數,計算指定字符串str長度,不包括結束字符
size_t strlen(char const* str);
- 所以需要進行一次函數調用,調用示例如下面的代碼所示:
char sArr[] = "ILOVEC";
/*用strlen()求長度*/
printf("sArr的長度=%d\n", strlen(sArr));
- 運行結果爲 6(因爲不包括結束字符 null)。
- 注意的是,函數 strlen 返回的是一個類型爲 size_t 的值,從而有可能讓程序導致意想不到的結果,如下面的示例代碼所示:
/*判斷一*/
if(strlen(x)>= strlen(y))
{
}
/*判斷二*/
if(strlen(x)- strlen(y)>= 0)
{
}
- 判斷表達式一沒什麼問題,程序也能夠完全按照預想的那樣工作;但判斷表達式二的結果就不一樣了,它將永遠是真,爲什麼?
- 因爲函數 strlen 的返回結果是 size_t (即無符號整型),size_t 類型絕不可能是負的。因此,語句“if(strlen(x)-strlen(y)>=0)”將永遠爲真。
- 就算表達式中同時包含了有符號整數和無符號整數,還是有可能產生意想不到的結果,如下面的代碼:
/*判斷一*/
if(strlen(x)>= 5)
{
}
/*判斷二*/
if(strlen(x)- 5>=0)
{
}
- 顯然,判斷表達式二的結果還是永遠是真,其原因與上面相同。
- sizeof 是一個單目運算符,不是一個函數。
- 參數可以是數組、指針、類型、對象、函數等
char sArr[] = "ILOVEC";
/*用sizeof求長度*/
printf("sArr的長度=%d\n", sizeof(sArr));
- 運行結果爲 7(因爲它包括結束字符 null)。
- 對 sizeof 而言,因爲緩衝區已經用已知字符串進行初始化,其長度固定,所以sizeof 在編譯時計算緩衝區的長度。
- 由於在編譯時計算,sizeof 不能用來返回動態分配的內存空間的大小。
參考鏈接
- http://c.biancheng.net/view/342.html
C語言中sizeof和strlen的區別與聯繫
- strlen:統計字符串中字符的個數
- sizeof:統計對象所佔的單元(字節)的個數,
- 一般以8位二進制作爲一個存儲單元,
- 所以字節數一般等於存儲單元的個數。
- 返回值
- 整數
- 整數
- 參數
- 類型、數組、指針‘函數
- 數組
- 是否包含“\0”
- 包含
- 不包含(以“\0結束”)
- 本質
- 運算符
- 函數
- 計算時間
- 編譯
- 運行
- 一般用途
- 統計存儲單元個數
- 統計字符串中字符的個數,包括空格
- sizeof用法注意:
- 用於測定類型所佔存儲單元時,類型必須用sizeof(類型)
- 用於數組時,表示數組所佔的存儲空間的大小,可以不用(),
- sizeof(name)=sizeof name,name爲數組
#include <stdio.h>
#include <string.h>
#define PRAISE "What a super marvelous name!"
int main(void)
{
char name[40];
printf("What's your name?\n");
scanf("%s",name);
printf("Hello,%s.%s\n",name,PRAISE);
printf("Your name of %d letters occupies %d memory cells.\n",strlen(name),sizeof(name));
printf("The phrase of praise has %d letters",strlen(PRAISE));
printf("and occupies %d cells.\n",sizeof(PRAISE));
return 0;
}
int sum(int ar[], int n)
{
int i;
int total = 0;
for(i=0;i<n;i++)
{
total += ar[i];
}
printf("The size of ar is %zd bytes.\n",sizeof ar);
return total;
}
- sizeof後面的對象如果是實參數組名,
- 結果爲該數組的存儲空間,
- 但sizeof如果爲一個指向數組首元素的指針,
- 則對於4字節地址的計算機系統,指針的大小爲4字節
- 如以上的sum函數,ar是一個指向數組的首元素的指針,
- 所以該函數輸出的結果爲4。
悲觀鎖與樂觀鎖
- 悲觀鎖
- 每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。
- 關係型數據庫裏邊就用到了很多這種鎖機制,
- 如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
- 它指的是對數據被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度,因此,在整個數據處理過程中,將數據處於鎖定狀態。
- 悲觀鎖的實現,往往依靠數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改數據)。
- 樂觀鎖
- 每次去拿數據的時候都認爲別人不會修改,所以不會上鎖,但在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。
- 適用於多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。
- 兩種鎖各有優缺點,
- 樂觀鎖適用於寫比較少的情況下,即衝突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。
- 但如果經常產生衝突,上層應用會不斷的進行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。
參考鏈接
- https://blog.csdn.net/coderDogg/article/details/85093741
最通俗易懂的樂觀鎖與悲觀鎖原理及實現
- 樂觀鎖 總認爲不會產生併發問題,每次去取數據的時候總認爲不會有其他線程對數據修改,因此不上鎖,
- 但在更新時會判斷其他線程在這之前有沒有對數據進行修改,一般會使用版本號機制或CAS操作實現。
- version方式:一般是在數據表中加上一個數據版本號version字段,表示數據被修改的次數,當數據被修改時,version值會加一。
- 當線程A要更新數據值時,在讀取數據的同時也會讀取version值,在提交更新時,若剛纔讀取到的version值爲當前數據庫中的version值相等時才更新,否則重試更新操作,直到更新成功。
update table set x=x+1, version=version+1 where id=#{id} and version=#{version};
- CAS操作方式:即compare and swap 或者 compare and set,涉及到三個操作數,數據所在的內存值,預期值,新值。
- 當需要更新時,判斷當前內存值與之前取到的值是否相等,若相等,則用新值更新,若失敗則重試,一般情況下是一個自旋操作,即不斷的重試。
- 悲觀鎖
- 每次取數據時都認爲其他線程會修改,所以都會加鎖(讀鎖、寫鎖、行鎖等),
- 當其他線程想要訪問數據時,都需要阻塞掛起。
- 可以依靠數據庫實現,如行鎖、讀鎖和寫鎖等,都是在操作之前加鎖,
- Java中,synchronized的思想也是悲觀鎖。
參考鏈接
- https://blog.csdn.net/L_BestCoder/article/details/79298417
B樹
- 從算法邏輯上來講,二叉查找樹的查找速度和比較次數都是最小的。
- 但我們不得不考慮一個現實問題磁盤IO
- 數據庫索引是存儲在磁盤上的,當數據量較大的時候,
- 索引的大小可能有幾個G
- 當利用索引查詢的時候,能把整個索引全部加載到內存嗎?
- 不可能。
- 只有逐一加載每一個磁盤頁,這裏的磁盤頁對應着索引樹的節點。
- 如果用二又查找樹作爲索引結構
- 設樹高4,查找的值是10,那麼流程如下
-
磁盤I0的次數是4次,索引樹的高度也是4。
-
最壞情況下,磁盤I0數等於樹高
-
爲了減少磁盤I0次數,需把原本“瘦高”的樹結構變得“矮胖”。
-
這就是B-樹的特徵之ー。
-
B樹是一種多路平衡查找樹,每一個節點最多包含k個孩子,k
被稱爲B樹的階。 -
k取決於磁盤頁的大小。
- 3階B-樹爲例,看看B樹具體結構。
- 樹中的具體元素和剛纔的二叉查找樹是一樣的。
- 查5吧!
-
B樹在查詢中的比較次數其實不比二又查找樹少,尤其當單一節點中的元素數量很多時。
-
可是相比磁盤I0的速度,內存中的比較耗時幾乎可以略。
-
所以只要樹的高度足夠低,I0次數足夠少,就可
以提升查找性能。 -
相比之下節點內部元素多一些也沒有關係,僅僅是多了幾內存交互,只
要不超過磁盤頁的大小即可。 -
這就是B-樹的優勢之ー。
這兒還有點沒寫
- B-樹主要應用於文件系統及部分數據庫索引,如著名的非關係
型數據庫 Mongodb。 - 大部分關係型數據庫,如Mysq1用B+樹作爲索引。
參考鏈接
B+樹
- B+樹是B-樹的一種変體,
- 有着比B-樹更高的查詢性能。
- 每個父節點的元素都出現在子節點中,是子節點的最大(或最小)
元素。
- 注意,根節點的最大元素(15),也就等同於整個B+樹的最大元素。
- 以後無論插入刪除多少元素,始終要保持最大
元素在根節點當中。
- 至於葉子節點,由於父節點的元素都出現在子節點,因此所有葉子節點包含了全量元素信息。
- 每一個葉子節點都帶有指向下ー個節點的指針,形成了一個
有序鏈表。
- 衛星數據,指的是索引元素所指向的數據記錄,比如數據庫中的某一行。
- B樹中,無論中間節點還是葉子節點都帶有衛星數據。
- B+樹當中,只有葉子節點帶衛星數據,其餘中間節點僅僅是索
引,沒有任何數據關聯。
- 數據庫的聚集索引中,葉子節點直接包含衛星數據。
- 非聚集索引中,葉子節點帶有指向衛星數據的指針。
- B+樹的好處主要體現在查詢性能上。
- 通過單行查詢和範圍查詢來分析。
- 單元素查詢的時候,B+樹會自頂向下逐層查找節點,最終找到匹配
的葉子節點。 - 比如要查找的是元素3
-
兩點不同。
-
首先,B樹的中間節點沒有衛星數據,所以同樣大小的
磁盤頁可以容納更多的節點元素。 -
意味着,數據量相同的情況下,B+樹比B樹更“矮胖”
因此查詢時10次數也更少。
- B+樹的查詢必須最終查找到葉子,B樹只要找到匹配元素
,無論匹配元素處於中間節點還
是葉子節點。 - B樹查找性能並不穩定(最
好情況是隻查根節點,最壞情況是查
到葉子節點)。而B樹的每一次查找
都是穩定的。