牛頓迭代法(Newton's method)又稱(chēng)為牛頓-拉夫遜(拉弗森)方法(Newton-Raphson method),它是牛頓在17世紀(jì)提出的一種在實(shí)數(shù)域和復(fù)數(shù)域上近似求解方程的方法。
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),洛隆企業(yè)網(wǎng)站建設(shè),洛隆品牌網(wǎng)站建設(shè),網(wǎng)站定制,洛隆網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷(xiāo),網(wǎng)絡(luò)優(yōu)化,洛隆網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M(mǎn)足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專(zhuān)業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶(hù)成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
中文名
牛頓迭代法
外文名
Newton's method
別名
牛頓-拉夫遜(拉弗森)方法
提出時(shí)間
17世紀(jì)
快速
導(dǎo)航
牛頓迭代公式
其他迭代算法
C語(yǔ)言代碼
C++代碼
matlab代碼
Python代碼
Java代碼
JavaScript代碼
Fortran代碼
產(chǎn)生背景
多數(shù)方程不存在求根公式,因此求精確根非常困難,甚至不可解,從而尋找方程的近似根就顯得特別重要。方法使用函數(shù) 的泰勒級(jí)數(shù)的前面幾項(xiàng)來(lái)尋找方程 的根。牛頓迭代法是求方程根的重要方法之一,其最大優(yōu)點(diǎn)是在方程 的單根附近具有平方收斂,而且該法還可以用來(lái)求方程的重根、復(fù)根,此時(shí)線性收斂,但是可通過(guò)一些方法變成超線性收斂。另外該方法廣泛用于計(jì)算機(jī)編程中。
牛頓迭代公式
設(shè) 是 的根,選取 作為 的初始近似值,過(guò)點(diǎn) 做曲線 的切線 , ,則 與 軸交點(diǎn)的橫坐標(biāo) ,稱(chēng) 為 的一次近似值。過(guò)點(diǎn) 做曲線 的切線,并求該切線與x軸交點(diǎn)的橫坐標(biāo) ,稱(chēng) 為r的二次近似值。重復(fù)以上過(guò)程,得 的近似值序列,其中, 稱(chēng)為 的 次近似值,上式稱(chēng)為牛頓迭代公式。
用牛頓迭代法解非線性方程,是把非線性方程 線性化的一種近似方法。把 在點(diǎn) 的某鄰域內(nèi)展開(kāi)成泰勒級(jí)數(shù) ,取其線性部分(即泰勒展開(kāi)的前兩項(xiàng)),并令其等于0,即 ,以此作為非線性方程 的近似方程,若 ,則其解為 , 這樣,得到牛頓迭代法的一個(gè)迭代關(guān)系式: 。
已經(jīng)證明,如果是連續(xù)的,并且待求的零點(diǎn)是孤立的,那么在零點(diǎn)周?chē)嬖谝粋€(gè)區(qū)域,只要初始值位于這個(gè)鄰近區(qū)域內(nèi),那么牛頓法必定收斂。 并且,如果不為0, 那么牛頓法將具有平方收斂的性能. 粗略的說(shuō),這意味著每迭代一次,牛頓法結(jié)果的有效數(shù)字將增加一倍。
迭代法也稱(chēng)輾轉(zhuǎn)法,是一種不斷用變量的舊值遞推新值的過(guò)程,跟迭代法相對(duì)應(yīng)的是直接法(或者稱(chēng)為一次解法),即一次性解決問(wèn)題。迭代算法是用計(jì)算機(jī)解決問(wèn)題的一種基本方法。它利用計(jì)算機(jī)運(yùn)算速度快、適合做重復(fù)性操作的特點(diǎn),讓計(jì)算機(jī)對(duì)一組指令(或一定步驟)重復(fù)執(zhí)行,在每次執(zhí)行這組指令(或這些步驟)時(shí),都從變量的原值推出它的一個(gè)新值。
利用迭代算法解決問(wèn)題,需要做好以下三個(gè)方面的工作:
一、確定迭代變量
在可以用迭代算法解決的問(wèn)題中,至少存在一個(gè)可直接或間接地不斷由舊值遞推出新值的變量,這個(gè)變量就是迭代變量。
二、建立迭代關(guān)系式
所謂迭代關(guān)系式,指如何從變量的前一個(gè)值推出其下一個(gè)值的公式(或關(guān)系)。迭代關(guān)系式的建立是解決迭代問(wèn)題的關(guān)鍵,通常可以使用遞推或倒推的方法來(lái)完成。
三、對(duì)迭代過(guò)程進(jìn)行控制
在什么時(shí)候結(jié)束迭代過(guò)程?這是編寫(xiě)迭代程序必須考慮的問(wèn)題。不能讓迭代過(guò)程無(wú)休止地執(zhí)行下去。迭代過(guò)程的控制通常可分為兩種情況:一種是所需的迭代次數(shù)是個(gè)確定的值,可以計(jì)算出來(lái);另一種是所需的迭代次數(shù)無(wú)法確定。對(duì)于前一種情況,可以構(gòu)建一個(gè)固定次數(shù)的循環(huán)來(lái)實(shí)現(xiàn)對(duì)迭代過(guò)程的控制;對(duì)于后一種情況,需要進(jìn)一步分析得出可用來(lái)結(jié)束迭代過(guò)程的條件。
其他迭代算法
歐幾里德算法
最經(jīng)典的迭代算法是歐幾里德算法,用于計(jì)算兩個(gè)整數(shù)a,b的最大公約數(shù)。其計(jì)算原理依賴(lài)于下面的定理:
定理:gcd(a,b) = gcd(b,a mod b)
證明:a可以表示成a = kb + r,則r = a mod b。假設(shè)d是a,b的一個(gè)公約數(shù),則有 a%d==0,b%d==0,而r = a - kb,因此r%d==0 ,因此d是(b,a mod b)的公約數(shù)
查看更多
將整個(gè)系統(tǒng)看做這樣一個(gè)物理系統(tǒng):質(zhì)點(diǎn)和橡皮筋的系統(tǒng);橡皮筋有個(gè)自然長(zhǎng)度Length,當(dāng)橡皮筋被拉長(zhǎng)時(shí)產(chǎn)生彈力T;任意2個(gè)質(zhì)點(diǎn)間存在反萬(wàn)有引力G(簡(jiǎn)單的說(shuō)就是質(zhì)量產(chǎn)生斥力,和物理系統(tǒng)相反)。當(dāng)斥力和彈力平衡的時(shí)候,布局就結(jié)束了,算法簡(jiǎn)單描述如下:
設(shè)系統(tǒng)為G(V,E);
for (vi in V) {
vi.x = random ();
vi.y = random ();
}
while (未平衡) {
for (ei(vx, vy) in E) {
Fx += T(ei, vx, vy);
Ty += T(ei, vy, vx);
}
for (vi in V) {
for (vj in V) {
if (i == j) 跳過(guò)
Fi += G (vi, vj);
}
}
for (fi in F) {
vi.x = |fi| * cos(fi.angle);
vi.y = |fi| * sin(fi.angle);
}
}
其中彈力公式T(e, vi, vj)遵循胡克定律:F = Length(e) Length ? K * (Length(e) - Length) : 0; K 為胡克常數(shù),酌情取值
萬(wàn)有引力公式G(vi, vj)遵循牛頓萬(wàn)有引力定律,但方向相反:
F = -G * Mass(vi) * Mass(vj) / (Distance(vi, vj) * Distance(vi, vj)); G 為萬(wàn)有引力常數(shù),酌情取值,Mass(v)為質(zhì)點(diǎn)v的質(zhì)量,可直接去定點(diǎn)的邊數(shù);Distance(vi, vj)為質(zhì)點(diǎn)vi 和vj之間的距離,根據(jù)勾股定理可到。
系統(tǒng)平衡的標(biāo)準(zhǔn):合彈力=合斥力,表現(xiàn)為v.x和v.y不再發(fā)生變化或震動(dòng)
注意:當(dāng)隨機(jī)初始化后,可能產(chǎn)生2個(gè)質(zhì)點(diǎn)重疊的現(xiàn)象,這時(shí)2質(zhì)點(diǎn)間的斥力可用常數(shù)替代,方向隨機(jī)。若質(zhì)點(diǎn)無(wú)質(zhì)量,可使用一個(gè)小常數(shù)替代,如.0005
Matter.js 中基礎(chǔ)的概念
大多數(shù)的物理引擎對(duì)于物理模擬的要素都有著相近的概念,不同的引擎差別在于使用的方式,功能的全面性,模擬的精細(xì)度等層面,下面就先從物理世界的基礎(chǔ)概念講起。
Engine(引擎)和 World(世界)
Matter.Engine?模塊包含了創(chuàng)建和處理引擎的方法,引擎是負(fù)責(zé)管理和更新模擬世界的控制器,引擎可以控制時(shí)間的縮放,可以檢測(cè)所有的碰撞事件,并且拿到所有碰撞的物體對(duì)(pairs)。
在 Matter.js 中任何的物體都需要一個(gè)容身處,而存放這些物體的地方,我們稱(chēng)之為世界,物體必須添加到世界里,然后由引擎運(yùn)行這個(gè)世界。而創(chuàng)建世界需要使用到?Matter.World模塊,該模塊包含了用于創(chuàng)建和操作世界的方法,一個(gè)?Matter.World?相當(dāng)于一個(gè)復(fù)合物體,物體、約束、復(fù)合物體的聚合體,其次世界還有額外的一些屬性,比如重力、邊界。
Render(渲染)
JavaScript
1
2
3
4
5
6
7
8
9
10
// Matter.Render 用法
var engine = Engine.create();
// ... 將物體加入到世界中
var render = Render.create({
element: document.body,
engine: engine,
options: options
});
Engine.run(engine);
Render.run(render);
element?是一個(gè)容器元素,使用時(shí)指定要渲染的節(jié)點(diǎn)
engine?指定為?Matter.Engine?實(shí)例
options?指定一些渲染的參數(shù)
Matter.Render?是將實(shí)例渲染到 Canvas 中的渲染器,控制視圖層的樣式,它的主要作用是用于開(kāi)發(fā)和調(diào)試,默認(rèn)情況下?Matter.Render?將只顯示物體的線框(輪廓),這對(duì)于開(kāi)發(fā)和調(diào)試很有幫助,但如果需要使用到全局實(shí)體渲染則需要將線框模式關(guān)閉?render.options.wireframes = false,另外它同樣也適合制作一些簡(jiǎn)單的游戲,因?yàn)樗艘恍├L圖選項(xiàng)、線框、向量、Sprite 精靈和視窗功能。
DEMO 戳這里
Body(剛體)
物體或者叫剛體,在物理引擎里特指堅(jiān)硬的物體,具有固定的形狀,不能形變。剛體可以用于表示一個(gè)箱子、一個(gè)球或是一塊木頭,每個(gè)物體都有自己的物理屬性,質(zhì)量、速度、摩擦力、角度等,還可以設(shè)置剛體的標(biāo)記。Matter.Bodies?模塊中內(nèi)置了幾種剛體,矩形?Matter.rectangle、多邊形?Matter.polygon、圓形?Matter.circle?、梯形?Matter.trapezoid?等等。
JavaScript
1
2
3
4
5
6
7
// 創(chuàng)建剛體
var rect = Bodies.rectangle(200, 100, 50, 50), // 矩形
circle = Bodies.circle(300, 100, 25), // 圓
polygon = Bodies.polygon(450, 100, 5, 25), // 多邊形
trapezoid = Bodies.trapezoid(590, 100, 50, 50, 3); // 梯形
// 將剛體添加到世界中
World.add(engine.world, [rect, circle, polygon, trapezoid]);
DEMO 戳這里
Composite(復(fù)合體)
由剛體和復(fù)合材料通過(guò)約束組合在一起的就叫做復(fù)合體。復(fù)合體對(duì)外當(dāng)作一個(gè)剛體,復(fù)合體的物理屬性是通過(guò)所包含的剛體的屬性綜合計(jì)算出來(lái)的。Matter.Composite?模塊包含用于創(chuàng)建和處理復(fù)合體的方法,另外還有一個(gè)?Matter.Composites?模塊,提供了幾種特別的復(fù)合材料,例如 鏈?Composites.chain、牛頓擺球?Composites.newtonsCradle、軟體?Composites.softBody、汽車(chē)?Composites.car?、堆疊?Composites.stack?等等。
橋梁
JavaScript
1
2
3
4
5
6
7
8
9
10
11
// 使用堆疊創(chuàng)建橋梁
var group = Body.nextGroup(true);
var bridge = Composites.stack(150, 300, 9, 1, 10, 10, function(x, y) {
return Bodies.rectangle(x, y, 50, 20, {
collisionFilter: { // 過(guò)濾碰撞
group: group
}
});
});
// 創(chuàng)建鏈約束
Composites.chain(bridge, 0.5, 0, -0.5, 0, { stiffness: 0.9 });
DEMO 戳這里
布
JavaScript
1
2
3
4
5
6
7
8
9
10
// 軟體
var cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, {
friction: 0.00001, // 摩擦力
collisionFilter: {
group: Body.nextGroup(true)
},
render: {
visible: false
}
});
DEMO 戳這里
牛頓擺球
JavaScript
1
2
// 創(chuàng)建牛頓擺球
var newtonsCradle = Composites.newtonsCradle(300, 320, 5, 25, 150);
DEMO 戳這里
Constraint(約束)
約束可理解為通過(guò)一條線,將剛體 A 和剛體 B 兩個(gè)剛體連接起來(lái),被約束的兩個(gè)剛體由于被連接在了一起,移動(dòng)就相互受到了限制。Matter.Constraint?模塊包含了用于創(chuàng)建和處理約束的方法,這個(gè)約束可以很寬松,也可以很緊繃,還可以定義約束的距離,約束具有彈性,可以用來(lái)當(dāng)作橡皮筋。
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 創(chuàng)建一個(gè)矩形和圓形
var rect = Bodies.rectangle(400, 100, 50, 50, {
isStatic: true
}),
ball = Bodies.circle(400, 400, 50);
World.add(engine.world, [
rect,
ball,
Constraint.create({
bodyA: rect, // 約束剛體 A
pointA : { // 約束點(diǎn) A
x: 0,
y: 0
},
bodyB: ball, // 約束剛體 B
pointB: { // 約束點(diǎn) B
x: 0,
y: -50
},
stiffness: 0.6
})
]);
DEMO 戳這里
MouseConstraint(鼠標(biāo)約束)
如果你想讓剛體與用戶(hù)之間有交互,那就要在鼠標(biāo)和剛體之間建立連接,也就是鼠標(biāo)和剛體間的約束,Matter.MouseConstraint?模塊包含用于創(chuàng)建鼠標(biāo)約束的方法,提供通過(guò)鼠標(biāo)或觸摸(移動(dòng)端時(shí))移動(dòng)剛體的能力,可以設(shè)置什么標(biāo)記的物體才能被鼠標(biāo)操縱,創(chuàng)建鼠標(biāo)約束后,可以捕獲到鼠標(biāo)的各類(lèi)事件。
JavaScript
1
2
3
4
5
// 全局鼠標(biāo)約束
var mouseConstraint = MouseConstraint.create({
element: render.canvas
});
World.add(engine.world, mouseConstraint);
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 設(shè)置某個(gè)標(biāo)記的物體才能被鼠標(biāo)操縱
var categoryBall = 0x0001; // 分類(lèi)
var ball = Matter.Bodies.circle(300, 350, 32, {
density: 0.68, // 密度
restitution: 1, // 彈性
collisionFilter: {
category: categoryBall
}
});
var mouseConstraint = MouseConstraint.create({
element: render.canvas,
collisionFilter: {
mask: categoryBall
}
});
World.add(engine.world, mouseConstraint);
DEMO 戳這里
Vector(向量)
Matter.Vector?模塊包含用于創(chuàng)建和操縱向量的方法,向量是引擎有關(guān)幾何操作行為的基礎(chǔ),修改物體的運(yùn)動(dòng)狀態(tài)基本都是使用向量來(lái)控制,例如賦予物體一個(gè)力,或者設(shè)置物體的速度、旋轉(zhuǎn)角度,并且內(nèi)置了多個(gè)向量的求解函數(shù):向量積、標(biāo)量積、格式化、垂直向量等等。
Events(事件)
Matter.Events?模塊包含了綁定、移除和觸發(fā)對(duì)象的方法。
綁定事件?Matter.Events.on(object, eventNames, callback)
移除事件?Matter.Events.off(object, eventNames, callback)
觸發(fā)事件?Matter.Events.trigger(object, eventNames, event)
Matter.js 中的一些屬性
施加力
Matter.Body.applyForce(body, position, force)?方法可以給剛體施加一個(gè)力,傳入 X 和 Y 軸需要的力度值,通過(guò)這個(gè)方法你可以去模擬踢一個(gè)足球、投一個(gè)籃球的效果。
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
var ball = Bodies.circle(300, 100, 25, {
density: 0.68, // 密度
restitution: 0.8 // 彈性
});
World.add(engine.world, ball);
function addForce() {
var forceMagnitude = 0.02 * ball.mass;
Body.applyForce(ball, ball.position, {
x : (forceMagnitude + Common.random() * forceMagnitude) * Common.choose([1, -1]),
y : -forceMagnitude + Common.random() * -forceMagnitude
});
}
addForce();
DEMO 戳這里
重力
可以設(shè)置 X、Y 軸的重力值,默認(rèn)都為 1,參數(shù)在 0、1、-1 中選擇使用。
JavaScript
1
2
3
4
// 實(shí)現(xiàn)反重力效果
engine.world.gravity.y = -1;
// 無(wú)重力效果
engine.world.gravity.y = 0;
DEMO 戳這里
睡眠狀態(tài)
通過(guò)?enableSleeping: true?開(kāi)啟睡眠模式后,當(dāng)剛體處于不受作用狀態(tài)時(shí),會(huì)進(jìn)入睡眠狀態(tài),這樣可以有效的提高引擎的性能,當(dāng)物體被其他物體碰撞或者對(duì)剛體施加力時(shí),剛體會(huì)被叫醒,引擎會(huì)繼續(xù)對(duì)其進(jìn)行計(jì)算模擬。
JavaScript
1
2
3
4
5
6
7
8
// 開(kāi)啟睡眠狀態(tài)
var engine = Engine.create({
enableSleeping: true
});
// 還可以針對(duì)進(jìn)入睡眠狀態(tài)的剛體進(jìn)行監(jiān)聽(tīng),比如將剛體移出世界
Event.on(ball, "sleepStart", function() {
World.remove(engine.world, ball);
});
DEMO 戳這里
摩擦力
摩擦力在 Matter.js 中分別提供了三種:摩擦力?friction、空氣摩擦力?frictionAir?以及靜止摩擦力?frictionStatic。friction?默認(rèn)值是 0.1,取值范圍在 0 – 1,當(dāng)值為 0 意味著剛體可以摩擦力的無(wú)限滑動(dòng),1 意味著對(duì)剛體施加力后會(huì)立刻停止,frictionAir?默認(rèn)值是 0.01,取值范圍 0 – 1,當(dāng)值為 0 意味著剛體在空間中移動(dòng)時(shí)速度永遠(yuǎn)不會(huì)減慢,值越高時(shí)剛體在空間的移動(dòng)速度越慢,frictionStatic?默認(rèn)值 0.5,當(dāng)值為 0 時(shí)意味著剛體幾乎是靜止的,值越高時(shí)意味著需要移動(dòng)剛體所需的力就越大。
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
// 摩擦力
Bodies.rectangle(300, 70, 40, 40, {
friction: 0.01
})
// 空氣摩擦力
Bodies.rectangle(300, 70, 40, 40, {
frictionAir: 0.05
})
// 靜止摩擦力
Bodies.rectangle(300, 70, 40, 40, {
frictionStatic: 1
})
時(shí)間縮放
可以控制全局的時(shí)間,當(dāng)值為 0 時(shí)為凍結(jié)模擬,值為 0.1 給出慢動(dòng)作效果,值為 1.2 時(shí)給出加速效果。
JavaScript
1
engine.timing.timeScale = 0.1;
這里就簡(jiǎn)單提及到幾個(gè)屬性,當(dāng)然還有更多的屬性比如:視圖(View)、彈性(Restitution)等等,更詳細(xì)的 API 可到官網(wǎng)查看。
Matter.js 調(diào)試
除了前面講?Matter.Render?模塊的時(shí)候提到的線框模式?wireframes?便于調(diào)試外,Matter.Render?模塊其實(shí)還為我們提供了以下幾種方法,便于我們自定義調(diào)試選項(xiàng):
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var render = Render.create({
element: document.body,
engine: engine,
options: {
width: 800,
height: 600,
pixelRatio: 1, // 設(shè)置像素比
background: '#fafafa', // 全局渲染模式時(shí)背景色
wireframeBackground: '#222', // 線框模式時(shí)背景色
hasBounds: false,
enabled: true,
wireframes: true, // 線框模式
showSleeping: true, // 剛體睡眠狀態(tài)
showDebug: false, // Debug 信息
showBroadphase: false, // 粗測(cè)階段
showBounds: false, // 剛體的界限
showVelocity: false, // 移動(dòng)剛體時(shí)速度
showCollisions: false, // 剛體碰撞點(diǎn)
showSeparations: false, // 剛體分離
showAxes: false, // 剛體軸線
showPositions: false, // 剛體位置
showAngleIndicator: false, // 剛體轉(zhuǎn)角指示
showIds: false, // 顯示每個(gè)剛體的 ID
showVertexNumbers: false, // 剛體頂點(diǎn)數(shù)
showConvexHulls: false, // 剛體凸包點(diǎn)
showInternalEdges: false, // 剛體內(nèi)部邊界
showMousePosition: false // 鼠標(biāo)約束線
}
});
另外官方提供了三個(gè)調(diào)試工具,可單獨(dú)使用或一起使用,如下:
工具:
MatterTools.Demo?用于運(yùn)行和測(cè)試 DEMO
MatterTools.Gui?改變引擎的屬性
MatterTools.Inspector?檢查世界
你可以先去【繪學(xué)霸】網(wǎng)站找“游戲特效/unity3D”板塊的【免費(fèi)】視頻教程-【點(diǎn)擊進(jìn)入】完整入門(mén)到精通視頻教程列表: ;tagid=305,306zdhhr-11y17r-239619078
想要系統(tǒng)的學(xué)習(xí)可以考慮報(bào)一個(gè)網(wǎng)絡(luò)直播課,推薦CGWANG的網(wǎng)絡(luò)課。老師講得細(xì),上完還可以回看,還有同類(lèi)型錄播課可以免費(fèi)學(xué)(贈(zèng)送終身VIP)。
自制能力相對(duì)較弱的話,建議還是去好點(diǎn)的培訓(xùn)機(jī)構(gòu),實(shí)力和規(guī)模在國(guó)內(nèi)排名前幾的大機(jī)構(gòu),推薦行業(yè)龍頭:王氏教育。
王氏教育全國(guó)直營(yíng)校區(qū)面授課程試聽(tīng)【復(fù)制后面鏈接在瀏覽器也可打開(kāi)】:
在“游戲特效/unity3D”領(lǐng)域的培訓(xùn)機(jī)構(gòu)里,【王氏教育】是國(guó)內(nèi)的老大,且沒(méi)有加盟分校,都是總部直營(yíng)的連鎖校區(qū)。跟很多其它同類(lèi)型大機(jī)構(gòu)不一樣的是:王氏教育每個(gè)校區(qū)都是實(shí)體面授,老師是手把手教,而且有專(zhuān)門(mén)的班主任從早盯到晚,爆肝式的學(xué)習(xí)模式,提升會(huì)很快,特別適合基礎(chǔ)差的學(xué)生。
大家可以先把【繪學(xué)霸】APP下載到自己手機(jī),方便碎片時(shí)間學(xué)習(xí)——繪學(xué)霸APP下載:
學(xué)了總沒(méi)有壞處的,出來(lái)工作了,至少你不編程吧,別人說(shuō)你還是聽(tīng)得懂,不至于盲
C語(yǔ)言的基本語(yǔ)法我是不打算再提了,很多C語(yǔ)言編程的書(shū),就是將一些基本的數(shù)據(jù)類(lèi)型、數(shù)據(jù)結(jié)構(gòu)、語(yǔ)法,然后就是一些數(shù)值
計(jì)算的實(shí)例,大多數(shù)都是雷同的,難免有抄襲之嫌,而且頁(yè)沒(méi)有多少實(shí)用價(jià)值。
本書(shū)以實(shí)用實(shí)例作為編程指導(dǎo),指引大家編寫(xiě)真正實(shí)用的程序。了解到大家對(duì)黑客程序、病毒、窗口類(lèi)程序比較感興趣,因此我就拿這些實(shí)例進(jìn)行講解?;诖蠹一径加肳indows XP SP3,我也就在這個(gè)系統(tǒng)上把程序調(diào)試成功后再給大家講解。編程環(huán)境,我還是喜歡VisualC++ 6.0
本書(shū)計(jì)劃從四個(gè)大的方面來(lái)講,這四個(gè)方面是:窗口類(lèi)、文件操作類(lèi)、網(wǎng)絡(luò)類(lèi)、數(shù)據(jù)庫(kù)類(lèi)。
都是時(shí)下流行的編程必備技術(shù),也是軟件開(kāi)發(fā)者,必須掌握的技術(shù)。中間以實(shí)例講解,逐步學(xué)習(xí),相信大家看完后會(huì)有很大的提高的。
第一章窗口類(lèi)程序的編寫(xiě)
這一章就先來(lái)講解下窗口類(lèi)程序的編寫(xiě)。因?yàn)楝F(xiàn)在程序沒(méi)有界面,就像人沒(méi)有臉面一樣,而且好的界面更能吸引人。從基本的界面開(kāi)始,相信能給大家指明出一條路的,使大家很容易地掌握窗口序的編寫(xiě)。其實(shí)界面設(shè)計(jì)利用VC 6.0 的MFC,很容易地制作出來(lái)。這里從底層開(kāi)始寫(xiě)代碼來(lái)寫(xiě)界面程序,使大家知道一些底層的東西,為以后學(xué)習(xí)打下好的基礎(chǔ),相信您學(xué)了這些,再用VC 的MFC會(huì)得心應(yīng)手的。
1.1
用 C 寫(xiě)的第一個(gè)一個(gè)窗口程序
作為編程的開(kāi)始,我們還是以一個(gè)Hello World來(lái)開(kāi)始我們的學(xué)習(xí)之旅。代碼如下:
#include stdio.h
void main()
{
printf("Hello World!");
}
這是一個(gè)再簡(jiǎn)單不過(guò)的C程序了,只要有點(diǎn)C語(yǔ)言的知識(shí)就能夠懂的,不過(guò)這里估計(jì)還有些人,到現(xiàn)在還不知道#include
stdio.h中的頭文件stdio.h到底是什么東西,我就來(lái)說(shuō)下了,stdio.h是一個(gè)文本文件,存在于磁盤(pán)上的,已VC為例它的位置如下圖:
也許你聽(tīng)說(shuō)過(guò)printf()函數(shù)是在stdio.h中預(yù)定義的,但是你見(jiàn)過(guò)其定義的形式?jīng)]有,沒(méi)有且看下圖
其定義形式,就如圖中所示,也許你并不懂前面那些東西是什么,不用擔(dān)心,以后我會(huì)慢慢解釋給大家的。函數(shù)是先定義才能使用的,所以stdio.h中定義printf函數(shù),我我們?cè)谝昧藄tdio.h頭文件后就可以在程序中調(diào)用printf函數(shù)了。
上面是在命令行中顯示一個(gè)“Hello World!”,沒(méi)什么意思,下面我寫(xiě)一個(gè)窗口程序,顯示個(gè)Hello World!
#include windows.h
void main()
{
MessageBox(NULL,"Hello World!","我的第一個(gè)窗口程序",MB_OK);
}
編譯運(yùn)行后如下圖:
彈出的是一個(gè)對(duì)話框,上面有Hello World,還有一個(gè)標(biāo)題和一個(gè)“確定”按鈕。
當(dāng)然你會(huì)說(shuō)這對(duì)話框也算個(gè)窗口嗎?這里肯定的告訴你:是的,對(duì)話框是窗口程序的一個(gè)子集。你可能還會(huì)這樣問(wèn),這樣一個(gè)簡(jiǎn)單的窗口有啥用呢,其實(shí)這樣的窗口非常有用,我們?cè)诓僮饔?jì)算機(jī)的時(shí)候,會(huì)出現(xiàn)一些警告或提示的對(duì)話框,都是基本是這種方法寫(xiě)出來(lái)的。就算是這個(gè)很簡(jiǎn)單,學(xué)習(xí)本來(lái)不就是有易向難,有淺顯深?yuàn)W去的過(guò)程嗎。
整個(gè)效果幾乎就是靠一個(gè)函數(shù)MessageBox的功勞。這里也先不介紹這個(gè)函數(shù)了,說(shuō)些其他的。
其實(shí)用C編寫(xiě)一些惡程序,就是把編程環(huán)境中所提供的一些函數(shù)熟悉了基本就可以了。用VC來(lái)寫(xiě)成序,其中的頭文件有很多,定義了很多Windows API 函數(shù)、數(shù)據(jù)結(jié)構(gòu)、宏,可以讓我們大家運(yùn)用,通過(guò)它們,我們可以快速開(kāi)發(fā)出使用的程序。這些Windows API在微軟的MSDN上查,上面有很多說(shuō)明,部分還有代碼示例。不會(huì)是可以輸入函數(shù)名,查找相關(guān)信息,建議大家用英文版的Library,因?yàn)槠鋬?nèi)容比中文版的全面,英語(yǔ)不好的同學(xué)呢,就先看中文了
中文MSDN:
英文MSDN:
到這里,我們就完成第一個(gè)有界面程序的編寫(xiě),你感覺(jué)寫(xiě)有界面的程序難嗎?顯然不難。
下面看一個(gè)向鋒和波波感興趣的程序:九九乘法
采用命令行形式
#include “stdio.h”
int i=0,j=0;
for(i=1;i10;i++)
for(j=1;ji+1;j++)
printf(“%d*%d=%d\t”,j,i,j*i);
printf(“\n”);
和那個(gè)javascript效果都是一樣的,所以語(yǔ)言只要學(xué)好一樣,其他的就很容易旁通的,學(xué)習(xí)就撿一種學(xué)好,不要貪多。
好的,這一節(jié)就這樣吧,大家先各自了解下微軟的MSDN,對(duì)以后的學(xué)習(xí)會(huì)有很大的幫助的。
1.2 第一個(gè)真正的窗口程序
上一節(jié)中,我們用MessageBox函數(shù)輕松地實(shí)現(xiàn)了一個(gè)對(duì)話框窗口,可能你會(huì)說(shuō),那僅僅是個(gè)沒(méi)有用的對(duì)話框而已,是的,只是對(duì)話框而已。我之所以以一個(gè)對(duì)話框?yàn)槔?,是因?yàn)槲抑皇窍胱屇阒缹?xiě)一個(gè)有界面的程序并不是件難辦的事。明白了這一點(diǎn)后,我們繼續(xù)。今天來(lái)編寫(xiě)一個(gè)真正的窗口程序。
下面就該羅嗦一段了,由于大家以前并沒(méi)有寫(xiě)過(guò)什么窗口程序,寫(xiě)的都是命令行下的,我們知道在命令行下的程序都有一個(gè)主函數(shù)main,這個(gè)函數(shù)也就是程序的入口函數(shù)。我們現(xiàn)在用VC 6.0來(lái)寫(xiě),而且要寫(xiě)窗口類(lèi)程序,VC 6.0給我們提供了一個(gè)專(zhuān)門(mén)用作窗口類(lèi)程序的入口函數(shù)WinMain()
這個(gè)函數(shù)原型是這樣的
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTRlpCmdLine,
int nCmdShow
);
大家是不是感覺(jué)這個(gè)函數(shù)挺復(fù)雜的,有這么幾個(gè)參數(shù),而像main好像就沒(méi)有參數(shù)。其實(shí)main是有參數(shù),這個(gè)向鋒和小四是知道了的。但是main函數(shù)的參數(shù)是可以省略的,而WinMain是不可以省的。這里也要對(duì)VC6.0的編譯模式改下
看下圖
依次是“工程”→“設(shè)置”→“連接”,在“工程選項(xiàng)”里把console改為windows就可以了。如果認(rèn)真學(xué)了匯編,或是手寫(xiě)命令編譯連接過(guò)C程序,就會(huì)知道這是干什么的。Console是控制臺(tái)的意思,以前我們用mian函數(shù)寫(xiě)的程序都是以控制臺(tái)模式連接的,所以很少會(huì)有界面的?,F(xiàn)在我們要寫(xiě)有界面的程序,所以要選Windows(窗口)模式了。
我們寫(xiě)入以下代碼,并按照上面說(shuō)的方法去做,看看結(jié)果
#include "windows.h"
int WINAPI WinMain(HINSTANCEhInstance,
HINSTANCE hPreInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
MessageBox(NULL,"WinMain創(chuàng)建的窗口程序","WinMain",MB_OK);
return0;
}
結(jié)果如下圖:
與第一節(jié)中的這段代碼代碼比較下
#include “windows.h”
void main()
{
MessageBox(NULL,"Hello World!","我的第一個(gè)窗口程序",MB_OK);
}
兩者比較下,后者多了個(gè)cmd窗口。可見(jiàn)用main寫(xiě)的并沒(méi)有完全脫離命令行呀。所以以后我們寫(xiě)窗口程序就用winmain了。
好了,轉(zhuǎn)過(guò)來(lái),我們來(lái)看看WinMain()函數(shù),其中有4個(gè)參數(shù)
先看下解釋?zhuān)床幻靼椎孟瓤赐辏?/p>
hInstance:應(yīng)用程序當(dāng)前事例的句柄。
hPrelnstance:應(yīng)用程序的先事例的句柄。對(duì)于同一個(gè)程序打開(kāi)兩次,出現(xiàn)兩個(gè)窗口第一次打開(kāi)的窗口就是先前實(shí)例的窗口。對(duì)于一個(gè)32的位程序,該參數(shù)總為NULL。
lpCmdLine:指向應(yīng)用程序命令行的空字符串的指針,不包括函數(shù)名。獲得整個(gè)命令行,參看GetCommandLine。
nCmdShow:指明窗口如何顯示(是隱藏還是顯示,有沒(méi)有最大化按鈕之類(lèi)的)。取值可以參考MSDN
這里我相信有一個(gè)詞大家好應(yīng)該比較陌生,句柄(HANDLE)是吧。下面我就來(lái)簡(jiǎn)單的說(shuō)下
句柄其實(shí)就是Windows系統(tǒng)中一個(gè)東西的唯一標(biāo)識(shí)。就是系統(tǒng)中有很多運(yùn)行的程序或者資源之類(lèi)的,為了更好的管理使用,Windows系統(tǒng)給它們每人一個(gè)ID一樣。懂得網(wǎng)頁(yè)制作的人應(yīng)該知道網(wǎng)頁(yè)中各個(gè)元素的ID吧,網(wǎng)頁(yè)的ID如果重復(fù)話可能出現(xiàn)錯(cuò)誤。那么系統(tǒng)的句柄會(huì)不會(huì)有相同的,那是肯定不會(huì)有的了,就和我們的學(xué)號(hào)一樣,系統(tǒng)自動(dòng)分配每一個(gè)模塊的句柄,是不會(huì)相同的了。
對(duì)于句柄大家可以先這樣理解著,不用一下子搞懂得。以后學(xué)著學(xué)著就明白了。
估計(jì)大家對(duì)那幾個(gè)參數(shù)的類(lèi)型改犯迷糊了吧。其實(shí)那幾個(gè)類(lèi)型,并不是什么新類(lèi)型,都是Windows開(kāi)發(fā)人員為了自己和他人編程方便,同過(guò)基本的C語(yǔ)言語(yǔ)法定義一種新的結(jié)構(gòu)體,或者是共同體,再者就是枚舉類(lèi)型。我知道結(jié)構(gòu)體、共同體和枚舉類(lèi)型,很多老師是沒(méi)有講到的,因?yàn)樵跁?shū)的后邊,很多教C的,又是很垃圾的老師,所以不會(huì)講那么快的。其實(shí)結(jié)構(gòu)體這些數(shù)據(jù)類(lèi)型,就是通過(guò)我們常用的字符、整型、浮點(diǎn)等數(shù)據(jù)類(lèi)型構(gòu)造一個(gè)比較復(fù)雜的類(lèi)型而已,舉個(gè)例子,就是我們知道C沒(méi)有一個(gè)數(shù)據(jù)類(lèi)型可以描述一個(gè)人吧,那么我構(gòu)造一個(gè)是不是很方便我們編程呢。我們可以這樣構(gòu)造一個(gè)
struct People
{
intage;//年齡
charsex[2];//性別
intheight;//身高
……
}
我們這樣定義以后就可以在我們以后的程序中利用這個(gè)數(shù)據(jù)類(lèi)型了,People zhangsan;把zhangsan的身高172放到zhangsan.height中。這樣可以方便完成很多工作。所以結(jié)構(gòu)體是很簡(jiǎn)單的,還有其他的復(fù)雜數(shù)據(jù)類(lèi)型也是很簡(jiǎn)單的,都是有常用的簡(jiǎn)單的類(lèi)型來(lái)結(jié)合到一起構(gòu)造一個(gè)復(fù)雜的而已。這和JAVA定義類(lèi)是很相似的,java定義個(gè)人類(lèi),不是可以這樣的
public class People
{
publicint age;
publicstring sex;
publicheight;
……
}
看起來(lái)都差不多,而且用法也很相像。唯一的差別其實(shí)就是類(lèi)可以有方法,而結(jié)構(gòu)體是沒(méi)有的(經(jīng)過(guò)特殊處理也是可以的,這里不用考慮)。
上面是為了讓大家了解下復(fù)雜數(shù)據(jù)類(lèi)型的定義,羅嗦了一大堆。下面來(lái)看下WinMain中第一個(gè)參數(shù)的類(lèi)型HINSTANCE這個(gè)只是個(gè)結(jié)構(gòu)體而已,實(shí)際上和HANDLE這個(gè)類(lèi)型差不多,但是有一點(diǎn)差別,而HANDLE是這樣typedef PVOID HANDLE;定義的,PVOID是什么呢,我們來(lái)看下typedef void *PVOID;說(shuō)明PVOID是一個(gè)指針,初始指向空(void)。因此可以知道句柄也是個(gè)指針而已??粗@么復(fù)雜原來(lái)也只是指針。
這些都可以在微軟的msdn上查得到的,而且很詳細(xì)的
那個(gè)第二個(gè)LPSTR 根據(jù)字面上的意思就知道是字符串類(lèi)型了。查一查果然是。
大家一定要利用好msdn,很有用的。
本節(jié)就到此結(jié)束了,主要是說(shuō)明了一個(gè)WinMain函數(shù)和結(jié)構(gòu)體的事情,東西也不算太多,大家應(yīng)該能接受得了吧。下節(jié)就來(lái)點(diǎn)復(fù)雜點(diǎn)深點(diǎn)的東西,希望大家做好心理準(zhǔn)備。
1.3 窗口程序的編寫(xiě)
在來(lái)啰嗦之前,希望大家能夠做好準(zhǔn)備,這一節(jié)知識(shí)有點(diǎn)多,內(nèi)容有點(diǎn)長(zhǎng)。但愿大家能夠一口氣讀完,如果一口氣讀不完,那就換口氣接著讀。
上節(jié)中我們用MessageBox()就實(shí)現(xiàn)了一個(gè)真正的窗口。MessageBox()中的原型如下:
Int MessageBox(HWND hWnd,
LPCTSTRlpText,
LPCTSTRlpCaption,
UINT uType);
參數(shù)解釋
hWnd 所屬對(duì)話框所屬窗口的句柄,如果是NULL,則此對(duì)話框不屬于任何一個(gè)窗口。
lpText 對(duì)話框窗口的顯示內(nèi)容。
lpCaption 對(duì)話框窗口的標(biāo)題。
uType 對(duì)話框的樣式和動(dòng)作(像是確定按鈕,還是取消按鈕就是設(shè)置這里的)
關(guān)于這個(gè)函數(shù)的細(xì)節(jié)可以看這里
到此為止,你也算是會(huì)了窗口程序的編寫(xiě),但只是一個(gè)開(kāi)始,不過(guò)這已經(jīng)很好,可能會(huì)讓你感覺(jué)到了C的魅力,也可能會(huì)稍微解點(diǎn)C語(yǔ)言能干什么的疑惑。在開(kāi)始寫(xiě)代碼之前,我有必要把細(xì)節(jié)和原理先說(shuō)明下。
Windows下一個(gè)窗口創(chuàng)建的過(guò)程有以下幾個(gè)步驟:
1. 程序創(chuàng)建一個(gè)窗口,首先要向Windows系統(tǒng)注冊(cè)一個(gè)窗口類(lèi)wndclassex,其實(shí)就是定義一個(gè)變量,變量的類(lèi)型是WNDCLASSEX(結(jié)構(gòu)體)。該結(jié)構(gòu)體的定義與介紹看這里(),
typedef struct {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;
成員介紹
cbSize 值為sizeof(WNDCLASSEX),在調(diào)用GetClassInfoEx前必須要先設(shè)置它值。
style 窗口類(lèi)的樣式,它的值可以是窗口樣式值的任意組合。
可以有以下的值
lpfnWndProc 指向窗口處理函數(shù)(回調(diào)函數(shù))。處理窗口事件,像單擊鼠標(biāo)會(huì)怎樣,右擊鼠標(biāo)會(huì)怎樣,都是由此函數(shù)控制的。
cbClsExtra 為窗口類(lèi)的額外信息做記錄,系統(tǒng)初始化為0。
cbWndExtra 記錄窗口實(shí)例的額外信息,系統(tǒng)初始為0.如果程序使用WNDCLASSEX注冊(cè)一個(gè)從資源文件里創(chuàng)建的對(duì)話框,則此參數(shù)必須設(shè)置為DLGWINDOWEXTRA
hIcon 窗口類(lèi)的圖標(biāo),為資源句柄,如果設(shè)置為NULL,系統(tǒng)將為窗口提供一個(gè)默認(rèn)的圖標(biāo)。
hCursor 窗口類(lèi)的鼠標(biāo)樣式,為鼠標(biāo)樣式資源的句柄,如果設(shè)置為NULL,系統(tǒng)提供一個(gè)默認(rèn)的鼠標(biāo)樣式。
hbrBackground 窗口類(lèi)的背景刷,為背景刷句柄,也可以為系統(tǒng)顏色值,如果顏色值已給出,則必須轉(zhuǎn)化為以下的HBRUSH的值
· COLOR_ACTIVEBORDER
· COLOR_ACTIVECAPTION
· COLOR_APPWORKSPACE
· COLOR_BACKGROUND
· COLOR_BTNFACE
· COLOR_BTNSHADOW
· COLOR_BTNTEXT
· COLOR_CAPTIONTEXT
· COLOR_GRAYTEXT
· COLOR_HIGHLIGHT
· COLOR_HIGHLIGHTTEXT
· COLOR_INACTIVEBORDER
· COLOR_INACTIVECAPTION
· COLOR_MENU
· COLOR_MENUTEXT
· COLOR_SCROLLBAR
· COLOR_WINDOW
· COLOR_WINDOWFRAME
· COLOR_WINDOWTEXT
lpszMenuName 指向一個(gè)以NULL結(jié)尾的字符床,同目錄資源的名字一樣。如果使用整型id表示菜單,可以用MAKEINTRESOURCE定義一個(gè)宏。如果它的值為NULL,那么該類(lèi)創(chuàng)建的窗口將都沒(méi)有默認(rèn)的菜單。
lpszClassName 窗口類(lèi)的名字,字符串類(lèi)型。
hIconSm 小圖標(biāo)的句柄,在任務(wù)欄顯示的圖標(biāo),可以和上面的那個(gè)一樣。
定義一個(gè)WNDCLASSEX類(lèi)型變量后,在給變量成員初始化后,我們就可以用
RegisterWindowEx(wndclassex)來(lái)注冊(cè)這個(gè)窗口類(lèi)了。
這個(gè)注冊(cè)過(guò)程,就和我們平常創(chuàng)建一個(gè)項(xiàng)目一樣,都要先注冊(cè)才能創(chuàng)建。
文章名稱(chēng):javascript牛頓的簡(jiǎn)單介紹
分享URL:http://m.rwnh.cn/article40/dsdhhho.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、網(wǎng)站策劃、微信公眾號(hào)、靜態(tài)網(wǎng)站、Google、小程序開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)