第五章
P34,作用域符::,代表的是程序中的全局變量或者標準程序庫的函數
P35,判斷條件與(&、i++),其中當判斷條件中前面的條件爲0後面的條件就不用計算了,或也是如此
P36,編程風格:常量在判斷等式前面
P36,優先級:》的優先級在~之前
P38,float和double的存儲方式:其中float是這樣的,1位符號位,8位階碼位,23位尾數位,先將數據化爲二進制,再將其畫成科學數位的樣式,存儲階碼=其畫成階碼所要移動的位數+127,23位尾數=原本科學計數法的數-1,如1.0f=3F800000,0=0x00000000
int 智能取值,int & 取地址相應的值
大端模式:高位存儲低位(這樣其實很方便查看),51單片機等等。小端模式:低位存儲低位,高位存儲高位。arm、dsp、x86都是這鐘
P38,強行轉換時,太多會直接取低位
P38-39,
unsigned int a=0xFFFFFFF7;
unsigned char i=(unsigned char )a
char *b=(char *)&a;
結果是,i 的值爲0x000000f7,0xfffffff7.
P41,x&(x-1)的妙用,2的N次方對x&(x-1)計算結果爲0,同時while(m){count ++,m=m&(m-1)}可以計算m中1的個數
P42,ab交換的方法 .方法一:a=a+b;b=a-b;a=a-b;方法二:a=a^b;b=a^b;a=a^b;
不判斷找出最大的:max=((a+b)+abs(a-b))/2
int c=a-b,然後講c右移31位,再看是1或者0即可
第六章
P49,內存對齊,這個知識點有很多內容,只發散以下兩點
結構體的大小,遇到長的必須以4或者8爲單位對齊,如
{ char a;double b,int a}的大小爲24,
{ char a[9];double b,int a}的大小爲32,
{char a[9];int c;double b;}的大小爲24
類的大小
空類爲1
父類是空類的,對子類無影響
如果類中有定義變量,仿照結構體大小加上即可
靜態變量是存放在全軍區域的不計算在內
繼承:子本身+父類大小就是=子類大小
虛繼承:也要執行內存對齊的方式,繼承所加的虛繼承指針要加上4,如果父類或者子類中有double子類的大小就加8,並且出現後者子類中有char或者int的就對齊的方式
class I{double a;}//大小爲8
class J:public virtual I{char c[4];};//大小爲16,但是如果charc[4]改成char c[5]就變成了24了
虛函數:虛函數和虛繼承一樣,一般加4,本身有double+8.(虛函數的個數不管,多少都是照此辦理,並且虛函數的位置也不管,都一樣)(指針),繼承還得算上父類的大小,都得算,有兩個就都加,而且採用對齊
其實虛函數和虛繼承都是多了個指針而已,但都講求內存對齊,其中虛函數是放在那裏都一樣,但是虛繼承放在子類和父類就不一樣了,放在父類還能補缺
虛函數繼承,上述綜合體(實繼承了有虛函數的類,可以當成沒有)
P49,問題2,關於預處理的程序
#include <iostream>
using namespace std;
#define FIND(struc,e)(size_t)&(((struc *)0)->e)
struct student
{
int a;
char b[20];
double ccc;
};
void main()
{
intm=FIND(student,ccc);
cout<<m;
}
先分析下上述程序,其中奇怪的地方有兩三處,從main()入手:第一,find中的元素兩個都不是變量,其實這就是預處理的作用,替換,而不會管你是否有語法錯誤
第二,defin中的(struc )* 0表示什麼意思,其實這就是將常數0轉化成struc的所指向的地址且爲0,&(((struc *)0)->e)表示取結構體中e的地址,首地址爲0,取得e地址就是其偏移地址,
第三,size_t是一種數據類型,和機器的位數長一樣,在32位系統中等於unsigned int
P50
#defineyear_abc (unsigned long)(60*60*24*365)
收到的要點有兩個:第一個書也有錯誤,根據自己心裏來,第二,宏的用處不少
const與#define的異同:
都可以定義不可改變的數,但是const需要經過編譯需要經過安全檢查,有數據類型,而且佔用內存空間,並且可以調試,但是#define這些都沒有,所以他更簡單
P52
sizeof:1指針和數組(本質是指針)不一樣的地方就在於sizeof
2\n在字符串中算一位
3指針的大小是定值,不受指針類型的影響
#pragmapack(1)與#pragma pack()前後包夾可以防止內存對齊,
const
1)指針本身是常量不可變
(char*) const pContent;
const (char*) pContent;
const (char*) pContent;
(2)指針所指向的內容是常量不可變
const (char) *pContent;
(char) const *pContent;
(char) const *pContent;
a. const成員函數不被允許修改它所在對象的任何一個數據成員。
b. const成員函數能夠訪問對象的const成員,而其他成員函數不可以。
但是mutable 修飾除外(mutable int a;)
常函數的意義:標記函數爲只讀函數防修改,增強可讀性
P57 float 大小爲4(拜託我今天才知道)
sizeof求的是內存大小(指針有指針的大小,數組有數組的大小(length*單個大小))
strlen求的是字符串的大小(必須以\0結尾),char 的數組還能計算出來,int的一定會報錯,
strlent(*ss)指的是第一個字符的大小
P58
sizeof(string)的大小爲4
P62 其中例題8的答案很奇怪,我認爲是A,B
P63 內聯函數(inline或者是類的函數(把代碼直接寫到函數出現的地方,不需要經過壓彈操作,能夠提高效率,和宏的單獨代替不同,編譯是否進過檢測的問題(2),)
第七章 指針和引用
P65
引用不可爲空,但是指針可以,所以指針要時刻檢測其是否爲空(合法性測試)
指針是變量,課重新複製,但是引用指向的地址無法改變,但內容可變
引用及長指針使用的特別注意事項
Int&rev=iv (如果不在初始化時刻賦值,則錯誤,這句話表示rev爲iv的別名
常指針初始化時候必須賦值,比如const double maxWage=10.0;
給某個地址賦值爲0(
long*p;
p=(long*)0x123456789;
*p=0)
或者
*((long *)0x123456789)=0
上述這種做法相當危險,不管是這個地址的內存是否被使用,都可能會導致運行問題,程序會崩潰
P68
用指針作爲參數申請內存必須用申請的內存地址作爲函數返回值
注意如果是用數組應付上述情況就錯了,因爲數組內存會隨時收回堆棧裏面的數值,用靜態變量或者是指針都可以
子類與父類的變量同名時候,各自函數都只調用各自的變量
注意,在聲明函數指針(在主函數內部)爲int max(int,int)
Int (*p)(int,int)=&max
P76 指針數組和數組指針
指針數組就是數組元素爲指針的數組(int *p[5],五個指針)
int *p[3];
int a[3][4];
for(i=0;i<3;i++)
p[i]=a[i];
數組指針就是指向數組的指針,也稱行指針(int (*p)[5])
int(*p)[4];
inta[3][4]={{1,2,4,3},{1,2,4,3},{1,2,4,3}};
p=&a[0];
訪問的第一組的第一個元素應該用(*p)[0]
注意,優先級:()>[]>*
這裏面涉及一個二維數組概念,要釐清
函數指針示例int (*a)(int)
函數指針數組示例 int (*a[10])(int)
注意數組名和其他指針不一樣的地方 (數組名本來就是指針,加上&就是雙指針,這裏的指針指的就是數組,所以加1就是數組整體加一行)
int a[]={1,2,3,4,5}
int*ptr =(int *)(&a+1)
printf(“%d,%d”,*(a+1))
答案是2和5
指針的指針都是加一行,例如
chara[]={“hello”,”the”,”world”};
char**pa=a;
pa++;
cout<<*pa<<endl;
運行結果是the
P81
空指針,即是沒有分配內存空間的的指針,其爲NULL,地址是0x00000000,迷途指針,也就是野指針,即是分配了內存空間,但是內存空間的被刪除,但是指針沒指向0的指針。
使用空指針,最多是程序崩潰,使用野指針,崩潰不可預料
P83
由智能指針的問題,想起來類本身的問題,構造類和析構類就是需要很多的時間,不如數組輕便,這個教訓應該心理有數
New和delete這是一對,如果有異常導致delete沒有執行,那麼系統會自動收回
第八章 循環遞歸與概率
P86
第一次知道字符串匹配除了樸素匹配和KMP或者改進的KMP以外還有遞歸方法,而且這種可以將所有匹配住的情況全部寫下來
適合遞歸的非遞歸版本:遍歷樹是while一直到葉子節點
P90
數組查找匹配中比較難的就是降低比較次數:各自排序後再比較是最好的
這裏必須要複習下數據結構了
冒泡排序
直接插入排序,第一個爲標準,然後大的插後面,小的插前面(記了一次沒記住,把代碼貼在下面)
voidInsertSort(SqList *L)
{
int i,j;
for(i=2;i<=L->length;i++)
{
if (L->r[i]<L->r[i-1]) /* 需將L->r[i]插入有序子表 */
{
L->r[0]=L->r[i]; /* 設置哨兵這裏的作用實際是當L->r[i]被覆蓋了之後將會講L->r[i]能夠插入到正確的位置(最後一個需要挪動的)*/
for(j=i-1;L->r[j]>L->r[0];j--)
L->r[j+1]=L->r[j]; /* 記錄後移 */
L->r[j+1]=L->r[0]; /* 插入到正確位置 */
}
}
}
選擇排序,找最小的放第一個,再找次小的放第二個
Ps:快速排序、希爾排序、堆排序、選擇排序不是穩定的排序算法,而冒泡排序、插入排序、歸併排序和基數排序是穩定的排序算法
選擇排序,按照找最小值,與無序區首部交換的思想則不穩定:
排序前:
排序後:
2,4,4*,3 2,3,4*,4
希爾排序,以步長劃分組進行直接插入排序,變化步長直到步長爲1
increment=increment/3+1; /* 增量序列 */
堆排序,根據序號冒泡唄
歸併排序
快速排序,第一個作爲基準,然後開始比較,各自找大小,跟key替換,來來回回直到i=j,返回這時候的key的位置值,然後以這個變量爲中心分成兩組,分別進行快排,直到low=high
/*對順序表L中的子序列L->r[low..high]作快速排序 */
voidQSort(SqList *L,int low,int high)
{
intpivot;
if(low<high)
{
pivot=Partition(L,low,high); /* 將L->r[low..high]一分爲二,算出樞軸值pivot */
QSort(L,low,pivot-1); /* 對低子表遞歸排序 */
QSort(L,pivot+1,high); /* 對高子表遞歸排序 */
}
}
/*交換順序表L中子表的記錄,使樞軸記錄到位,並返回其所在位置 */
/*此時在它之前(後)的記錄均不大(小)於它。 */
intPartition(SqList *L,int low,int high)
{
int pivotkey;
pivotkey=L->r[low]; /* 用子表的第一個記錄作樞軸記錄 */
while(low<high) /* 從表的兩端交替地向中間掃描 */
{
while(low<high&&L->r[high]>=pivotkey)
high--;
swap(L,low,high); /* 將比樞軸記錄小的記錄交換到低端 */
while(low<high&&L->r[low]<=pivotkey)
low++;
swap(L,low,high); /* 將比樞軸記錄大的記錄交換到高端 */
}
return low; /* 返回樞軸所在位置 */
}
除了上訴的其中算法,在百度的時候還發現以下兩種算法
基數排序法:先用個數排序,再用十位數排序(這就是高位優先策略)
P92螺旋隊列:
這個問題在循環和數組比較典型,之字形和回字形都輸屬於這個問題
解決辦法:先用座標求出在第幾層,每層的第一個數可以根據規律和層數計算出來,然後看清楚增長方向,分爲幾種類型,然後加上尾數即可
P95 概率問題
概率問題出現是由於rand引起,兩種計算,一是由面積之比算概率,一直是由rand擴大縮小求新的rand
第九章 stl
最難的是API太多
其中向量算法等等的都不說了,泛型編程自己也編程過,最新接觸的就是模板,用函數指針把幾個輸入輸出的函數統一到一個函數裏面調用,test(int(*p)(int,int),inta,int b),調用時就可以把符合函數指針的函數名填入進去即可
第十章 面對對象
Struct和class是一樣的,不過是爲了兼容c纔有這個關鍵字的,但是其變量默認是public,struct可以用{}的方式賦值(Aa={'p',7,3.1415926}),但是如果struct中加入了函數,那麼久不能用{}賦值了,第三個不同點是“class”這個關鍵字還用於定義模板參數,就像“typename”。但關鍵字“struct”不用於定義模板參數。很
很牛叉的是struct居然也可以繼承和多態,並且繼承是默認是公有還是私有,完全取決於其是繼承的是struct還是class
類的靜態成員變量作用是統計對象的個數,需要初始化,並且需要再類外初始化,比如類中定義是static int howmanycat 那麼在類外就是 int cat:: howmanycat=0;
類的初始化列表變量順序是根據變量的聲明順序來執行的
Static常量允許在初始化聲明處賦初值(記得常量不允許在初始化聲明處賦初值,靜態變量也不允許)
析構函數是virtual修飾的話,作爲基類將不會被調用,當析構函數爲virtual類型時候,派生類的
在這一個章節出現了一些困擾已久的問題
1 virtual的作用:
class Base
{
public:Base(){}
public:
//virtual
void print(){cout<<"Base";}
};
classDerived:public Base
{
public:Derived(){}
public:
voidprint(){cout<<"Derived";}
};
intmain()
{
Base*point=new Derived();
point->print();
return 0;
}
其中如果base的virtual不加,結果就是base,如果加了就實現了覆蓋爲Derived。然而覆蓋與隱藏雖然從代碼上我能識別出來,覆蓋必須父類與子類函數名與參數完全相同且父類函數有virtual關鍵字修飾,但一直讓我從功能上無法區分
覆蓋就是看不見,隱藏就是通過類名::函數名可以訪問到。如果基類被重寫的函數是虛函數的話就是覆蓋,否則就是隱藏。
加了virtual遇上程序中的情況,子函數實現了覆蓋就能夠收回在先分配內存,不會造成內存泄露,所以在使用類的時候,最好加virtual
只要有函數是虛函數,一般代表其析構函數默認是virtual析構函數
這裏分清楚隱藏和覆蓋(),只是申請自己初始化自己的時候各用各自的
析構函數可以是內聯函數
單個參數的構造函數,如果不添加 explicit關鍵字會定義一個隱含類型轉換(從參數轉換成自己),添加了exlicit會消除這種隱含轉換
是否需要拷貝構造函數(凡是需要統一分配系統資源的用戶定義類型都需要一個拷貝構造函數),拷貝構造函數的格式爲:類名(const 類名& 對象名);//拷貝構造函數的原型,參數是常量對象的引用。由於拷貝構造函數的目的是成員複製,不應修改原對象,所以建議使用const關鍵字。
String構造函數分配內存空間時應該多分配一位,這樣可以加入\0
空字符指針判斷必須要根深蒂固
重載是同一個類,不同的函數參數,多態是不同類,同樣的參數
友元函數必須要在類裏面申明,在外面實現函數體 friend +一般函數聲明
第十一章 繼承和接口
如果有爺父子三代繼承,調用函數由上往下調用,虛函數是被覆蓋,只有本類調用時候是調用本類的那個虛函數內部程序,其他情況都是由子決定,子沒有看父
如果調用函數中出現兩個父類的函數同名,調用方法c.A::foo()
當類的函數聲明瞭virtual並且沒有函數體(直接函數聲明=0),這樣整個類是不能實例化的(抽象類)
虛指針:虛函數的的實現細節,每個帶有虛函數的類都有一個指向該類虛函數表的的指針
構造函數設置爲私有的時候,類的對象不能實例化,這時可以通過調用內部的靜態函數來初始化,這樣就控制了入口
Com口的知識好像不重要
第十二章
printf("%f",5);由int轉f或者d就越界了(注意如果用內心強制類型轉換就不會有這個問題)
printf(“%d”,5.1)大數
定義結構體位制:不能超過32,不然就越界了(位段成員的類型僅能夠爲unsigned或者int
),如
Struct{int x:1;
int y:2;
int z:33}
P148
四種基本的轉換:數制轉換、動態轉換,const轉換,reinterpret轉換
P149
聯合體是共享內存,相互覆蓋
P150
注意指針題目 int *pa=BULL;int pb=pa+15,求pb的值,答案是60,因爲pa是int*類型的指針所以加上15也強制轉換成這個類型的,所以就是15*4=60
嵌入式中,中斷裏面不允許傳參和返回值,並且少用printf和浮點運算
P151
Volatile是用來避免被編譯器優化的標誌
Const能夠讓代碼寫出更少的垃圾,讓代碼更緊湊,代表只讀
中斷指針是volatile的
P154
合法指針指向的內容也可能爲NULL,驗證方法爲strlen(指針)==0或者是sizeof(指針)==4來驗證
其中需要說明的是malloc(0)是有分配空間的(編譯器對malloc(N)都有預留),不過如果使用free就會報錯,而且malloc(0)得出的指針是合法指針
P156
用共用體能夠檢測機器到底是大端模式還是小端模式
靜態變量只能被初始化一次
比如
fun(inta)
{ int b=0;
static int c=3;
b++;
c++;
return(a+b+c);}
main()
{int i,a=5;
for(i=0;i<3;i++)
printf(" %d %d ",i,fun(a));
printf("\n"); }
中的static int c=3;只會在開始的時候執行一次
第十三章 數據結構基礎
單鏈表,創建插入 刪除(注意是否是頭結點) 改動,排序(冒泡)
其中以創建爲最難,其次就是改動(特別是逆置),創建中先聲明頭結點head,然後每個點s先申請空間,給s內存空間賦值,然後將傳遞值q的下一個指針指向申請內存s,然後讓p=s
其中遵循的原則是,先接後斷(先讓插入的元素和已有的元素扯上關係,之後再拆分原有元素)。
雙鏈表的逆置:(每次只改一個指向,然後讓其不斷的往後走,最後改head)
P1=head,p2=p1->next
While(p2)
{
P3=p2->next;
P2->next=p1;
P1=p2;
P2=p3;
}
Head->next=null;
Head=p1;
Returnhead;
單鏈表求中間結點:用兩個指針,p,q,p=p->next->next,q=q->next,當p達到終點時,q就是中間結點啦,不過這個得先檢測q的next結點是否是null
P167
雙鏈表
創建(跟單鏈表同,先申請地方,給數據,然後再結兩個關係,最後再挪動地盤)
刪除(先判斷是否是頭結點再判斷是否是尾結點,頭結點先把頭的位置讓出來,並讓其pre指空,再free(p1),尾結點的話先把次尾結點指空,然後對尾結點free)
插入(按照大小插入)
除去插在頭上的特殊情況,其他都一樣
循環鏈表
建立(先寫頭結點,之後申請空間,前驅結點與當前結點相互指向)
刪除(改前驅指向,然後free,最後過渡到下一個刪除)
隊列(入隊和出隊,除了單鏈表的數據結構外,加頭尾兩個指針的數據結構,單鏈表的指針由頭指向尾)
入隊,申請空間,判斷是否爲空,改原來隊尾的指針,然後改隊尾HQ->rear=s
出隊,判斷是否爲空,取數,判斷是否爲1,改指針,釋放空間(本來每次釋放空間之後都要令指針爲0的)
棧(入棧和出棧,除了單鏈表結構,還有棧頂和棧底兩個指針,和隊列不同的地方是出去位置都是同一個,並且單鏈表的指向是由頂指向底,我的想法和書上不一樣,書上太死板了,刪除時候費功夫)(記住,系統函數的嵌套是用堆棧完成,但是函數遞歸層數過多,x86的堆棧大小爲1MB堆棧會造成堆棧溢出,相當於平均每個函數用100byte,只能用來保存10000個函數信息)
入棧,申請空間,判斷是否爲空(爲空就兩個指針都指向s),改原來隊尾的指針,然後改棧頂HQ->rear=s
出棧,判斷是否爲空(判斷棧頂或者棧頂爲NULL),取數,判斷是否爲1(判斷棧頂和棧底是否相等),改指針,釋放空間(本來每次釋放空間之後都要令指針爲0的)
聯想知識:查過多遍,都不沒記住,x86是大端模式,查看數據很順眼的這種,高位存低位的數據,低位存高位的數據
堆棧的基本常識:調用函數時首先進行參數壓棧,一般壓棧的順序爲由由右到左(從近到遠,反正跟閱讀順序的正反有關,這個關鍵點在編譯器,c調用的話就是如此,s調用就不是了),除了壓棧順序之外,還要考慮生長方向,事實上,window中,堆棧方向都是從上往下生長的(即棧頂地址總是小於等於棧的基地址,記住那個圖)
網上摘抄了一段堆和棧的
堆和棧的區別
一、預備知識—程序的內存分配
一個由c/C++編譯的程序佔用的內存分爲以下幾個部分
1、棧區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。(1MB)
2、堆區(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表,呵呵。(虛擬內存大小)
3、全局區(靜態區)(static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。 - 程序結束後有系統釋放
4、文字常量區—常量字符串就是放在這裏的。 程序結束後由系統釋放
5、程序代碼區—存放函數體的二進制代碼。
二、例子程序
這是一個前輩寫的,非常詳細
//main.cpp
int a = 0; 全局初始化區
char *p1; 全局未初始化區
main()
{
int b; 棧
char s[] = "abc"; 棧 (s變量在棧上,指向應該在數據區)
char *p2; 棧
char *p3 = "123456"; 123456\0在常量區,p3在棧上。
static int c =0; 全局(靜態)初始化區
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得來得10和20字節的區域就在堆區。
strcpy(p1, "123456"); 123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。
}
堆(由上面程序總結出來,malloc申請出來的就是在堆中)
裏面扯出來東西很多,設計函數調用方式對堆棧的壓入順序的影響,已經放到前面
樹
突然忘記了各種遍歷的具體是怎麼回事:前中後都是根據根節點的位置 來定的(相互推算的時候必須不能少中序遍歷)
創建,不難,只不過根據大小看是創建左子樹還是友子樹
插入,判斷是否其要插入的左子樹右子樹是否爲空
刪除,刪除葉子節點不難,難的是不是葉子節點,必須要遍歷刪除其左子樹和右子樹纔行
查找,二分查找看來是最簡單的(排序後)
這個其實和字符串很有關係
排序(在上面已經講得很詳細)
幾個典型的數據結構問題
大數據
限制時間複雜度和空間複雜度情況
留着後面一起解決?
求素數問題(用篩選法)
第十四章 字符串
整數轉化成字符串問題:(1)itoa,(number,string,10),其中string是申請了空間的char*或者是數組名,(2)可以通過+’0’,然後再逆序就可以(我的想法是先複製一個數統計位數,然後直接轉)
字符串轉化爲整數:(1) int atoi(constchar *nptr)(2)取出每個字母減去‘0’之後,然後再乘以10,直到末尾
Strcpy不用庫函數
char * strcpy(char * strDest,constchar * strSrc)
{
if ((strDest==NULL)||(strSrc==NULL))//[1]
throw "Invalid argument(s)";//[2]
char *strDestCopy=strDest; //[3]
while ((*strDest++=*strSrc++)!='\0');//[4]
*strDest=’\0’;(字符數組最後一位必須加上‘\0’)
returnstrDestCopy;
}
malloc注意:當內存不足時,函數未能成功分配存儲空間,返回爲NULL,這也就是各個函數要檢查地址是否爲NULL的原因
free省了
還剩下幾個函數
memset, void *memset(void *s, char ch, size_t n)
memcpy void *memcpy(void *dest, const void *src, size_t n)
發現一個問題,在main()函數中,數組申明在前面的數組地址反而在後面,地址是倒過去用的
數組初始化與數組越界,過大的字符串寫到沒申請空間地址上,會出現數組越界的問題
Int n=7,a[n];是不可以的,因爲數位裏面必須有常量
字符串問題
字符串匹配
樸素匹配
改進KMP
出現次數最多最長子串統計:
所有字符串放到向量裏面去,從長到短,然後取出來根據長度一個個比較compare函數,後面比前面次數多才
正序查找 num1=find(str)
逆序查找num2=find(str)
第十五章設計模式
第十六章 操作系統
1、什麼是進程(Process)和線程(Thread)?有何區別?
進程是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。一個線程可以創建和撤銷另一個線程,同一個進程中的多個線程之間可以併發執行。
進程與應用程序的區別在於應用程序作爲一個靜態文件存儲在計算機系統的硬盤等存儲空間中,而進程則是處於動態條件下由操作系統維護的系統資源管理實體。
2、Windows下的內存是如何管理的?
Windows提供了3種方法來進行內存管理:虛擬內存,最適合用來管理大型對象或者結構數組;內存映射文件,最適合用來管理大型數據流(通常來自文件)以及在單個計算機上運行多個進程之間共享數據;內存堆棧,最適合用來管理大量的小對象。
Windows操縱內存可以分兩個層面:物理內存和虛擬內存。
其中物理內存由系統管理,不允許應用程序直接訪問,應用程序可見的只有一個2G地址空間,而內存分配是通過堆進行的。對於每個進程都有自己的默認堆,當一個堆創建後,就通過虛擬內存操作保留了相應大小的地址塊(不佔有實際的內存,系統消耗很小)。當在堆上分配一塊內存時,系統在堆的地址表裏找到一個空閒塊(如果找不到,且堆創建屬性是可擴充的,則擴充堆大小),爲這個空閒塊所包含的所有內存頁提交物理對象(在物理內存上或硬盤的交換文件上),這時就可以訪問這部分地址。提交時,系統將對所有進程的內存統一調配,如果物理內存不夠,系統試圖把一部分進程暫時不訪問的頁放入交換文件,以騰出部分物理內存。釋放內存時,只在堆中將所在的頁解除提交(相應的物理對象被解除),繼續保留地址空間。
如果要知道某個地址是否被佔用/可不可以訪問,只要查詢此地址的虛擬內存狀態即可。如果是提交,則可以訪問。如果僅僅保留,或沒保留,則產生一個軟件異常。此外,有些內存頁可以設置各種屬性。如果是隻讀,向內存寫也會產生軟件異常。
3、Windows消息調度機制是?
A)指令隊列;B)指令堆棧;C)消息隊列;D)消息堆棧
答案:C
處理消息隊列的順序。首先Windows絕對不是按隊列先進先出的次序來處理的,而是有一定優先級的。優先級通過消息隊列的狀態標誌來實現的。首先,最高優先級的是別的線程發過來的消息(通過sendmessage);其次,處理登記消息隊列消息;再次處理QS_QUIT標誌,處理虛擬輸入隊列,處理wm_paint;最後是wm_timer。
4、描述實時系統的基本特性
在特定時間內完成特定的任務,實時性與可靠性。
所謂“實時操作系統”,實際上是指操作系統工作時,其各種資源可以根據需要隨時進行動態分配。由於各種資源可以進行動態分配,因此,其處理事務的能力較強、速度較快。
5、中斷和輪詢的特點
對I/O設備的程序輪詢的方式,是早期的計算機系統對I/O設備的一種管理方式。它定時對各種設備輪流詢問一遍有無處理要求。輪流詢問之後,有要求的,則加以處理。在處理I/O設備的要求之後,處理機返回繼續工作。儘管輪詢需要時間,但輪詢要比I/O設備的速度要快得多,所以一般不會發生不能及時處理的問題。當然,再快的處理機,能處理的輸入輸出設備的數量也是有一定限度的。而且,程序輪詢畢竟佔據了CPU相當一部分處理時間,因此,程序輪詢是一種效率較低的方式,在現代計算機系統中已很少應用。
程序中斷通常簡稱中斷,是指CPU在正常運行程序的過程中,由於預先安排或發生了各種隨機的內部或外部事件,使CPU中斷正在運行的程序,而轉到爲響應的服務程序去處理。
輪詢——效率低,等待時間很長,CPU利用率不高。
中斷——容易遺漏一些問題,CPU利用率高。
6、什麼是臨界區?如何解決衝突?
每個進程中訪問臨界資源的那段程序稱爲臨界區,每次只准許一個進程進入臨界區,進入後不允許其他進程進入。
(1)如果有若干進程要求進入空閒的臨界區,一次僅允許一個進程進入;
(2)任何時候,處於臨界區內的進程不可多於一個。如已有進程進入自己的臨界區,則其它所有試圖進入臨界區的進程必須等待;
(3)進入臨界區的進程要在有限時間內退出,以便其它進程能及時進入自己的臨界區;
(4)如果進程不能進入自己的臨界區,則應讓出CPU,避免進程出現“忙等”現象。
7、說說分段和分頁
頁是信息的物理單位,分頁是爲實現離散分配方式,以消減內存的外零頭,提高內存的利用率;或者說,分頁僅僅是由於系統管理的需要,而不是用戶的需要。
段是信息的邏輯單位,它含有一組其意義相對完整的信息。分段的目的是爲了能更好的滿足用戶的需要。
頁的大小固定且由系統確定,把邏輯地址劃分爲頁號和頁內地址兩部分,是由機器硬件實現的,因而一個系統只能有一種大小的頁面。段的長度卻不固定,決定於用戶所編寫的程序,通常由編輯程序在對源程序進行編輯時,根據信息的性質來劃分。
分頁的作業地址空間是一維的,即單一的線性空間,程序員只須利用一個記憶符,即可表示一地址。分段的作業地址空間是二維的,程序員在標識一個地址時,既需給出段名,又需給出段內地址。
8、說出你所知道的保持進程同步的方法?
進程間同步的主要方法有原子操作、信號量機制、自旋鎖、管程、會合、分佈式系統等。
9、Linux中常用到的命令
顯示文件目錄命令ls 如ls
改變當前目錄命令cd 如cd /home
建立子目錄mkdir 如mkdir xiong
刪除子目錄命令rmdir 如rmdir /mnt/cdrom
刪除文件命令rm 如rm /ucdos.bat
文件複製命令cp 如cp /ucdos /fox
獲取幫助信息命令man 如man ls
顯示文件的內容less 如less mwm.lx
重定向與管道type 如type readme>>direct,將文件readme的內容追加到文direct中
10、Linux文件屬性有哪些?(共十位)
-rw-r--r--那個是權限符號,總共是- --- --- ---這幾個位。
第一個短橫處是文件類型識別符:-表示普通文件;c表示字符設備(character);b表示塊設備(block);d表示目錄(directory);l表示鏈接文件(link);後面第一個三個連續的短橫是用戶權限位(User),第二個三個連續短橫是組權限位(Group),第三個三個連續短橫是其他權限位(Other)。每個權限位有三個權限,r(讀權限),w(寫權限),x(執行權限)。如果每個權限位都有權限存在,那麼滿權限的情況就是:-rwxrwxrwx;權限爲空的情況就是- --- --- ---。
權限的設定可以用chmod命令,其格式位:chmod ugoa+/-/=rwxfilename/directory。例如:
一個文件aaa具有完全空的權限- --- --- ---。
chmod u+rw aaa(給用戶權限位設置讀寫權限,其權限表示爲:- rw---- ---)
chmod g+r aaa(給組設置權限爲可讀,其權限表示爲:- ---r-- ---)
chmod ugo+rw aaa(給用戶,組,其它用戶或組設置權限爲讀寫,權限表示爲:- rw-rw- rw-)
如果aaa具有滿權限- rwx rwx rwx。
chmod u-x aaa(去掉用戶可執行權限,權限表示爲:- rw-rwx rwx)
如果要給aaa賦予制定權限- rwx r-x r-x,命令爲:
chmod u=rwx,go=rx aaa
11、makefile文件的作用是什麼?
一個工程中的源文件不計其數,其按類型、功能、模塊分別放在若干個目錄中。makefile定義了一系列的規則來指定哪些文件需要先編譯,哪些文件需要後編譯,哪些文件需要重新編譯,甚至於進行更復雜的功能操作。因爲makefile就像一個Shell腳本一樣,其中也可以執行操作系統的命令。makefile帶來的好處就是——“自動化編譯”。一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大地提高了軟件開發的效率。make是一個命令工具,是一個解釋makefile中指令的命令工具。一般來說,大多數的IDE都有這個命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可見,makefile都成爲了一種在工程方面的編譯方法。
12、簡術OSI的物理層Layer1,鏈路層Layer2,網絡層Layer3的任務。
網絡層:通過路由選擇算法,爲報文或分組通過通信子網選擇最適當的路徑。
鏈路層:通過各種控制協議,將有差錯的物理信道變爲無差錯的、能可靠傳輸數據幀的數據鏈路。
物理層:利用傳輸介質爲數據鏈路層提供物理連接,實現比特流的透明傳輸。
13、什麼是中斷?中斷時CPU做什麼工作?
中斷是指在計算機執行期間,系統內發生任何非尋常的或非預期的急需處理事件,使得CPU暫時中斷當前正在執行的程序而轉去執行相應的事件處理程序。待處理完畢後又返回原來被中斷處繼續執行或調度新的進程執行的過程。
14、你知道操作系統的內容分爲幾塊嗎?什麼叫做虛擬內存?他和主存的關係如何?內存管理屬於操作系統的內容嗎?
操作系統的主要組成部分:進程和線程的管理,存儲管理,設備管理,文件管理。虛擬內存是一些系統頁文件,存放在磁盤上,每個系統頁文件大小爲4K,物理內存也被分頁,每個頁大小也爲4K,這樣虛擬頁文件和物理內存頁就可以對應,實際上虛擬內存就是用於物理內存的臨時存放的磁盤空間。頁文件就是內存頁,物理內存中每頁叫物理頁,磁盤上的頁文件叫虛擬頁,物理頁+虛擬頁就是系統所有使用的頁文件的總和。
15、線程是否具有相同的堆棧?dll是否有獨立的堆棧?
每個線程有自己的堆棧。
dll是否有獨立的堆棧?這個問題不好回答,或者說這個問題本身是否有問題。因爲dll中的代碼是被某些線程所執行,只有線程擁有堆棧。如果dll中的代碼是exe中的線程所調用,那麼這個時候是不是說這個dll沒有獨立的堆棧?如果dll中的代碼是由dll自己創建的線程所執行,那麼是不是說dll有獨立的堆棧?
以上講的是堆棧,如果對於堆來說,每個dll有自己的堆,所以如果是從dll中動態分配的內存,最好是從dll中刪除;如果你從dll中分配內存,然後在exe中,或者另外一個dll中刪除,很有可能導致程序崩潰。
16、什麼是緩衝區溢出?有什麼危害?其原因是什麼?
緩衝區溢出是指當計算機向緩衝區內填充數據時超過了緩衝區本身的容量,溢出的數據覆蓋在合法數據上。
危害:在當前網絡與分佈式系統安全中,被廣泛利用的50%以上都是緩衝區溢出,其中最著名的例子是1988年利用fingerd漏洞的蠕蟲。而緩衝區溢出中,最爲危險的是堆棧溢出,因爲入侵者可以利用堆棧溢出,在函數返回時改變返回程序的地址,讓其跳轉到任意地址,帶來的危害一種是程序崩潰導致拒絕服務,另外一種就是跳轉並且執行一段惡意代碼,比如得到shell,然後爲所欲爲。通過往程序的緩衝區寫超出其長度的內容,造成緩衝區的溢出,從而破壞程序的堆棧,使程序轉而執行其它指令,以達到攻擊的目的。
造成緩衝區溢出的主原因是程序中沒有仔細檢查用戶輸入的參數。
17、什麼是死鎖?其條件是什麼?怎樣避免死鎖?
死鎖的概念:在兩個或多個併發進程中,如果每個進程持有某種資源而又都等待別的進程釋放它或它們現在保持着的資源,在未改變這種狀態之前都不能向前推進,稱這一組進程產生了死鎖。通俗地講,就是兩個或多個進程被無限期地阻塞、相互等待的一種狀態。
死鎖產生的原因主要是:?系統資源不足;?進程推進順序非法。
產生死鎖的必要條件:
(1)互斥(mutualexclusion),一個資源每次只能被一個進程使用;
(2)不可搶佔(nopreemption),進程已獲得的資源,在未使用完之前,不能強行剝奪;
(3)佔有並等待(hold andwait),一個進程因請求資源而阻塞時,對已獲得的資源保持不放;
(4)環形等待(circularwait),若干進程之間形成一種首尾相接的循環等待資源關係。
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖。
死鎖的解除與預防:理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配算法,避免進程永久佔據系統資源。此外,也要防止進程在處於等待狀態的情況下佔用資源。因此,對資源的分配要給予合理的規劃。
死鎖的處理策略:鴕鳥策略、預防策略、避免策略、檢測與恢復策略。
第十七章 數據庫與SQL語言
先參見打印內容(相關word)
SQL常用語句一覽
sp_password null,'新密碼','sa'
修改數據庫密碼
(1)數據記錄篩選:
sql="select * from
數據表where
字段名=字段值orderby
字段名 [desc] "
sql="select * from 數據表where
字段名 like '%字段值%'orderby
字段名 [desc]"
sql="select top10 * from 數據表where
字段名 orderby
字段名[desc]"
sql="select * from 數據表 where
字段名in('值1','值2','值3')"
sql="select * from 數據表 where
字段名between
值1 and 值2"
(2)更新數據記錄:
sql="update 數據表 set
字段名=字段值where
條件表達式"
sql="update 數據表 set
字段1=值1,字段2=值2……字段n=值nwhere
條件表達式"
(3)刪除數據記錄:
sql="delete from 數據表 where
條件表達式"
sql="delete from 數據表 "(將數據表所有記錄刪除)
(4)添加數據記錄:
sql="insert into 數據表(字段1,字段2,字段3…)values(值1,值2,值3…)"
sql="insert into 目標數據表 select * from
源數據表"(把源數據表的記錄添加到目標數據表)
(5)數據記錄統計函數:
AVG(字段名)得出一個表格欄平均值
COUNT(*|字段名)對數據行數的統計或對某一欄有值的數據行數統計
MAX(字段名)取得一個表格欄最大的值
MIN(字段名)取得一個表格欄最小的值
SUM(字段名)把數據欄的值相加
引用以上函數的方法:
sql="selectsum(字段名)as別名from數據表where條件表達式"
setrs=conn.excute(sql)
用rs("別名")獲取統的計值,其它函數運用同上。
(5)數據表的建立和刪除:
CREATETABLE數據表名稱(字段1類型1(長度),字段2類型2(長度)……)
例:CREATETABLEtab01 (namevarchar(50), datetimedefaultnow ())
DROPTABLE數據表名稱(永久性刪除一個數據表)
視圖
視圖是虛表,是從一個或幾個基本表(或視圖)中導出的表,在系統的數據字典中僅存放了視圖的定義,不存放視圖對應的數據。
視圖是原始數據庫數據的一種變換,是查看錶中數據的另外一種方式。可以將視圖看成是一個移動的窗口,通過它可以看到感興趣的數據。 視圖是從一個或多個實際表中獲得的,這些表的數據存放在數據庫中。那些用於產生視圖的表叫做該視圖的基表。
四個範式
第一, 不可分解
第二, 依賴性
第三, 非主屬性都不傳遞依賴
第四, 多值依賴
BC範式,第一 and 第三
存儲過程(一些列SQL語句的集合)和函數(已定義的方法)
事務
ACID
ACID,指數據庫事務正確執行的四個基本要素的縮寫。包含:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。一個支持事務(Transaction)的數據庫系統,必需要具有這四種特性,否則在事務過程(Transaction processing)當中無法保證數據的正確性,交易過程極可能達不到交易方的要求。
原子性
整個事務中的所有操作,要麼全部完成,要麼全部不完成,不可能停滯在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
一致性
在事務開始之前和事務結束以後,數據庫的完整性約束沒有被破壞。
隔離性
隔離狀態執行事務,使它們好像是系統在給定時間內執行的唯一操作。如果有兩個事務,運行在相同的時間內,執行相同的功能,事務的隔離性將確保每一事務在系統中認爲只有該事務在使用系統。這種屬性有時稱爲串行化,爲了防止事務操作間的混淆,必須串行化或序列化請求,使得在同一時間僅有一個請求用於同一數據。
持久性
在事務完成以後,該事務所對數據庫所作的更改便持久的保存在數據庫之中,並不會被回滾。
由於一項操作通常會包含許多子操作,而這些子操作可能會因爲硬件的損壞或其他因素產生問題,要正確實現ACID並不容易。ACID建議數據庫將所有需要更新 以及修改的資料一次操作完畢,但實際上並不可行。
目前主要有兩種方式實現ACID:第一種是Write ahead logging,也就是日誌式的方式。第二種是Shadow paging。
遊標的作用 用於定位結果集的行
觸發,事前觸發,事後觸發,語句級觸發,行級觸發(所影響的每一行觸發一次)
SQL注入式攻擊
相當大一部分程序員在編寫代碼的時候,沒有對用戶輸入數據的合法性進行判斷,使應用程序存在安全隱患。用戶可以提交一段數據庫查詢代碼,根據程序返回的結果,獲得某些他想得知的數據,這就是所謂的SQL Injection,即SQL注入。
SQL語言
????
W3C 網站有SQL的教程,很全面
http://www.w3school.com.cn/sql/index.asp
官方網站,自己一節一節學吧,把關鍵字和函數的意思弄懂了,就好搞了
P258及P259有詳細的筆記
P266 SQL程序
第十八章:計算機網絡和分佈式系統
Osi七層和TCP、IP五層模型對比
TCP與UDP區別
TCP三次握手(啓動鏈接)(一個syn,一個回覆syn+ack,再回復)及4次揮手(關閉鏈接)(特別兩個fin信號,兩個回覆)
套接字細節
網絡攻擊
入侵檢測與防火牆
蠕蟲病毒(icmp目的地無法抵達的包)
阻塞會出現丟包的情況
端口說明
21 GTP
23telnet
25 SMTP
53 dns服務器,用於域名解析
80 http
109/110,pop2,pop3
135 遠程過程調用
443 網頁瀏覽
554 實時瀏覽
網絡子網問題(子網掩碼、可用地址)
IP後面帶/30 /29 /27等是什麼意思?
子網掩碼的意思 子網掩碼是4個8位的2進制數字組成, 30表示前30位數字爲1,即11111111.11111111.11111111.11111100,換成十進制就是255.255.255.252
主機號在掩碼內全是0代表的是多播地址,全是是1代表的是廣播地址
29表示11111111.11111111.11111111.11111000,十進制就是255.255.255.248 27表示11111111.11111111.11111111.11100000,十進制就是255.255.255.224
各種協議命令Ping
ICMP
智力題
未完待續。。。