[Powered by Google Translate] [Secțiunea 4 - mai confortabil]
[Rob Bowden - Universitatea Harvard]
[Acest lucru este CS50. - CS50.TV]
Avem un test mâine, în cazul în care voi nu știți că.
E practic pe tot ce ai putut fi văzut în clasă sau ar fi văzut în clasă.
Aceasta include indicii, chiar dacă ele sunt un subiect foarte recentă.
Tu ar trebui cel puțin să înțeleagă niveluri ridicate ale acestora.
Orice lucru care a fost plecat peste in clasa ar trebui să înțeleagă pentru test.
Deci, dacă aveți întrebări cu privire la ele, le puteți întreba acum.
Dar acest lucru va fi o sesiune foarte elev condusă de unde voi pune întrebări,
deci sperăm că oamenii au întrebări.
Are cineva întrebări?
Da. >> [Elev] Poti sa te duci peste indicii din nou?
Voi trece peste pointeri.
Toate variabilele neapărat trăiesc în memorie,
dar, de obicei, nu vă faceți griji despre asta și ai spus x si y + 2 + 3
și compilatorul va da seama unde lucrurile sunt vii pentru tine.
După ce de-a face cu pointeri, acum te utilizați în mod explicit acele adrese de memorie.
Deci, o singură variabilă va fi doar trăi vreodată într-o singură adresă la un moment dat.
Dacă vrem să declare un pointer, ceea ce este tipul de gând să arate?
>> Vreau să declare un pointer p. Ce face tipul arata?
[Elev] int * p. Da >>. Deci, int * p.
Și cum să fac să indice către x? >> [Elev] Ampersand.
[Bowden] Deci ampersand este literalmente numit adresa operatorului.
Deci, atunci când spun & x se obține adresa de memorie a variabilei x.
Asa ca acum am p indicatorul, și oriunde în codul meu pot folosi * p
sau am putea folosi x si va fi exact același lucru.
(* P). Ce este aceasta face? Ce înseamnă asta înseamnă stea?
[Elev] Aceasta înseamnă o valoare în acel moment. Da >>.
Deci, dacă ne uităm la ea, poate fi foarte util pentru a scoate în diagrame
în cazul în care aceasta este o cutie mica de memorie pentru x, care se întâmplă să aibă valoarea 4,
atunci avem o cutie mica de memorie pentru p,
și astfel punctele p la x, asa ca am trage o săgeată de la P la x.
Așa că atunci când spunem p * ne spui merge la caseta care este p.
Star este urmați săgeată și apoi faci ce vrei cu cutia aia de acolo.
Deci, eu pot spune * p = 7, și care va merge la caseta pe care este x și schimbare care la 7.
Sau aș putea spune int z = * p * 2; Asta e confuz, deoarece stele, stele.
De o stea este dereferencing p, alte stele este înmulțirea cu 2.
Observati ca am putea avea la fel de bine înlocuiește p * cu x.
Aveți posibilitatea să le utilizați în același mod.
Și apoi mai târziu am pot avea p punctul de a un lucru complet nou.
Eu pot spune doar p = &z;
Deci, acum nu p puncte mai la X, aceasta subliniază la z.
Și în orice moment să fac * p e la fel ca faci z.
Deci, lucru util despre acest lucru este, odată ce vom începe a intra în funcțiile.
>> E un fel de inutil să declare un pointer care indică spre ceva
si apoi esti doar o dereferencing
, atunci când ar fi putut folosi variabila originală pentru a începe cu.
Dar atunci când vei ajunge în funcții - așa că hai să spunem că avem o anumită funcție, int foo,
care ia un pointer și doar nu * p = 6;
Cum am văzut înainte de swap cu, nu poți să faci un schimb eficient și o funcție separată
prin care trece doar numere întregi pentru că totul în C este întotdeauna trece prin valoare.
Chiar și atunci când ești trece indicii ce te trece prin valoare.
Pur și simplu așa se întâmplă că aceste valori sunt adrese de memorie.
Deci, atunci când spun foo (p); am trece indicatorul în funcția de foo
si apoi foo este de a face * p = 6;
Deci, în interiorul acestei funcții, * p este încă echivalent cu x,
dar eu nu pot folosi x interiorul această funcție, deoarece nu e scoped în această funcție.
Deci, * p = 6 este singurul mod pot accesa o variabilă locală dintr-o altă funcție.
Sau, ei bine, pointerii sunt singurul mod pot accesa o variabilă locală dintr-o altă funcție.
[Elev] Hai spune că a vrut să se întoarcă un pointer. Exact cum faci asta?
[Bowden] Reveniți un indicator la fel ca în ceva de genul int y = 3; retur & Y? >> [Elev] Da.
[Bowden] Ok. Tu nu ar trebui să facă acest lucru. Acest lucru este rău.
Cred că am văzut în aceste diapozitive curs ai început să vezi această diagramă întreagă de memorie
în cazul în care aici le-ați luat adresa de memorie 0
si aici aveti adresa de memorie 4 gig-uri sau 2 pentru a 32.
Deci, atunci ai niște lucruri și unele lucruri si apoi ai stack-ul
și le-ați luat morman ta, pe care tocmai l-ați început să învețe despre, în creștere în sus.
[Elev] nu este grămadă de mai sus stiva?
>> Da. Heap este pe partea de sus, nu-i așa? >> [Elev] Ei bine, el a pus pe partea de sus 0.
[Elev] Oh, el a pus pe partea de sus 0. >> [Elev] Oh, bine.
Disclaimer: Oriunde, cu CS50 ai de gând să-l văd în acest fel. >> [Elev] Ok.
E doar că, atunci când te vezi prima stive,
ca atunci când te gândești la un teanc credeți de stivuire lucruri pe partea de sus a unul pe altul.
Deci, avem tendinta de a răsturna această jurul astfel încât stiva este în creștere în sus ca o stivă în mod normal, ar fi
în loc de stivă este purtata in jos. >> [Elev] Nu grămezi cresc punct de vedere tehnic prea, deși?
Aceasta depinde de ceea ce vrei să spui cu maturizezi.
Stivă și heap cresc întotdeauna în direcții opuse.
O stivă este întotdeauna în creștere până în sensul că este în creștere în sus
spre adrese mai mari de memorie, și heap este în creștere în jos
în măsura în care este în creștere față de adresele de memorie mai mici.
Deci, partea de sus este 0 și partea de jos este de adrese de memorie de mare.
Sunt amândoi în creștere, doar în direcții opuse.
[Elev] Am vrut doar că pentru că ai spus că ai pus teancul în partea de jos
deoarece se pare mult mai intuitivă, deoarece pentru stiva să înceapă de la partea de sus a unui heap,
morman e pe partea de sus de la sine, deci that - >> Da.
Puteți, de asemenea că a heap ca de creștere și mai mare, dar stiva cu atât mai mult.
Deci, stivă este cea pe care am cam vrea să arate crescut.
Dar peste tot te uiti altfel va pentru a vedea adresa de 0 la partea de sus
și adresa de memorie mai mare în partea de jos, astfel încât aceasta este opinia dumneavoastră obișnuită de memorie.
>> Ai o intrebare?
[Elev] Ne puteți spune mai multe despre heap?
Da. Voi ajunge la faptul că într-o secundă.
În primul rând, revenind la motivul pentru returnarea & y este un lucru rău,
pe stiva aveți o grămadă de cadre stack care reprezintă toate funcțiile
care au fost chemați.
Deci, ignorând lucrurile anterioare, partea de sus a stack-ul tău este întotdeauna o să fie funcția principală
din moment ce e prima funcție care a fost numit.
Și apoi când apelați o altă funcție, stiva este de gând să crească în jos.
Deci, dacă am numi o anumită funcție, foo, și devine cadrul acesteia stivă proprie,
se poate apela o anumită funcție, bar, acesta devine rama stiva proprie.
Și barul ar putea fi recursive și s-ar putea numi ea însăși,
și astfel încât al doilea apel la Barul este mergi la a lua cadru de stivă proprie.
Și astfel, ceea ce se întâmplă în aceste cadre stack sunt toate variabilele locale
și toate argumentele funcției care -
Orice lucruri care sunt la nivel local scoped la această funcție meargă în aceste cadre stack.
Asta înseamnă că atunci când am zis ceva de genul bar este o funcție,
Mă duc să declare un număr întreg și apoi să se întoarcă un pointer la întreg.
Deci, în cazul în care nu locuiesc y?
[Elev] Y locuiește în bar. >> [Bowden] Da.
Undeva în acest pătrat mic de memorie este un pătrat Littler care are y în ea.
Când mă voi întoarce & Y, Mă întorc un pointer la acest bloc mic de memorie.
Dar apoi, când se întoarce funcția, rama stiva sa se apărut pe stiva.
Și de aceea se numește stivă.
E ca și cum structura de date stiva, dacă știi ce este.
Sau chiar ca un teanc de tăvi este întotdeauna exemplu,
principal este de gând să meargă pe partea de jos, apoi prima funcție suna este de gând să meargă pe partea de sus de faptul că,
si nu poti sa ma intorc la principal până când te vei întoarce de la toate funcțiile care au fost numite
care au fost plasate pe partea de sus a acesteia.
>> [Elev] Deci, dacă tu ai făcut reveni y &, ca valoare este supusă de a schimba fără notificare prealabilă.
Da, e. - >> [elev] Ar putea fi suprascrise. Da >>.
E complet - Dacă încercați și -
Acest lucru ar fi, de asemenea, un bar * int, deoarece se întoarce un pointer,
deci tipul său de retur este * int.
Dacă încercați să utilizați valoarea întoarsă de această funcție, e un comportament nedefinit
pentru că indicatorul indică memorie proasta. >> [Elev] Ok.
Și ce dacă, de exemplu, a declarat int * y = malloc (sizeof (int))?
Asta e mai bine. Da.
[Elev] Noi am vorbit despre cum, atunci când ne trageți lucrurile să coșul de gunoi nostru
ei nu sunt de fapt șterse; vom pierde doar pointeri lor.
Deci, în acest caz, avem de fapt șterge valoarea sau este încă acolo, în memoria?
Pentru cea mai mare parte, o să fie încă acolo.
Dar hai să spunem că se întâmplă pentru a apela o alta functie, Baz.
Baz este mergi la a lua cadru de stivă propria aici.
O să fie suprascrierea toate aceste lucruri,
și apoi, dacă încercați mai târziu și de a folosi indicatorul pe care ai înainte,
nu va fi aceeași valoare.
Se va fi schimbat doar pentru că ai sunat Baz funcția.
[Elev] Dar dacă nu am fi, ne-am primi în continuare 3?
[Bowden] În toate probabilitățile, ai face.
Dar nu te poti baza pe asta. C spune doar un comportament nedefinit.
>> [Elev] Oh, nu. Bine.
Deci, atunci când doriți să se întoarcă un pointer, în cazul în care acest lucru este malloc vine în uz.
Am scris, de fapt a reveni la doar malloc (3 * sizeof (int)).
Vom trece peste malloc mai mult intr-o secunda, dar ideea de malloc este tot de variabilele locale
întotdeauna merge pe stiva.
Orice lucru care se malloced merge pe movila, și-l va pentru totdeauna și să fie întotdeauna pe heap
până când eliberați în mod explicit.
Deci, acest lucru înseamnă că, atunci când malloc ceva, o să supraviețuiască după întoarcerea funcția.
[Elev] Va supraviețui după programul de funcționare se oprește? Nu >>
Bine, așa că va fi acolo pana cand programul este tot drumul făcut de rulare. Da >>.
Putem merge peste detalii cu privire la ceea ce se întâmplă atunci când rulează programul se oprește.
S-ar putea nevoie pentru a-mi aminti, dar că este un lucru separat în întregime.
[Elev] Deci, malloc creează un pointer? Da >>.
Malloc - >> [elev] Cred că malloc desemnează un bloc de memorie pe care un pointer poate folosi.
[Bowden] Vreau diagrama din nou. >> [Elev] Deci, această funcție este, totuși?
[Elev] Da, malloc desemnează un bloc de memorie pe care le puteți utiliza,
și apoi returnează adresa primului bloc de memorie care.
>> [Bowden] Da. Deci, atunci când malloc, te hapsân unele bloc de memorie
care este în prezent în grămadă.
În cazul în heap este prea mic, atunci heap este doar de gând să crească, și aceasta crește în această direcție.
Deci, haideți să spunem heap este prea mic.
Apoi este vorba despre să crească un pic și a reveni un pointer la acest bloc, care tocmai au crescut.
Când chestii gratuite, tu faci mai mult spațiu în heap,
Deci, atunci o sun mai târziu la malloc poate reutiliza că memoria pe care le-au eliberat anterior.
Cel mai important lucru despre malloc și gratuit este că vă oferă control complet
peste durata de viață a acestor blocuri de memorie.
Variabilele globale sunt mereu vie.
Variabilele locale sunt în viață în domeniul de aplicare a acestora.
De îndată ce te duci trecut o proteză cret, variabilele locale sunt morți.
Memoria Malloced este în viață când vrei să fii în viață
și apoi este eliberat atunci când îl spui să fie eliberat.
Acestea sunt, de fapt, doar 3 tipuri de memorie, într-adevăr.
Nu e de management automat al memoriei, care este stiva.
Lucrurile se întâmplă pentru tine în mod automat.
Când spui x int, memoria este alocată pentru x int.
Atunci când x iese din sfera de aplicare, memorie este regenerată pentru x.
Apoi, nu e de management al memoriei dinamice, care este ceea ce este malloc,
care este atunci când aveți de control.
Tu decizi dinamic atunci când memoria ar trebui să și nu ar trebui să fie alocate.
Și apoi nu e static, ceea ce înseamnă doar că trăiește pentru totdeauna,
care este ceea ce variabilele globale sunt.
Sunt doar mereu în memorie.
>> Întrebări?
[Elev] Poți defini un bloc doar prin utilizarea acolade
dar care nu au de a avea o? if sau o declarație vreme sau ceva de genul asta
Puteți defini un bloc ca într-o funcție, dar care are acolade prea.
[Elev] Deci, nu poti avea la fel ca o pereche de acolade aleatoriu în codul dvs.
care au variabilele locale? >> Da, puteți.
În interiorul barei de int am putea avea {int y = 3;}.
Asta ar trebui să fie chiar aici.
Dar care definește complet domeniul de aplicare al int y.
După aceea bretele două cret, y nu poate fi folosit mai.
Ai aproape niciodată asta, deși.
Noțiuni de bază înapoi la ceea ce se întâmplă atunci când un program se termină,
e un fel de minciună neînțelegere / jumătate dăm, în scopul de a face doar lucrurile mai ușor.
Noi vă spunem că, atunci când aloca memorie
te alocarea unei părți bucată de RAM pentru acea variabilă.
Dar tu nu ești cu adevărat atingă direct RAM vreodată în programele dumneavoastră.
Dacă te gândești la asta, cum am desenat -
Și, de fapt, dacă te duci prin GDB în veți vedea același lucru.
Indiferent de câte ori aveți o de program sau de ce program ai rulează,
stiva este întotdeauna de gând să înceapă -
mereu te duci sa vezi variabile în jurul a ceva oxbffff adresa.
Este, de obicei, undeva în acea regiune.
Dar cum poate avea, eventual, 2 programe indicatori către aceeași memorie?
[Elev] E un desemnarea arbitrar de locul în care oxbfff ar trebui să fie pe memoria RAM
care poate fi de fapt în locuri diferite, în funcție de momentul în care funcția a fost numit.
Da. Termenul este memoria virtuală.
Ideea este că fiecare proces unic, fiecare singur program care se execută pe computer
are propriul său - să presupunem 32 de biți - spațiu de adrese complet independent.
Acesta este spațiul de adrese.
Ea are propriile sale complet independente 4 gigaocteți de a utiliza.
>> Deci, dacă aveți 2 programe simultan, acest program vede 4 gigaocteți la sine,
acest program vede 4 gigaocteți la sine,
și este imposibil pentru acest program pentru a dereference un pointer
și se încheie cu o memorie de la acest program.
Și ce memorie virtuală este o mapare de la un spațiu de adrese procese
la lucruri reale pe RAM.
Deci, este de până la sistemul de operare să știe că,
hei, atunci când acest tip oxbfff dereferences indicatorul, care înseamnă cu adevărat
că el vrea RAM octet 1000,
întrucât în ​​cazul în care acest program oxbfff dereferences, el vrea cu adevărat RAM octet 10000.
Ele pot fi arbitrar departe unul de altul.
Acest lucru este adevărat și de lucruri într-un singur spațiu adrese procese.
Deci, la fel ca el vede toate cele 4 gigaocteți la sine, dar hai sa spunem -
[Elev] Are fiecare singur proces -
Să presupunem că aveți un calculator cu numai 4 GB de RAM.
Are fiecare proces unic vedea întregul 4 gigaocteți? Da >>.
Dar ea vede 4 gigaocteți este o minciună.
E doar crede că are toate astea de memorie pentru că nu cunosc nici un alt proces există.
Se vor folosi numai de memorie la fel de mult ca de fapt are nevoie.
Sistemul de operare nu este de gând să dea RAM la acest proces
în cazul în care nu se folosește nici o amintire în întreaga regiune.
Aceasta nu va da de memorie pentru această regiune.
Dar ideea este că - Încerc să mă gândesc la - Nu mă pot gândi la o analogie.
Analogii sunt greu.
Una din problemele de memorie virtuală sau unul dintre lucrurile pe care le-a rezolvare
este faptul că procesele ar trebui să fie complet conștienți de una de alta.
Și astfel încât să puteți scrie orice program care dereferences orice fel de pointer,
ca scrie doar un program care spune * (ox1234),
adresa și faptul că memoria dereferencing 1234.
>> Dar este de până la sistemul de operare pentru a traduce apoi ce înseamnă 1234.
Deci, dacă se întâmplă să fie 1234 o adresă de memorie validă pentru acest proces,
ca e pe stivă sau ceva, atunci acest lucru se va returna valoarea de care adresei de memorie
în ceea ce privește procesul de știe.
Dar dacă nu este 1234 o adresă validă, se întâmplă ca să aterizeze
în unele mică bucată de memorie aici, care este dincolo de stivă și dincolo de heap
și nu ați folosit într-adevăr că, atunci asta e atunci când ajungi lucruri, cum ar fi segfaults
pentru ca esti atingi de memorie pe care nu ar trebui să fie ating.
Acest lucru este, de asemenea, adevărat -
Un sistem pe 32 de biți, 32 de biți înseamnă că trebuie 32 de biți pentru a defini o adresă de memorie.
Acesta este motivul pentru indicii sunt 8 octeți, deoarece 32 de biți sunt 8 octeți sau 4 octeți -.
Pointeri sunt 4 octeți.
Deci, când veți vedea un indicator ca oxbfffff, care este -
În cadrul oricărui program de dat poti construi orice fel de indicatorul arbitrară,
oriunde de la ox0 la ox 8 f's - ffffffff.
[Elev] N-ai spus că sunt 4 octeți? Da >>.
[Elev] Apoi, fiecare octet va avea - >> [Bowden] Hexadecimal.
Hexadecimal - 5, 6, 7, 8. Deci, indicii veti vedea mereu în hexazecimal.
E doar modul în care ne clasifica pointeri.
La fiecare 2 cifre ale hexazecimal este de 1 octet.
Deci nu va fi de 8 cifre hexazecimale pentru 4 octeți.
Deci, la fiecare indicatorul singur pe un sistem de 32-biți va fi 4 octeți,
ceea ce înseamnă că, în procesul de dumneavoastră, puteți construi orice arbitrare 4 octeți
și să facă un pointer din ea,
ceea ce înseamnă că, în măsura în care acesta este conștient, se poate adresa unui întreg 2 la 32 bytes de memorie.
Chiar dacă nu are cu adevărat acces la faptul că,
chiar dacă computerul tău are doar 512 MB, acesta crede că are acea memorie de mult.
Și sistemul de operare este suficient de inteligent ca va aloca doar ceea ce ai de fapt nevoie.
Ea nu merge doar, oh, un nou proces: 4 show-uri.
>> Da. >> [Elev] Ce bou înseamnă? De ce ai scris-o?
E doar simbolul pentru hexazecimal.
Când vedeți un început număr cu boul, lucrurile sunt succesive hexazecimal.
[Elev] Ai fost să explice despre ce se întâmplă atunci când un program se termină. Da >>.
Ce se întâmplă atunci când un program se termină este sistemul de operare
șterge doar mapările pe care le are pentru aceste adrese, și asta e tot.
Sistemul de operare poate oferi acum doar că memoria la un alt program pentru a utiliza.
[Elev] Ok.
Deci, atunci când alocă ceva pe halde sau variabilele stivei sau globale sau orice altceva,
acestea toate dispar la fel de repede ca și programul se încheie
deoarece sistemul de operare este acum gratuit pentru a da ca memoria oricărui alt proces.
[Elev] Chiar dacă există, probabil, încă valori scrise în? Da >>.
Valorile sunt probabil încă acolo.
E doar că va fi dificil pentru a ajunge la ele.
E mult mai greu pentru a ajunge la ei decât este de a ajunge la un fișier șters
deoarece tipul de fișier șters sta acolo pentru o lungă perioadă de timp și unitatea hard disk este mult mai mare.
Deci, o să suprascrie diferite părți ale memoriei
înainte de a se întâmplă să suprascrie bucată de memorie pe care acel fișier folosit pentru a fi la.
Dar memoria principală, RAM, ai ciclului printr-o mult mai repede,
așa că va fi suprascrise foarte rapid.
Întrebări cu privire la acest lucru sau orice altceva?
[Elev] Am întrebări despre un subiect diferit. Bine >>.
Are cineva întrebări cu privire la acest lucru?
>> Bine. Diferite subiect. >> [Elev] Ok.
Am fost trece prin unele dintre teste de practică,
și într-una dintre ele a fost vorba despre sizeof
și valoarea pe care returnează sau diferite tipuri de variabile. Da >>.
Și a spus că atât timp cât int si retur 4, astfel încât acestea sunt atât lungimea de 4 octeți.
Există vreo diferență între un int și un lung, sau este același lucru?
Da, există o diferență.
Standard C -
Am, probabil, de gând să încurce.
Standardul C este la fel ca ceea ce C este, documentația oficială a lui C.
Aceasta este ceea ce se spune.
Deci, standardul C spune doar că o va char pentru totdeauna și întotdeauna să fie de 1 octet.
Totul după care - o scurtă este întotdeauna la fel definită ca fiind mai mare sau egal cu un char.
Acest lucru ar putea fi strict mai mare decât, dar nu pozitivă.
Un int este la fel definită ca fiind mai mare sau egală cu un scurtcircuit.
Și un lung este la fel definită ca fiind mai mare sau egală cu un int.
Și o lungă lung este mai mare sau egală cu un lung.
Deci, singurul lucru standard C defineste este ordonarea relativă a tot.
Cantitatea reală de memorie ca lucrurile să ia sus este, în general, până la punerea în aplicare,
dar e destul de bine definit în acest moment. >> [Elev] Ok.
Deci, pantaloni scurți sunt aproape întotdeauna o să fie de 2 octeți.
Ints sunt aproape întotdeauna o să fie de 4 octeți.
Lungimi lungi sunt aproape întotdeauna o să fi de 8 octeți.
Și dorește, depinde dacă utilizați un 32-bit sau un sistem de 64-biți.
Deci, un lung este de gând să corespundă cu tipul de sistem.
Dacă utilizați un sistem pe 32 de biți ca Aparatura, o să fie de 4 octeți.
Dacă utilizați un 64-biți ca o mulțime de calculatoare recente, o să fi de 8 octeți.
>> Ints sunt aproape intotdeauna 4 octeți de la acest punct.
Lungimi lungi sunt aproape întotdeauna 8 octeți.
În trecut, Ints folosit pentru a fi doar 2 octeți.
Dar observați că acest îndeplinește complet toate aceste relații de mai mare și egal cu.
Atât de mult timp este perfect permis să fie de aceeași dimensiune ca un întreg,
și este, de asemenea, a permis să fie de aceeași dimensiune ca un lung timp.
Și doar așa se întâmplă să fie că, în 99,999% din sisteme, aceasta va fi egală cu
fie un int sau un lung timp. Este doar depinde de 32-biți sau 64-biți. >> [Elev] Ok.
În flotoare, cât este punctul zecimal desemnat în termeni de biți?
Dori ca un binar? Da >>.
Nu aveți nevoie să știe că pentru CS50.
Tu nu invata chiar că, în 61.
Tu nu invata că într-adevăr, în orice curs.
E doar o reprezentare.
Am uitat de alocații exacte biți.
Ideea de virgulă mobilă pe care îl alocă un anumit număr de biți pentru a reprezenta -
Practic, totul este în notație științifică.
Astfel încât să aloce un anumit număr de biți pentru a reprezenta numărul însuși, ca și 1.2345.
Eu nu pot reprezenta un număr cu cifre mai mult de 5.
Apoi, va aloca, de asemenea, un anumit număr de biți, astfel încât acesta tinde să fie ca
poti sa te duci numai până la un anumit număr, cum ar fi faptul că e cel mai mare exponent poti avea,
și puteți merge doar până la un anumit exponent,
ca asta e cel mai mic exponent poti avea.
>> Nu-mi aduc aminte de biți exacte modul în care sunt alocate pentru toate aceste valori,
dar un anumit număr de biți sunt dedicate 1.2345,
un alt anumit număr de biți sunt dedicate exponent,
și este posibil să reprezinte un exponent de o anumită dimensiune.
[Elev] Și o dublă? Este ca ca un flotor extra lung? Da >>.
E același lucru ca un float, cu excepția acum sunteți folosind 8 octeți în loc de 4 octeți.
Acum vei putea folosi 9 cifre sau 10 cifre,
iar acest lucru va fi capabil să meargă până la 300 în loc de 100. >> [Elev] Ok.
Și plutește sunt, de asemenea, 4 octeți. Da >>.
Ei bine, din nou, probabil depinde de ansamblu privind punerea în aplicare generală,
dar flotoare sunt 4 octeți, camere duble sunt de 8.
Duble sunt numite dublu, deoarece acestea sunt duble dimensiunea de flotoare.
[Elev] Ok. Și acolo sunt dublu dublu? Nu sunt >>.
Cred că - >> [elev] Ca lungimi lungi? Da >>. Nu sunt de părere. Da.
[Elev] La testul de anul trecut a existat o întrebare despre funcția principală
având în a fi parte a programului dumneavoastră.
Răspunsul a fost că nu trebuie să facă parte din programul dumneavoastră.
În ce situație? Asta e ceea ce am văzut.
[Bowden] Se pare - >> [elev] Ce situație?
Ai probleme? >> [Elev] Da, eu pot trage cu siguranta-l în sus.
Aceasta nu trebuie să fie, punct de vedere tehnic, dar în esență o să fie.
[Elev] Am văzut una pe un an diferit de.
A fost ca și cum Adevarat sau Fals: O validă - >> Oh, un c fisier.?
. [Elev] Orice fișier c trebuie să aibă - [vorbind, atât dintr-o dată - de neînțeles]
Bine. Deci asta e separat.
>> Un fișier C. Trebuie doar să conțină funcții.
Puteți compila un fișier în cod mașină, binar, indiferent,
fără a fi încă executabil.
Un executabil validă trebuie să aibă o funcție principală.
Puteți scrie 100 de funcții în 1 fisier dar nu principalelor
și apoi compila că până la binar,
atunci va scrie un alt fișier care are doar principal, dar solicită o grămadă de aceste funcții
în acest fișier binar de aici.
Și așa că atunci când faci executabil, asta e ceea ce face linker-ul
se combină aceste 2 fișiere binare într-un executabil.
Deci, un fișier c.., Nu are nevoie să aibă o funcție principală, la toate.
Și pe baze de cod mari, veți vedea mii de fișiere. C și 1 fișierul principal.
Mai multe întrebări?
[Elev] Nu a fost o altă întrebare.
Acesta a declarat fac este un compilator. Adevărat sau fals?
Și răspunsul a fost fals, și am înțeles de ce nu e ca zăngănit.
Dar ce numim face dacă nu e?
Asigurați-este de fapt doar - Eu pot vedea exact ceea ce se solicită.
Dar se execută doar comenzile.
Asigurați.
Pot trage asta. Da.
Oh, da. Asigurați-are, de asemenea, faptul că.
Aceasta spune scopul de a marca de utilitate este de a determina în mod automat
care bucăți de un program de mare trebuie să fie recompilate
și emite comenzi pentru a le recompilați.
Puteți face face fișierele care sunt absolut imens.
Asigurați uită la ștampilele de timp de fișiere și, așa cum am spus mai înainte,
puteți compila fișierele individuale în jos, și nu e până când ajunge la linker-ul
că acestea sunt puse împreună într-un executabil.
Deci, dacă aveți 10 fișiere diferite și faceți o schimbare la 1 din ele,
atunci ceea ce fac este de gând să faci este doar faptul că recompilare 1 fișier
și repună în legătură apoi totul împreună.
Dar e mult mai prost decât asta.
E de până la tine pentru a defini complet că e ceea ce ar trebui să facă.
Ea implicit are capacitatea de a recunoaste aceste lucruri ștampila de timp,
dar aveți posibilitatea să scrie un fișier marcă să facă ceva.
Puteți scrie un fișier face astfel încât atunci când tastați face doar CD-uri într-un alt director.
Am fost obtinerea frustrat pentru că am tot ce tac interiorul Aparatura meu
si apoi am vedea PDF din Mac.
>> Așa că mă duc la Finder și eu pot să fac Du-te, Conectare la server,
și să mă conectez la serverul de e Appliance meu, iar apoi am deschide PDF-
care devine compilate de LaTeX.
Dar am fost obtinerea frustrat deoarece de fiecare data am avut nevoie pentru a actualiza PDF,
A trebuit să-l copiați într-un anumit director, care ar putea avea acces
și a fost obtinerea enervant.
Deci, în loc am scris un fișier marcă, care va trebui să definiți modul în care face lucrurile.
Cum te face în acest sens este PDF LaTeX.
La fel ca orice alt fișier face alte - sau cred că nu s-au văzut dosarele faceti-va,
dar avem în Aparatura un fișier marca la nivel mondial, care tocmai spune,
Dacă compilați un fișier C, utilizați zăngănit.
Și astfel, aici, în dosarul meu marca pe care o fac eu spun,
acest fișier ai de gând să doriți să compilați cu PDF LaTeX.
Și așa e LaTeX PDF care face compilare.
Asigurați nu este compilarea. E doar execută aceste comenzi în ordinea I, specificată.
Deci ruleaza LaTeX PDF, îl copiază directorul vreau să fie copiat la,
este CD-uri la director și face alte lucruri,
dar tot ce face este să recunoască atunci când un fișier modificări,
și în cazul în care se schimbă, atunci acesta va rula comenzile pe care ar trebui sa ruleze
atunci când se schimbă de fișiere. >> [Elev] Ok.
Nu știu unde fișierele sunt globale faceti-va pentru mine sa-l verific.
Alte întrebări? Orice din trecut teste? Orice pointer lucruri?
Momentan nu sunt lucruri subtile, cum ar fi indicii cu -
Eu nu am de gând să fie în măsură să găsească o întrebare test pe ea -
dar la fel ca acest gen de lucruri.
Asigurați-vă că ați înțeles că atunci când spun int * x * y -
Acest lucru nu este exact nimic aici, cred.
Dar, ca * x * y, cele 2 variabile sunt care sunt pe stiva.
Când spun x = malloc (sizeof (int)), x este încă o variabilă pe stivă,
malloc este un bloc de peste grămadă în, și avem x punct la grămadă.
>> Deci ceva cu privire la punctele stivă la grămadă.
Ori de câte ori te malloc ceva, te stocarea inevitabil în interiorul unui pointer.
Așa că indicatorul este pe stiva, bloc malloced este pe heap.
O mulțime de oameni se confuz și spune int * x = malloc; x este pe heap.
Nu, ce indică spre x este pe heap.
x în sine este pe stiva, cu excepția cazului în orice motiv ați x fi o variabilă globală,
caz în care se întâmplă să fie într-o altă regiune de memorie.
Deci păstrarea evidenței, aceste diagrame cutie și săgeata sunt destul de comune pentru test.
Sau dacă nu e pe test 0, acesta va fi pe test 1.
Ar trebui să știi toate acestea, pașii din compilarea
din moment ce a trebuit să răspundă la întrebări privind cele. Da.
[Elev] Putem trece peste aceste etape - >> Sigur.
Înainte de a pasi si compilarea avem preprocesare,
compilarea, asamblarea și legarea.
Preprocesare. Ce face asta?
Acesta este cel mai simplu pas în - ei bine, nu ca -
asta nu inseamna ca ar trebui sa fie evident, dar e cel mai simplu pas.
Voi putea implementa voi înșivă. Da.
[Elev] Ia ceea ce aveți în dvs. include ca acest lucru și-l copiază și apoi, de asemenea, definește.
Se pare că pentru lucruri cum ar fi: # include # define și,
și doar copii și paste ceea ce înseamnă de fapt cele.
Deci, atunci când spui include # cs50.h, preprocesor este copierea și lipirea cs50.h
în acea linie.
Când spui # define x pentru a fi 4, preprocesor trece prin întregul program
și înlocuiește toate cazurile de x cu 4.
Deci, preprocesor ia un fișier C valabil și scoate un fișier valid C
în cazul în care lucrurile au fost copiate și lipite.
Deci, acum compilarea. Ce face asta?
[Elev] Se merge de la C la binar.
>> [Bowden] Nu merge tot drumul până la binar.
[Elev] Pentru cod mașină, atunci? >> Nu e cod mașină.
[Elev] Adunarea? Adunarea >>.
Se merge la Adunarea înainte de a merge tot drumul la codul C,
și cele mai multe limbi face ceva de genul asta.
Alege orice limbaj de nivel înalt, și dacă ai de gând să-l compilați,
este posibil să compilați în trepte.
În primul rând se va compila Python la C, apoi se va compila C la Adunarea,
și apoi Adunarea urmeaza sa se traduse în binar.
Deci, compilarea se gând să-l aducă de la C la Adunarea.
Cuvântul înseamnă, de obicei compilarea aducând-o la un nivel superior
la un nivel mai mic limbaj de programare.
Deci, acesta este singurul pas în elaborarea în cazul în care vă începeți cu un limbaj de nivel înalt
și sfârșesc într-o limbă de nivel scăzut, și de aceea se numește pas compilarea.
[Elev] În timpul compilării, să spunem că ați făcut # include cs50.h.
Va compilatorul recompilare cs50.h, cum ar fi funcțiile care sunt acolo,
și traduce asta în cod de asamblare, precum și,
sau va copia și lipi ceva care a fost pre-Adunarea?
cs50.h va destul de mult niciodata nu se termina pana in Adunarea.
Chestii de genul prototipuri funcționale și de lucruri sunt doar pentru tine de a fi atent.
Se garantează că compilatorul poate verifica lucruri ca și cum ai de asteptare funcții
cu tipurile potrivite de returnare, precum și argumentele potrivite si alte chestii.
>> Deci, cs50.h va fi preprocesată în fișier, și apoi atunci când este compilarea
Este practic aruncate după ce se asigură că totul se numește în mod corect.
Dar funcțiile definite în biblioteca CS50, care sunt separate de cs50.h,
cei care nu vor fi compilate separat.
Care va veni de fapt, în etapa de legătură, așa că vom ajunge la faptul că într-o secundă.
Dar, mai întâi, ceea ce este asamblarea?
[Elev] Adunarea în binar? Da >>.
Asamblarea.
Noi nu spunem că compilarea Adunarea este destul de mult o traducere pură a binar.
Există o logică foarte puțin în trecerea de la Adunarea în binar.
E la fel ca uita în sus într-un tabel, oh, avem această instrucțiune;
care corespunde binar 01110.
Și astfel, fișierele pe care, în general, asamblarea ieșiri sunt. Fișiere o.
Și fișierele sunt o. Ceea ce spuneam înainte,
modul în care un fișier nu trebuie să aibă o funcție principală.
Orice fișier poate fi compilat în jos într-un fișier. O, atâta timp cât este un fișier valid C.
Acesta poate fi compilate în jos pentru a. O.
Acum, legătura între ceea ce este de fapt aduce o grămadă de fișiere și o. Le aduce la un executabil.
Și ce face linking este vă puteți gândi la bibliotecă CS50 ca un fișier. O.
Acesta este un fișier binar compilat deja.
Și așa, atunci când compilați fișierul, hello.c dumneavoastră, prin care se solicită getString,
hello.c este compilată în jos pentru a hello.o,
hello.o este acum în binar.
Acesta utilizează getString, așa că trebuie să meargă pe la cs50.o,
și linker-le împreună și smooshes copiaza getString în acest fișier
și vine cu un executabil care are toate functiile de care are nevoie.
Deci cs50.o nu este de fapt un fișier O, dar e destul de aproape că nu există nicio diferență fundamentală.
Deci, care leagă doar aduce o grămadă de fișiere împreună
care conțin separat toate funcțiile am nevoie pentru a utiliza
și creează executabil care va rula, de fapt.
>> Și, de asemenea, astfel încât ceea ce spuneam înainte
unde poti avea 1000. fișiere c, te compilați-le pe toate la fișiere o,.
care va avea, probabil, un timp, apoi modificați 1. fisierul c.
Trebuie doar să recompilați că: 1. Dosarul C și apoi totul altceva relegarea,
link totul înapoi împreună.
[Elev] Atunci când suntem legătura între scriem lcs50?
Da, așa-lcs50. Că semnalele de pavilion pentru a linker-ul pe care ar trebui să fie de legătură în acea bibliotecă.
Întrebări?
Am trecut peste binare, altele decât faptul că 5 secunde în prima prelegere?
Nu sunt de părere.
Ar trebui să știi toate Os mari pe care le-am trecut peste,
și ar trebui să fie în măsură să, dacă am dat o funcție,
ar trebui să fie în măsură să spun că e mare O, aproximativ. Sau bine, Big O e dur.
Deci, dacă vedeți imbricate pentru bucle looping peste același număr de lucruri,
cum ar fi int i, i <N; int j, j > [elev] n pătrat. >> Acesta tinde să fie n pătrat.
Dacă ați triplu imbricate, acesta tinde să fie n tocati.
Deci, acest fel de lucru ar trebui să fie în măsură să sublinieze imediat.
Ai nevoie să știi de inserție și sortare sortare cu bule și îmbinarea fel și toate cele.
E mai ușor de înțeles de ce ei sunt cei n pătrat și n log n si toate că
pentru că eu cred că a fost un test pe un an, dacă ne-ați dat practic
o punere în aplicare de sortare cu bule și a spus, "Care este timpul de execuție al acestei funcții?"
Așa că, dacă-l recunoaște ca un fel bule, atunci vă pot spune imediat n pătrat.
Dar daca te uiti doar la el, nu aveți nevoie chiar de a realiza un fel e balon;
vă pot spune doar acest face asta și asta. Acest lucru este n pătrat.
[Elev] Există exemple dure puteți veni cu,
ca o idee similară a imaginind?
>> Nu cred că ne-ar da vreun exemplu dure.
Lucru de sortare cu bule este la fel de dur ca ne-ar merge,
și chiar faptul că, atâta timp cât ați înțeles că sunteți iterarea peste matrice
pentru fiecare element în matrice, care va fi ceva care n pătrat.
Există întrebări generale, cum ar fi chiar aici pe care le avem - Oh.
Doar zilele trecute, Doug a afirmat: "Eu am inventat un algoritm care poate sorta o matrice
"De numere n in O (log n) timp!"
Deci, cum putem ști că e imposibil?
[Răspuns studentul nu pot fi auzite] >> Da.
Cel puțin, trebuie să atingeți fiecare element în matrice,
așa că este imposibil să sortați o matrice de -
Dacă totul este în ordine nesortate, atunci ai de gând să fie totul în atingerea matrice,
astfel încât este imposibil de a face acest lucru în mai puțin de O din nr.
[Elev] Sunteti ne-a arătat că exemplul de a fi capabil să-l facă în O de n
dacă utilizați o mulțime de memorie. Da >>.
Asta e. Și - am uitat ce that - Este un fel de numărare?
Hmm. Acesta este un algoritm de sortare întreg.
Am fost în căutarea pentru nume special pentru aceasta că nu am putut aminti săptămâna trecută.
Da. Acestea sunt tipurile de felul, care pot realiza lucruri în mare O de n.
Dar există limitări, ca tine se poate folosi numai numere întregi până la un anumit număr.
Plus, dacă sunteți încercarea de a sorta that ceva -
Dacă matricea este 012, -12, 151, 4 milioane de euro,
apoi faptul că un singur element este de gând să strice totul de sortare intreaga.
>> Întrebări?
[Elev] Dacă aveți o funcție recursivă și-l face doar apeluri recursive
într-o declarație retur, asta e coada recursiv,
și astfel nu s-ar folosi mai multă memorie, care în timpul rulării
sau ar folosi de memorie de cel puțin comparabilă ca un proces iterativ soluție?
[Bowden] Da.
Ar fi probabil ceva mai lent, dar nu chiar.
Coada recursiv este destul de bun.
Privind din nou la coșul de fum de cadre, să spunem că avem principal
și ne-am int bar (int x) sau ceva.
Aceasta nu este o funcție recursivă perfectă, dar bara de retur (x - 1).
Deci, evident, acest lucru este greșit. Ai nevoie de cazuri de bază și alte chestii.
Dar ideea aici este că acest lucru este coada recursiv,
ceea ce înseamnă că atunci când solicită principal de bar se va obține cadrul său stivă.
În acest cadru stiva acolo va fi un bloc mic de memorie
care corespunde cu x argumentul său.
Și așa că hai să spunem principal se întâmplă pentru a apela bar (100);
Deci x este de gând să înceapă ca 100.
În cazul în care compilatorul recunoaște că aceasta este o funcție recursivă coada,
atunci când bara face apelul recursiv pentru a bloca,
în loc de a face un cadru nou teanc, care este în cazul în care stiva incepe sa creasca mare măsură,
în cele din urmă acesta va rula în grămadă și apoi te segfaults
deoarece memoria începe coliziunea.
>> Deci, în loc de a face cadrului său stiva proprie, se poate realiza,
hei, n-am nevoie să vină înapoi la acest cadru stivă,
astfel încât în ​​loc voi înlocui doar acest argument, cu 99 și apoi începe peste tot barul.
Și apoi îl va face din nou și se va ajunge la bara de retur (x - 1),
și în loc de a face un cadru nou teanc, acesta va înlocui pur și simplu argumentul său actual cu 98
și apoi să sară înapoi la începutul bar.
Aceste operațiuni, care înlocuiește valoarea 1 pe stivă și sărind înapoi la început,
sunt destul de eficiente.
Deci, nu numai ca aceasta este utilizarea memoriei ca o funcție separată, care este iterativ
pentru că sunteți folosind doar 1 cadru stivă, dar tu nu ești suferă dezavantaje
de a avea pentru a apela funcțiile.
Funcțiile de asteptare poate fi oarecum costisitoare, deoarece are de a face toate acestea de configurare
și teardown și toate chestiile astea.
Deci, acest recursia Coada este bine.
[Elev] De ce nu-l creează noi pași?
Pentru că își dă seama că nu are nevoie să.
Apel la barul se întoarce doar apelul recursiv.
Deci nu are nevoie de a face ceva cu valoarea de returnare.
E doar de gând să se întoarcă imediat.
Deci, este doar de gând să înlocuiască argumentul său propriu și de la capăt.
Și, de asemenea, în cazul în care nu aveți versiunea coada recursiv,
atunci veți obține toate aceste baruri, unde atunci când această bară se întoarce
ea are să se întoarcă valoarea sa la aceasta, atunci acel bar revine imediat
și-l întoarce valoarea sa la aceasta, atunci e doar de gând să se întoarcă imediat
și a reveni la valoarea sa aceasta.
Deci, tu ești salvarea acestui popping toate aceste lucruri de pe stivă
deoarece valoarea returnata este doar de gând să fi trecut tot drumul înapoi în sus, oricum.
Deci, de ce nu doar înlocuiți argumentul nostru cu argumentul completa și începe peste?
Dacă funcția nu este coada recursiv, dacă faci ceva de genul -
[Elev] în cazul în care bara de (x + 1). Da >>.
>> Deci, dacă ai pus-o în stare, atunci faci ceva cu valoarea de returnare.
Sau chiar daca ai face doar retur 2 * bar (x - 1).
Deci, acum, bar (x - 1) trebuie să se întoarcă pentru ca aceasta a calcula de 2 ori această valoare,
asa ca acum ea are nevoie de ei cadru de propria stivă separată,
și acum, indiferent de cat de greu incercati, ai de gând să nevoie pentru a -
Acest lucru nu este coada recursiv.
[Elev] Mi-ar încerca să aducă o recursivitate să vizeze o recursivitate coadă -
[Bowden] Într-o lume ideală, dar în CS50 nu trebuie să.
În scopul de a obține recursivitate coadă, în general, vă configurați un argument suplimentar
în cazul în care bara va lua x int y în
și Y corespunde lucru final pe care doriți să se întoarcă.
Deci, atunci acest lucru ai de gând să fie returnarea bar (x - 1), 2 * y.
Așa că e doar un nivel înalt cum te transformi lucrurile să fie coada recursiv.
Dar argument în plus -
Și apoi în cele din urmă, atunci când ajunge la cazul dumneavoastră de bază, vă întoarceți doar y
pentru că ați fost acumularea tot timpul valoarea de returnare pe care o doriți.
Ai un fel de au fost o fac iterativ, dar folosind apeluri recursive.
Întrebări?
[Elev] Poate despre aritmetică indicatorul, cum ar fi atunci când se utilizează șiruri. Sigur >>.
Pointer aritmetică.
Când utilizați șiruri e ușor pentru că sunt siruri de caractere char stele,
caractere sunt pentru totdeauna și întotdeauna un singur octet,
și așa aritmetică indicatorul este echivalent cu aritmetica regulat atunci când ai de a face cu siruri de caractere.
Să spunem doar char * s = "Hello".
Deci, avem un bloc în memorie.
Este nevoie de 6 octeți, deoarece intotdeauna ai nevoie de terminator null.
Și char * s este de gând să indice începutul acestei matrice.
Deci Puncte acolo.
Acum, acest lucru este practic modul în care funcționează orice matrice,
indiferent dacă a fost o întoarcere de malloc sau dacă e pe stivă.
Orice matrice este de fapt un pointer la începutul matrice,
și apoi orice operațiune matrice, orice indexare, este doar de gând în această matrice un anumit offset.
>> Asa ca atunci cand spun ceva de genul s [3], acest lucru este de gând să s și numărarea 3 caractere inch
Deci, s [3], avem 0, 1, 2, 3, deci s [3] este de gând să se referă la acest l..
[Elev] Și am putea ajunge la aceeași valoare de a face S + 3 stele din paranteze și apoi?
Da.
Acest lucru este echivalent cu * (e + 3);
și că este pentru totdeauna și întotdeauna echivalente, indiferent de ceea ce faci.
Niciodată nu trebuie să utilizați sintaxa consola.
Aveți posibilitatea să utilizați întotdeauna * (e + 3) sintaxă.
Oamenii au tendința de a dori sintaxa suportul, totuși.
[Elev] Deci, toate matricele sunt de fapt doar indicii.
Există o distincție ușoară atunci când spun int x [4]; >> [elevului] nu creeze că memoria?
[Bowden], care este de gând să creeze 4 Ints pe stiva, deci 16 bytes de ansamblu.
Se va crea 16 bytes pe stiva.
x nu este stocat nicăieri.
Acesta este doar un simbol referindu-se la începutul lucru.
Pentru ca ai declarat matrice interiorul acestei funcții,
ceea ce compilator este de gând să faceți este să înlocuiască doar toate instanțele de variabila x
în cazul în care sa întâmplat cu a alege să afișezi aceste 16 bytes.
Nu se poate face asta cu char * s, deoarece s este un pointer reală.
Este gratuit pentru a indica apoi la alte lucruri.
x este o constantă. Tu nu poți avea punct într-o matrice diferită. >> [Elev] Ok.
Dar această idee, această indexare, este același, indiferent de faptul dacă este o matrice tradițională
sau în cazul în care este un pointer la ceva sau dacă este un pointer la o matrice malloced.
Și, de fapt, este atât de echivalent că aceasta este, de asemenea, același lucru.
Este de fapt, doar se traduce ceea ce este în interiorul a paranteze și ce a mai rămas din paranteze,
adauga-le împreună, și dereferences.
Deci, aceasta este la fel de valabilă ca și * (e + 3) sau s [3].
[Elev] Poți avea indicii care indică 2-dimensionale matrice?
>> E mai greu. În mod tradițional, nu.
O matrice 2-dimensional este doar o matrice 1-dimensional cu unele sintaxa convenabil
pentru că atunci când spun int x [3] [3], aceasta este de fapt doar o matrice cu 9 valori.
Și așa că atunci când am indicelui, compilatorul știe ce vreau să spun.
Dacă eu spun x [1] [2], se știe că vreau să merg la al doilea rând, așa că va sări peste primele 3,
și apoi vrea doilea lucru, în care, așa că va obține această unul.
Dar este încă doar un singur array-dimensional.
Și așa, dacă am vrut să atribui un pointer la care matrice,
Aș spune int * p = x;
Tipul de x este doar -
E tipul dur spune lui x, deoarece ea este doar un simbol si nu este o variabilă reală,
dar aceasta este doar o int *.
x este doar un pointer la începutul acestui. >> [Elev] Ok.
Și așa nu voi putea accesa [1] [2].
Cred că nu există sintaxă specială pentru declararea un pointer,
ceva ridicol cum ar fi int (* p [-. ceva absolut ridicol nu știu măcar.
Dar există o sintaxa de declarare indicii, cum ar fi, cu paranteze și lucruri.
Acesta nu poate lăsa chiar tu faci asta.
Aș putea privi înapoi la ceva care să-mi spui adevărul.
Voi căuta mai târziu, în cazul în care există o sintaxă pentru punct. Dar niciodată nu va vedea.
Și chiar și sintaxa este atât de arhaică că, dacă îl folosiți, oamenii vor fi surprinși.
Matrice multidimensionale sunt destul de rare, așa cum este.
Ai destul de mult -
Ei bine, dacă faci lucruri matrice nu va fi rare,
dar în C te rar gând să fie utilizând matrici multidimensionale.
Da. >> [Elevului] Să presupunem că aveți o gamă foarte lung.
>> Deci, în memoria virtuală ar părea să fie consecutive,
cum ar fi elementele de dreptul de lângă altul,
dar în memoria fizică, ar fi posibil ca să fi defalcată? Da >>.
Cum functioneaza memoria virtuală este doar separă -
Unitatea de alocare este o pagină, care tinde să fie 4 kilobytes,
și astfel încât atunci când un proces spune, hei, vreau să folosesc această memorie,
sistemul de operare este de gând să-l aloce 4 kilobytes pentru că blocul mic de memorie.
Chiar dacă utilizați doar un singur octet puțin în întregul bloc de memorie,
sistemul de operare este de gând să-i dea întregului 4 kilobytes.
Deci, ce înseamnă acest lucru este că ar putea avea - să spunem acest lucru este stack-ul meu.
Acest lucru ar putea fi separate stivă. Stack-ul meu ar putea fi megaocteți și megaocteți.
Stack-ul meu ar putea fi imens.
Dar stiva însăși trebuie să fie împărțită în pagini individuale,
care, dacă ne uităm la peste aici să spunem că aceasta este RAM noastră,
daca am 2 GB de RAM, aceasta este 0 adresa reală ca octet zero de RAM meu,
și acest lucru este de 2 gigaocteți tot până aici.
Deci aceasta pagina s-ar putea să corespundă acestei bloc de aici.
Această pagină ar putea să corespundă acestei bloc de aici.
Acest lucru s-ar putea să corespundă asta de aici.
Deci, sistemul de operare este liber să atribuie memorie fizică
la orice pagină individ arbitrar.
Și asta înseamnă că, dacă acest lucru se întâmplă pentru a frontierei călare o matrice,
o matrice se întâmplă să fi lăsat de acest lucru si drept de acest ordin a unei pagini,
atunci matrice va fi împărțită în memorie fizică.
Și apoi, când te-ai lăsat programului, atunci când procesul se termină,
aceste mapări obține șters și apoi este liber să utilizeze aceste blocuri mici pentru alte lucruri.
Mai multe întrebări?
[Elev] indicatorul aritmetică. Oh, da >>.
Siruri de caractere au fost mai usor, dar se uită la ceva de genul Ints,
Deci, înapoi la int x [4];
Dacă aceasta este o matrice sau dacă este un pointer la o matrice malloced de 4 numere întregi,
o să fie tratate în același mod.
[Elev] Deci, matrice sunt pe heap?
[Bowden] Matricile nu sunt pe heap. >> [Elev] Oh.
>> [Bowden] Acest tip de matrice tinde să fie pe stiva
dacă nu a declarat la - ignorarea variabile globale. Nu folosiți variabile globale.
În interiorul unei funcții spun int x [4];
Se va crea un bloc de 4-întreg pe stivă pentru această matrice.
Dar acest malloc (4 * sizeof (int)); este de gând să meargă pe heap.
Dar, după acest moment pot folosi x si p destul de mult, în aceleași moduri,
altele decât excepțiile am spus înainte despre Puteți realoca p..
Punct de vedere tehnic, dimensiunile lor sunt oarecum diferite, dar asta e complet irelevant.
Niciodată nu folosi de fapt dimensiunile lor.
P. I-ar putea spune p [3] = 2; sau x [3] = 2;
Aveți posibilitatea să le utilizeze în exact aceleași moduri.
Deci, aritmetică indicatorul acum - Da.
[Elev] Nu trebuie să faci p *, dacă aveți paranteze?
Paranteze sunt o dereference implicite. Bine >>.
De fapt, de asemenea, ce vrei să spui cu poate te tablouri multidimensionale
cu indicii, ceea ce se poate face este ceva de genul, să spunem, int ** pp = malloc (sizeof (int *) * 5);
Voi scrie doar totul mai întâi.
Nu am vrut asta.
Bine.
Ceea ce am făcut aici este - Asta ar trebui să fie puncte procentuale [i].
Deci, pp este un pointer la un pointer.
Te mallocing puncte procentuale, pentru a indica o serie de 5 stele int.
Deci, în memoria aveți pe pp. stivă
O să indice o serie de 5 blocuri, care sunt toate s-au pointeri.
Și apoi, când am malloc aici, am malloc că fiecare dintre aceste indicii individuale
ar trebui să indice către un bloc separat de 4 octeți pe heap.
Deci, acest puncte de la 4 octeți.
Și aceasta puncte la un alt 4 octeți.
>> Și toate dintre ele indica propriile 4 octeți.
Acest lucru dă-mi o modalitate de a face lucruri multidimensionale.
Am putea spune pp [3] [4], dar acum acest lucru nu este același lucru ca tablouri multidimensionale
deoarece tablouri multidimensionale a tradus [3] [4] într-un singur diferența în matrice x.
Acest p. dereferences, accesează indicele treia, atunci dereferences că
și de acces - 4 ar fi invalidă - indicele de secunde.
Întrucât, atunci când am avut int x [3] [4] înainte de a ca o matrice multidimensional
și atunci când faceți dublu suport este într-adevăr doar un singur dereference,
te în urma unui pointer unic și apoi un offset,
aceasta este într-adevăr referințele 2D.
Urmați 2 pointeri separate.
Deci, acest punct de vedere tehnic, de asemenea, vă permite să aveți tablouri multidimensionale
în cazul în care fiecare individ este matrice de diferite dimensiuni.
Deci, eu cred că tablouri multidimensionale zimțate este ceea ce se numește
într-adevăr, deoarece primul lucru pe care ar putea să indice ceva care are 10 de elemente,
al doilea lucru ar putea indica ceva care are 100 de elemente.
[Elev] Exista vreo limita la numarul de indicii puteți avea
arătând spre alte indicii? Nu >>
Puteți avea int ***** p..
Înapoi la aritmetică indicatorul - >> [elev] Oh. Da >>.
[Elev] Dacă am int *** p și apoi să fac o dereferencing și spun * p este egal cu această valoare,
este doar de gând să facă un nivel de dereferencing? Da >>.
Deci, dacă vreau să acceseze lucru care indicatorul este îndreptat la ultima -
Apoi te faci p ***. Bine >>.
Deci, aceasta este de puncte p la 1 bloc, punctele de la un alt bloc, punctele de la un alt bloc.
Apoi, dacă faci * p = altceva, atunci se schimbă această
pentru a indica acum la un bloc diferit. Bine >>.
>> [Bowden] Iar dacă acestea au fost malloced, apoi s-au scurs de memorie acum
excepția cazului în care se întâmplă să aibă referințe diferite ale acestor
din moment ce nu se poate obține înapoi la acelea pe care tocmai l-ați aruncat.
Pointer aritmetică.
int x [4]; este de gând să aloce o serie de 4 numere întregi
unde x este de gând să indice începutul matrice.
Asa ca atunci cand spun ceva de genul x [1], vreau să însemne merge la întreg doua matrice,
care ar fi acesta.
Dar de fapt, asta e 4 octeți în matrice, deoarece acest număr întreg durează până la 4 octeți.
Deci, un offset de 1 înseamnă cu adevărat un offset de 1
ori dimensiunea indiferent de tipul de matrice este.
Acesta este un tablou de întregi, așa că știe să facă de 1 ori marimea int atunci când vrea să le compenseze.
Alte sintaxa. Amintiți-vă că acest lucru este echivalent cu * (x + 1);
Când spun indicatorul + 1, ceea ce este care returnează adresa care indicatorul este stocarea
plus 1 de ori dimensiunea de tipul de pointer.
Deci, daca x = ox100, atunci x + 1 = ox104.
Și vă puteți abuza de acest lucru și spune ceva de genul char * c = (char *) x;
iar acum c este de gând să fie aceeași adresă ca și x.
C va fi egală cu ox100,
dar C + 1 va fi egal cu ox101
deoarece aritmetică indicatorul depinde de tipul de indicatorul pe care îl adăugați la.
Deci, C + 1, se pare c la, este un pointer char, asa ca va adăuga 1 ori dimensiunea char,
care este întotdeauna o să fie de 1, astfel încât să obțineți 101,
întrucât, dacă fac x, care este, de asemenea, încă 100, x + 1 va fi 104.
[Elev] Poți folosi C + +, în scopul de a avansa indicatorul de 1?
Da, poți.
Nu puteți face asta cu x, deoarece x este doar un simbol, este o constantă, nu se poate schimba x.
>> Dar C se întâmplă să fie doar un pointer, deci c + + este perfect valabilă și se va incrementa cu 1.
Dacă c au fost doar o int *, apoi C + + ar fi 104.
+ + Are aritmetică indicatorul la fel ca C + 1 ar fi făcut aritmetică indicatorul.
Acesta este de fapt modul în care o mulțime de lucruri, cum ar fi un fel de îmbinare -
În loc de a crea copii de lucruri, puteți trece în schimb -
Ca și în cazul în care am vrut să treacă această jumătate din matrice - hai să șteargă o parte din aceasta.
Să spunem că am vrut să treacă această parte a matrice într-o funcție.
Ce mi-ar trece la această funcție?
Dacă eu trec x, am trecut de această adresă.
Dar eu vreau să treci această adresă special. Deci, ce ar trebui să treacă?
[Elev] Pointer + 2?
[Bowden] Deci x + 2. Da.
Asta va fi această adresă.
Veți de asemenea, foarte frecvent, o văd ca pe x [2] și apoi adresa asta.
Deci, aveți nevoie pentru a lua adresa de ea, deoarece suportul este o dereference implicită.
x [2] se referă la valoarea care este în această casetă, și apoi doriți adresa acea cutie,
asa ai spus si x [2].
Deci asta e modul în care ceva intr-un fel de îmbinare în cazul în care doriți să treci jumătate din lista de la ceva
într-adevăr doar treci & x [2], iar acum în ceea ce privește apelul recursiv este în cauză,
matrice noul meu începe acolo.
Întrebări last minute.
[Elev] Dacă nu vom pune un ampersand sau - ceea ce e numit? Steaua >>?
[Elev] stele. >> Punct de vedere tehnic, operatorul dereference, dar - >> [elev] dereference.
>> Dacă nu vom pune o stea sau un ampersand, ce se întâmplă dacă eu spun doar y = x si x este un pointer?
Care este tipul de y? >> [Elev] Voi spune doar că e indicatorul 2.
Deci, dacă spunem că y = x, x acum și punctul y la același lucru. >> [Elev] Punctul pentru același lucru.
Și dacă x este un pointer int? Aceasta ar plânge >> pentru că nu se poate atribui pointeri.
[Elev] Ok.
Amintiți-vă că indicii, chiar dacă le-am trage cu săgeți,
într-adevăr toate acestea magazin - int * x - x este într-adevăr toate stocarea e ceva de genul ox100,
care se întâmplă să reprezinte ca semn de blocul stocate la 100.
Deci, atunci când spun int * y = x; Eu doar copierea ox100 în Y,
pe care suntem doar de gând să reprezinte ca y, de asemenea, arătând spre ox100.
Și dacă eu spun int i = (int) x; apoi i se va stoca orice valoare a ox100 este
în interiorul acestuia, dar acum va fi interpretată ca un întreg în loc de un pointer.
Dar ai nevoie de turnat sau altceva se va plânge.
[Elev] Deci vrei să spui să arunce -
Este de gând să fie turnare int de int x sau y turnare a?
[Bowden] Ce?
[Elev] Ok. După aceste paranteze este acolo va fi un x sau ay acolo?
>> [Bowden] Fie. x și y sunt echivalente. >> [Elev] Ok.
Pentru că sunt atât pointeri. Da >>.
[Elev] Deci, s-ar păstra hexazecimal 100 în formă întreg? >> [Bowden] Da.
Dar nu valoarea a ceea ce se arată la.
[Bowden] Da. >> [Elev] Deci, doar adresa în formă întreg. Bine.
[Bowden] Dacă vrei să bizar pentru un motiv oarecare,
ai putea face exclusiv cu pointeri și niciodată a face cu numere întregi
și să fie la fel ca int * x = 0.
Atunci ai de gând să obțineți cu adevărat confuz dată aritmetică indicatorul incepe sa se intample.
Deci numerele pe care le stochează sunt lipsite de sens.
E doar modul în care ajunge să le interpreteze.
Deci, eu sunt liber să copiați ox100 de la un * int la un int,
si eu sunt liber să atribuie - Esti, probabil, va fi țipat la turnare pentru a nu -
Sunt liber pentru a atribui ceva de genul (int *) * ox1234 în acest int arbitrară.
Deci, ox123 este la fel de valabil o adresă de memorie așa cum este și y.
& Y se întâmplă să se întoarcă ceva care este destul de mult ox123.
[Elev] Ar fi ca un mod foarte misto de a merge la hexazecimal pentru a forma zecimală,
ca în cazul în care aveți un pointer și l-ați aruncat ca un int?
[Bowden] Puteți imprima folosind de fapt doar ca printf.
Să spunem că am int y = 100.
Deci printf (% d \ n - așa cum ar trebui să știi deja - că tipărarea ca un întreg, x%.
Vom imprima doar ca hexazecimal.
Deci, un pointer nu este stocată ca hexazecimal,
și un întreg nu este stocat ca zecimal.
Totul este stocat ca un binar.
E doar că avem tendința de a vedea indicii ca hexazecimal
pentru că ne gândim la lucruri din aceste blocuri 4-byte,
și adresele de memorie tind să fie familiarizați.
Suntem ca, în cazul în care începe cu BF, apoi se întâmplă să fie pe stiva.
Deci e doar interpretarea noastră de pointeri ca hexazecimal.
Bine. Alte întrebări ultimele?
>> Voi fi aici pentru un pic după ce, dacă aveți altceva.
Și asta e sfârșitul acelui.
>> [Elev] Yay! [Aplauze]
>> [CS50.TV]