[Powered by Google Translate] [Săptămâna 4] [David J. Malan] [Universitatea Harvard] [Acest lucru este CS50.] [CS50.TV] Bine, asta este CS50, iar acest lucru este începutul săptămânii 4, și acesta este unul dintre algoritmii de sortare cel mai lent posibil. Care dintre fost că ne-am privit acolo? Asta a fost un fel balon, în scopul de Big O (n ^ 2) + suma, și într-adevăr, nu suntem singurii în această lume pentru a par să știe ce fel bubble este sau timpul său de funcționare. Într-adevăr, aceasta a fost un interviu cu Eric Schmidt de la Google si fostul senator american Barack Obama la doar câțiva ani în urmă. Acum, senatorul, ești aici de la Google, și îmi place să mă gândesc la președinția ca un interviu de angajare. Acum, e greu pentru a obține un loc de muncă în calitate de președinte, și tu te duci prin rigorile acum. Este, de asemenea, greu pentru a obține un loc de muncă la Google. Avem întrebări, și ne pune întrebări candidaților noștri, si aceasta este de la Larry Schwimmer. Voi credeți că glumesc? E chiar aici. Care este cel mai eficient mod de a sorta un milion de numere întregi pe 32 de biți? [Râsete] Bine- Îmi pare rău >> Nu, nu, nu, nu.. Cred ca ar fi un fel bula mod greșit de a merge. Haide, care ia spus asta? Săptămâna trecută, amintesc am luat o pauza de la cod, cel puțin pentru o zi, și a început concentrându-se pe unele idei de nivel superior și de rezolvare a problemelor, în general, mai mult în contextul căutare și sortare, și am introdus ceva ce nu am palmă acest nume pe săptămâna trecută, dar notația asimptotică, Big O, Omega Big, și, uneori, Big notația Theta, și acestea au fost pur și simplu moduri de a descrie timpul de rulare al algoritmilor, cât de mult timp este nevoie pentru a rula un algoritm. Și poate vă amintiți că ați vorbit despre timpul de execuție în ceea ce privește dimensiunea de intrare, pe care noi o numim, în general, n, oricare ar fi problema poate fi, unde n este numărul de persoane în cameră, numărul de pagini dintr-o carte de telefon, și am început să scrie lucruri cum ar fi O (n ^ 2) sau O (n) sau O (n log n), și chiar și atunci când matematica nu a mers prea bine atât de perfect și a fost n ² - n / 2 sau ceva de genul asta în schimb ne-ar arunca pur și simplu o parte din termenii de ordine inferioare, și motivația nu este ca ne dorim cu adevarat o un fel de mod obiectiv de evaluare performanța programelor sau performanța algoritmilor faptul că, la sfârșitul zilei nu are nimic de a face, de exemplu, cu viteza de computer de astăzi. De exemplu, dacă ați pune în aplicare sortare cu bule, sau te pună în aplicare îmbinarea sortare sau o selecție sortare pe calculatorul de astăzi, un calculator 2 GHz, și tu-l executați, și este nevoie de un numar de secunde, anul viitor e un GHz 3 sau un 4 GHz calculator, și s-ar putea pretinde apoi că "Wow, mi algoritm este acum de două ori mai repede, "atunci când, în realitate, că nu e în mod evident cazul. E doar hardware-ul a devenit mai rapid, dar computerului a nu, și așa dorim cu adevărat să arunce lucruri, cum ar fi multipli de 2 sau multiplu de 3 atunci când vine vorba de a descrie cât de repede sau cât de încet un algoritm este și într-adevăr să se concentreze doar pe n sau un factor al acestuia, o anumită putere a acestora, în cazul felul de săptămâna trecută. Și reamintească faptul că, cu ajutorul fel de fuziune noi am fost capabil sa faca acest lucru mult mai bine decât sortare cu bule și sortare selecție și chiar și inserarea de sortare. Am ajuns la n log n, și, din nou, Reamintim că log n general, se referă la ceva care creste mai lent, apoi n, deci n log n până acum a fost bun pentru că a fost mai puțin ² n. Dar pentru a realiza n log n cu un fel de îmbinare ceea ce a fost germenul de bază a unei idei pe care am avut să impulsioneze că am, de asemenea, extinse la nivel înapoi în săptămâna 0? Cum am aborda problema de sortare ingenios cu un fel de îmbinare? Care a fost cheia înțelegere, poate? Oricine deloc. Bine, hai să facem un pas înapoi. Descrieți îmbinare de sortare în propriile tale cuvinte. Cum a mers? Bine, ne vom rândul inapoi la 0 săptămână. Bine, da. [Imperceptibil-elev] Bine, bine, așa că am împărțit matrice de numere în 2 bucăți. Am sortat fiecare dintre aceste piese, iar apoi le-am fuzionat, și am văzut această idee înainte de a lua o problemă care este atât de mare și tocare-l într-o problemă care este atât de mare sau atât de mare. Amintiți-exemplu cartea de telefon. Amintiți-algoritm de auto-numărare de săptămâni în urmă, sortare, astfel îmbinare a fost rezumată de acest pseudocod aici. Când ești dat n elemente, în primul rând a fost bun-simț verifica. Dacă n <2, atunci nu faci nimic, la toate pentru că dacă n <2, atunci n este, evident, 0 sau 1, și, deci, dacă e 0 sau 1 nu e nimic pentru a sorta. Ai terminat. Lista dvs. este deja sortat trivial. Dar altfel, dacă ai 2 sau mai multe elemente mergeți mai departe și împărțiți-le in 2 jumatati, la stânga și la dreapta. Sorteaza fiecare dintre aceste jumatati, iar apoi îmbinați jumatati sortate. Dar problema aici este faptul că, la prima vedere, acest lucru se simte ca și cum suntem punting. Aceasta este o definiție circulară în care, dacă v-am rugat a sorta aceste elemente n și tu îmi spui "Bine, bine, vom sorta aceste elemente n / 2 și cele N / 2," atunci urmatoarea mea intrebare va fi "Bine, cum vrei să sortați n / 2 elemente?" Dar, din cauza structurii acestui program, pentru că nu există acest caz de bază, ca să spunem așa, acest caz special care spune că, dacă n este > Sara, bine. Kelly. >> Kelly și? Willy. >> Willy, Sara, Kelly, și Willy. Chiar acum am fost întrebat de cineva cât de mulți oameni sunt pe această scenă, și nu am nici o idee. Aceasta este o listă foarte lungă, și astfel în loc să am de gând să fac acest truc. Mă duc să întreb persoana de lângă mine să fac cea mai mare parte de lucru, și o dată ea se face face de cele mai multe de lucru Am de gând să fac cel puțin suma de munca este posibil și se adaugă la doar 1 la orice răspunsul ei este, așa că aici vom merge. Am fost întrebat câți oameni sunt pe scena. Câți oameni sunt pe scenă la stânga de tine? Stânga de mine >> Ok?, Dar nu ieftin. Asta e bine, e corect, dar dacă vrem să continuăm această logică Să presupunem că vă doriți să similar punt această problemă la stânga de tine, Deci, mai degrabă decât răspunsul merge direct mai departe și să treacă doar dolar. Oh, cât de mulți oameni sunt la stânga de mine? Cât de mulți oameni sunt la stânga? 1. [Râsete] Ok, deci 0, deci ceea ce a făcut acum Willy te-ai întors răspunsul această direcție spunând 0. Acum, ce ar trebui să faci? >> 1. Bine, deci tu ești 1, asa ai spus, "Bine, am de gând să adăugați 1 la orice număr Willy a fost, "așa 1 + 0. Ești acum 1 atât de răspunsul dumneavoastră la dreapta este acum- 1. >> Si a mea ar fi 2. Bine, deci tu iei răspunsul anterior de 1, adăugând cantitatea minimă de muncă vrei să faci, ceea ce este un. Aveți acum 2, și tu dai apoi mi care valoarea? 3, vreau să spun, îmi pare rău, 2. Bine. Ei bine, am avut de la 0 la stânga. Apoi am avut 1, iar apoi adăugăm 2, si acum esti predarea-mi numărul 2, și așa spun, bine, +1, 3. E într-adevăr, 3 persoane în picioare lângă mine pe această scenă, asa ca am fi putut face, evident, acest lucru foarte liniar, foarte mult în modă evident, dar ceea ce am făcut cu adevărat? Am luat o problemă de dimensiune 3 inițial. Noi l-am rupt în jos într-o problemă de dimensiune 2, apoi o problema de dimensiune 1, și apoi în cele din urmă scenariul de bază a fost într-adevăr, oh, nu e nimeni acolo, moment în care a revenit în mod eficient Willy un răspuns hard-coded de cateva ori, iar al doilea a fost apoi barbotat sus, bule de aer în sus, barbotat sus, și apoi, prin adaugarea in aceasta suplimentară 1 am implementat această idee de bază a recursivitate. Acum, în acest caz nu a rezolvat într-adevăr o problemă mai eficient, atunci l-am văzut până acum. Dar gândește-te la algoritmii care le-am făcut pe scenă până acum. Am avut 8 bucăți de hârtie pe tablă, pe video atunci când Sean a fost în căutarea pentru numărul 7, și ce a făcut el chiar nu? Ei bine, el nu a făcut nici un fel de divide et impera. El nu a făcut nici un fel de recursivitate. Mai degrabă el a făcut doar acest algoritm liniar. Dar când am introdus ideea de numere sunt sortate pe scenă trăiesc săptămâna trecută atunci am avut acest instinct de a merge la mijloc, moment în care am avut o listă mai mică de mărimea 4 sau o altă listă de marimea 4, și apoi am avut exact aceeași problemă, așa că am repetat, repetat, repetat. Cu alte cuvinte, ne recursed. Vă mulțumesc foarte mult pentru cele 3 voluntari aici pentru a demonstra recursivitate cu noi. Să vedem dacă nu putem face asta acum concret un pic mai mult, rezolvarea unei probleme pe care din nou, am putea face destul de ușor, dar ne vom folosi ca o piatră de temelie pentru punerea în aplicare a acestei idei de bază. Dacă vreau să calculeze însumarea o grămadă de numere, de exemplu, dacă treci în numărul 3, Vreau să vă dau valoarea sigma 3, astfel încât suma de 3 + 2 + 1 + 0. Vreau să mă întorc răspunsul 6, așa că vom pune în aplicare această funcție Sigma, această funcție însumării că, din nou, ia în intrare, iar apoi returnează însumarea din acest număr tot drumul până la 0. Am putea face acest lucru destul de simplu, nu? Am putea face acest lucru cu un fel de structură looping, asa ca lasa-ma sa plec mai departe și a obține acest început. Include stdio.h. Lasă-mă să mă ajunge în principal pentru a lucra cu aici. Să salvăm acest lucru ca sigma.c. Apoi, am de gând să merg aici, și am de gând să o declare un int n, și am de gând să fac următoarele în timp ce utilizatorul nu cooperează. În timp ce utilizatorul nu mi-a dat un număr pozitiv lasă-mă să merg mai departe și cere-le pentru n = GetInt, și lasă-mă să le dau niște instrucțiuni cu privire la ce să fac, astfel încât printf ("număr întreg pozitiv vă rugăm"). Doar ceva relativ simplu, așa astfel încât, până când am lovit linia 14 acum avem un număr întreg pozitiv, probabil, în nr. Acum, hai să facem ceva cu ea. Lasă-mă să merg mai departe și calcula însumarea, astfel încât suma intre int = sigma (n). Sigma este doar însumarea, așa că eu sunt doar scris, în mod crescator. Vom numi doar sigma acolo. Asta e suma, iar acum am de gând să imprima rezultatul, printf ("Suma este% d \ n", suma). Și apoi voi întoarce 0 pentru o bună măsură. Am făcut tot ceea ce presupune acest program, cu excepția partea interesantă, care este de a pune în aplicare, de fapt funcția sigma. Lasă-mă să merg aici la partea de jos, și lasă-mă să declare funcția sigma. Trebuie sa ia o variabilă care este de tip întreg, și ce tip de date vreau să se întoarcă probabil de la Sigma? Int, pentru că vreau să se potrivească așteptărilor mele pe linia 15. În aici, lasă-mă să merg mai departe și punerea în aplicare a prezentei într-un mod destul de simplu. Să mergem mai departe și să spunem suma intre int = 0, și acum am de gând să merg avea un pic de buclă aici care va spune ceva de genul asta, pentru (int i = 0; i <= număr; i + +) + = i suma intre. Și apoi am de gând să se întoarcă suma intre. Am fi putut puse în aplicare acest lucru în orice număr de moduri. Am fi putut folosi o buclă în timp ce. Aș fi putut să omit folosind variabila suma în cazul în care am vrut să, dar pe scurt, avem doar o funcție care, dacă nu am făcut-Cea mai mare greseala declară suma intre este 0. Apoi, iterează la 0 pe sus, prin numărul, și pe fiecare iterație se adaugă faptul că valoarea actuală a sumei și apoi returnează suma intre. Acum, există o optimizare ușoară aici. Acesta este, probabil, un pas pierdut, dar așa să fie. Asta e bine pentru moment. Suntem cel puțin a fi aprofundată și merge 0 tot drumul pe sus. Nu este foarte greu și destul de simplă, dar se pare că, odată cu funcția de sigma avem aceeași oportunitate așa cum am făcut-o aici, pe scenă. Pe scenă ne-am numărat câți oameni au fost alături de mine, dar în schimb, dacă ne-am dorit pentru a contoriza numărul 3 + 2 + 1 privind în jos la 0 am putut în mod similar barca la o funcție pe care o voi descrie în loc ca fiind recursivă. Aici sa facem o verificare rapidă bun-simț și asigurați-vă că nu am făcut-o prost. Știu că e cel puțin un lucru în acest program pe care eu am făcut greșit. Când m-am lovit introduceți am de gând pentru a obține orice fel de țipi la mine? Ceea ce am de gând să fie strigat la aproximativ? Da, am uitat prototipul, asa ca am folosind o functie numita Sigma pe linia 15, dar nu este declarată până la linia 22, așa că am cel mai bun mod proactiv merge aici și declară un prototip, iar eu voi spune int Sigma (int numar), și asta e tot. Este implementat la partea de jos. Sau un alt modul în care am putea rezolva acest lucru, Aș putea muta funcția de acolo, ceea ce nu este rău, dar cel puțin atunci când programele încep pentru a obține lung, sincer, Cred că e ceva în valoare de având în principal întotdeauna în partea de sus astfel încât să în cititorul poate deschide fișierul și apoi să vedem imediat ceea ce face programul, fără a fi nevoie să căutați prin ea In cautare de faptul că funcția principală. Să mergem la fereastră terminal mea aici, încercați să fac Sigma Sigma, si am dat-on bară aici. Declarația implicită a funcției GetInt înseamnă că am uitat să fac ce altceva? [Imperceptibil-elev] Bine, deci se pare o greșeală comună, asa ca hai sa pun asta aici, cs50.h, și acum să ne întoarcem la fereastra terminalul meu. Voi goli ecranul, iar eu voi face reluare sigma. Se pare că s-au compilat. Lasă-mă să fugi acum sigma. Voi tastați în numărul 3, și eu am primit 6, deci nu un cec riguros, dar cel puțin se pare a fi de lucru la prima vedere, dar acum hai sa-l rupe în afară, și să pârghie de fapt, ideea de recursivitate, din nou, într-un context foarte simplu, astfel încât, în câteva săptămâni " atunci când vom începe explorarea structurilor de date mai frumoase decât matrice avem un alt instrument în set de instrumente cu care să manipula aceste structuri de date așa cum vom vedea. Aceasta este abordarea iterativă, abordarea bazată pe bucla. Lasă-mă în loc să fac asta acum. Permiteți-mi să spun că în loc însumarea numărului privind în jos la 0 este într-adevăr același lucru ca și Numărul + Sigma (număr - 1). Cu alte cuvinte, la fel ca și pe scenă am degajată la fiecare dintre oamenii de lângă mine, și aceștia, la rândul păstrat punting până când vom în cele din urmă durat până la Willy, care a trebuit să se întoarcă un răspuns hard-coded ca 0. Aici, acum suntem la fel punting la Sigma aceeași funcție ca și a fost inițial numit, dar perspectiva cheie aici este faptul că nu suntem de asteptare sigma identic. Noi nu suntem în trecere nr. Suntem în mod clar trecerea la număr - 1, astfel încât o problemă puțin mai mic, puțin mai mică problemă. Din păcate, acest lucru nu este destul de o soluție încă, și înainte de a ne repara ceea ce ar putea fi sărind ca evident, la unii dintre voi lasă-mă să merg mai departe și reluare a face. Se pare că pentru a compila bine. Lasă-mă să rulați din nou cu 6 sigma. Hopa, lasă-mă să rulați din nou cu 6 sigma. Am văzut acest lucru înainte, deși timpul accidental trecut. De ce am primit această eroare de segmentare criptic? Da. [Imperceptibil-elev] Nu e nici un caz de bază, și, mai precis, ceea ce probabil sa întâmplat? Acesta este un simptom a ceea ce comportament? Spune-o un pic mai tare. [Imperceptibil-elev] E o buclă infinită în mod eficient, iar problema cu bucle infinite atunci când acestea implică recursivitate în acest caz, o funcție în sine de asteptare, ceea ce se întâmplă de fiecare dată când apelați o funcție? Ei bine, cred că înapoi la modul în care am pus afară de memorie într-un computer. Am spus că există această bucată de memorie numit stiva care este în partea de jos, și de fiecare dată când apelați o funcție de memorie un pic mai mult se pune pe această stivă așa-numitul conține variabile care functioneaza despre locale sau parametri, așa că, dacă sigma sigma sigma Apeluri solicită sigma  solicită, în cazul în care se sigma acest scop poveste? Ei bine, în cele din urmă depășiri suma totală de memorie pe care le au la dispoziție la computer. Ai depășit segmentul pe care tu ar trebui să rămână în cadrul, și veți obține acest defect segmentare, miez fac obiectul unui dumping, și ce înseamnă de bază fac obiectul unui dumping este că am acum un fișier numit miez care este un fișier care conține zerouri și cele că, de fapt, în viitor, va fi folositoare pentru diagnostic. Dacă nu e evident pentru tine în cazul în care bug-ul dvs. este puteți face de fapt, un pic de analiza medico-legală, ca să spunem așa, în acest dosar benă de bază, care, din nou, este doar o grămadă de zerouri și cele care reprezintă în esență, starea programului în memorie momentul în care sa prăbușit în acest fel. Fix aici este că nu putem pur și simplu întoarce orbește sigma, numărul + sigma de o problemă puțin mai mică. Avem nevoie de a avea un fel de scenariul de bază aici, și ceea ce ar trebui să fie, probabil, cazul de bază? [Imperceptibil-elev] Bine, atâta timp cât numărul este pozitiv ar trebui să ne întoarcă de fapt acest lucru, sau, altfel spus, dacă numărul este, să spunem, <= cu 0 Știi ce, voi merge mai departe și să se întoarcă 0, la fel ca Willy făcut, și altceva, am de gând să merg mai departe și să se întoarcă acest lucru, așa că nu e mult mai scurtă decât versiunea iterativ care am incitat folosind mai întâi un pentru buclă, dar observați că există acest tip de eleganță să-l. În loc de a se întoarce un numar si efectuarea toate astea matematica și adăugarea de lucrurile cu variabilele locale tu spui în loc "Bine, dacă aceasta este o problemă foarte ușor, ca numărul este <0, permiteți-mi să se întoarcă imediat 0. " Noi nu suntem de gând să deranjez numere de sprijin negative, așa că am de gând să codul de greu valoarea 0. Dar altfel, să pună în aplicare această idee de însumând toate aceste numere împreună puteți face în mod eficient o muscatura mic din problema, la fel ca am facut aici pe scenă, apoi punt restul de problema următoarea persoană, dar, în acest caz, următoarea persoană este singur. Este o funcție identic pe nume. Doar treci o problemă mai mică și mai mică și mai mică de fiecare dată, și chiar dacă nu avem lucruri destul de formalizate în codul aici acest lucru este exact ceea ce se întâmplă în săptămâna 0, cu cartea de telefon. Acest lucru este exact ceea ce se întâmplă în ultimele săptămâni cu Sean și cu demonstrații noastre de căutare pentru numere. Este de a lua o problemă și împărțind-o din nou și din nou. Cu alte cuvinte, există o modalitate de a traduce acum acest construct lumea reală, această construcție nivel superior de dezbina si cucereste și de a face ceva nou și din nou în cod, astfel încât aceasta este ceva ce se va vedea din nou-a lungul timpului. Acum, ca o paranteză, dacă sunteți nou la recursia ar trebui să înțeleagă cel puțin acum de ce acest lucru este amuzant. Am de gând să merg la google.com, și am de gând pentru a căuta câteva sfaturi și trucuri despre recursivitate, introduceți. Spune-i persoanei de lângă tine, dacă acestea nu au fost doar râd acum. Ați vrut să spuneți recursivitate? Ați vrut să spuneți-ah, acolo mergem. Ok, acum că e restul de toată lumea. Un pic de ou de Paști inglobate undeva acolo în Google. Ca o paranteza, unul dintre link-urile de pe site-ul am pus cursului pentru ziua de azi este doar această grilă de algoritmi de sortare diferite, dintre care unele ne-am uitat la saptamana trecuta, dar ce e frumos despre această vizualizare în timp ce încerca să-și încheie în jurul valorii de mintea ta diverse lucruri legate de algoritmi știți că puteți foarte ușor începe acum, cu diferite tipuri de intrări. Intrarile toate inversat, cea mai mare parte a intrărilor sortate, intrările aleatoare și așa mai departe. În timp ce încerca să, din nou, distinge aceste lucruri în mintea ta dau seama că acest URL pe site-ul cursului pe pagina Prelegeri s-ar putea ajuta să vă motiv, prin unele dintre cele. Astăzi vom ajunge în cele din urmă pentru a rezolva această problemă dintr-o înapoi în timp, care a fost faptul că această funcție de swap pur si simplu nu au de lucru, și ceea ce a fost problema fundamentală cu acest swap funcție, scopul care a fost, din nou, să facă schimb de o valoare aici si aici astfel că se întâmplă acest lucru? Acest lucru nu lucrează efectiv. De ce? Da. [Imperceptibil-elev] Exact, explicația pentru acest bugginess pur și simplu pentru că a fost atunci când apelați funcții în C și funcțiile respective să ia argumente, ca a si b aici, te trec în copiile, indiferent de valoarea pe care o oferi la această funcție. Tu nu sunt furnizarea de valorile inițiale s-au, așa că am văzut acest lucru în contextul buggyc, buggy3.c, care a analizat ceva de genul asta. Amintiți-vă că am avut x și y inițializat la 1 și 2, respectiv. Apoi am imprimat ceea ce au fost. Apoi am susținut că am fost le-swapping sunand de swap x, y. Dar problema era că schimbarea a lucrat, dar numai în domeniul de aplicare al swap-sine funcționa. De îndată ce ne-am lovit linia 40 aceste valori schimbate s-au aruncat, și așa mai nimic în funcția originală principal a fost schimbat de fapt, la toate, așa că, dacă vă gândiți la ceea ce atunci, ca acest lucru arata ca in ceea ce priveste memoria noastră în cazul în care această partea stângă a consiliului reprezintă, și voi face meu cel mai bun pentru toată lumea să vadă acest-ar fi dacă această partea stângă a plăcii reprezintă, să zicem, RAM-ul, iar stiva este de gând să crească pe sus în acest fel, și am apela o funcție cum ar fi principal, și principalele are 2 variabile locale, x și y, Să descrie pe cei ca x aici, și să descrie aceste ca y aici, și să punem în valorile pe 1 și 2, astfel încât acesta este principalul aici, și atunci când solicită principal funcția de swap sistemul de operare dă funcția de swap cărare proprie de memorie pe stiva, rama proprie pe stiva, ca să spunem așa. Se alocă, de asemenea, 32 de biți pentru aceste Ints. Se întâmplă să le numim A și B, dar asta e cu totul arbitrar. Le-ar fi numit orice ar vrea, dar ce se întâmplă atunci când principalul de swap solicită este nevoie de acest lucru 1, pune o copie acolo, pune o copie acolo. Există 1 altor variabile locale în schimb, deși, numit ce? Tmp >>. Tmp, asa ca lasa-ma da eu încă 32 de biți de aici, și ceea ce am făcut în această funcție? I-am spus tmp int devine o, astfel încât o are 1, așa că am făcut acest lucru când am jucat cu ultima acest exemplu. Atunci devine b, deci b este 2, așa că acum aceasta devine 2, și acum B devine temperatură, deci temperatura este de 1, deci acum B devine asta. Asta-i grozav. Ea a lucrat. Dar apoi, de îndată ce se întoarce funcția Memoria de swap în mod eficient dispare, astfel încât să poată fi reutilizate printr-o altă funcție, în viitor, și, evident, principalul este complet neschimbat. Avem nevoie de o modalitate de rezolvare a acestei probleme fundamental, iar astăzi vom avea în sfârșit o modalitate de a face acest lucru, prin care putem introduce ceva numit un pointer. Se pare că putem rezolva această problemă nu prin trecerea în copii ale lui x și y ci prin trecerea in ceea ce, crezi că, la funcția de swap? Da, ceea ce despre adresa? Noi nu prea am vorbit despre adresele de mai multe detalii, dar dacă această tablă reprezintă memoria computerului meu am putea începe cu siguranță, numerotarea octeți în memoria RAM mea și spun acest lucru este octet # 1, acesta este octetul # 2, # 3 Octet, octet # 4, # Octet ... 2 miliarde EUR dacă am 2 GB de RAM, asa ca am putea veni cu siguranta cu o schema de numerotare arbitrare pentru toți octeții individuale în memoria computerului meu. Ce se întâmplă dacă în schimb când eu numesc de swap mai degrabă decât trecere în copii ale lui x și y de ce nu trec în locul în adresa lui x aici, adresa lui y aici, în esență, adresa poștală lui x și y, deoarece swap, în cazul în care el este informat a adresa în memoria lui x și y, apoi schimba, dacă ne-am antrenat-l un pic, el ar putea conduce, potențial, la acea adresă, ca să spunem așa, x, și de a schimba numărul de acolo, conduce apoi la adresa de Y, modifica numărul de acolo, chiar și atunci când nu primesc de fapt, copii ale acestor valori el însuși, Deci, chiar daca am vorbit despre acest lucru ca fiind memoria principală a lui și acest swap ca fiind memoria puternic și partea periculoasă a C este că orice funcție poate atinge memoria oriunde în calculator, și acest lucru este puternic, în care poți face lucruri foarte fancy, cu programe de calculator în C. Acest lucru este periculos deoarece puteți bară de asemenea, foarte usor. De fapt, una dintre cele mai comune modalități de programe în aceste zile pentru a fi exploatate încă este pentru un programator, nu pentru a realiza că el sau ea este de a permite o serie de date să fie scrise într-o locație de memorie, în care nu a fost destinat. De exemplu, el sau ea declară o matrice de dimensiune 10 dar apoi accidental încearcă să afișezi 11 octeți în faptul că matrice de memorie, și de a începe să atingeți părți ale memoriei care nu mai sunt valabile. Doar pentru a contextuale acest lucru, unii dintre voi s-ar putea știți că software-ul de multe ori vă solicită pentru numere de serie sau chei de înregistrare, Photoshop și Word și programe de acest gen. Există fisuri, așa cum unii dintre voi știți, online, unde puteți rula un mic program, și voila, nici o cerere mai mare pentru un număr de serie. Cum este că funcționează? În multe cazuri, aceste lucruri sunt pur și simplu găsirea în calculatoarele segmente de text în zerouri calculatorului reale și cele în cazul în care este această funcție în cazul în care numărul de serie se solicită, și vă suprascrie acel spatiu, sau în timp ce programul se execută vă puteți da seama de unde cheia este de fapt stocat folosind ceva numit un debugger, și puteți sparge software-ul în acest fel. Acest lucru nu este să spun că acest lucru este obiectivul nostru pentru urmatoarele doua zile, dar are foarte reale ramificații. Asta se întâmplă să implice furtul de software, dar există, de asemenea, compromis de mașini întregi. De fapt, atunci când site-uri web în aceste zile sunt exploatate și compromise și de date este scurgeri si parole sunt furate acest lucru foarte des se referă la gestionarea proastă a memoriei cuiva, sau, în cazul bazelor de date, incapacitatea de a anticipa intrare contradictorie, astfel mai mult pe faptul că, în următoarele săptămâni să vină, dar pentru moment doar o previzualizare a fel de daune pe care le puteți face prin faptul că nu înțelege destul de cum merg lucrurile sub capota. Să mergem despre a intelege de ce acest lucru este rupt cu un instrument care va deveni mai mult și mai util ca programele noastre devin mai complexe. Astfel, de departe atunci când ai avut un bug în program cum te-ai dus despre depanarea asta? Care au fost tehnicile de până acum, indiferent dacă predate de TF dvs. sau pur si simplu autodidact? [Student] printf. Printf, deci printf a fost, probabil, prietenul tău în care, dacă doriți să vedeți ce se întâmplă în interiorul programului tocmai l-ați pus printf aici, printf aici, printf aici. Atunci când îl rulați, și veți obține o grămadă de chestii pe ecran pe care le puteți utiliza pentru a deduce, atunci ceea ce se întâmplă de fapt greșit în programul tău. Printf tinde să fie un lucru foarte puternic, dar este un proces foarte manual. Trebuie sa pui un printf aici, o printf aici, si daca o pui in interiorul unei bucle s-ar putea obține 100 de linii de ieșire pe care trebuie sa te cerne prin intermediul. Nu e un mecanism foarte user-friendly sau interactiv pentru programe de depanare, dar din fericire există alternative. Există un program, de exemplu, numit GDB, Debugger GNU, care este un pic obscură în modul în care îl utilizați. E un complex pic, dar, sincer, acesta este unul dintre acele lucruri pe care, dacă ați pus în această săptămână și viitoare ora in plus de a înțelege ceva de genul GDB acesta va salva, probabil, zeci de ore pe termen lung, Și cu asta, permiteți-mi să vă dau un teaser a modului în care acest lucru functioneaza. Sunt într-o fereastră terminalul meu. Lasă-mă să merg mai departe și compila acest program, buggy3. E deja până la data de. Lasă-mă să-l rulați la fel cum am facut-o înapoi în timp, și într-adevăr, e rupt. Dar de ce este acest lucru? Poate am greșit funcția de swap. Poate e un și b. Eu nu sunt destul de ei se deplasează în jurul valorii de corect. Lasă-mă să mergeți mai departe și de a face acest lucru. Mai degrabă decât doar să rulați buggy3 lasă-mă să ruleze în locul acestui program de GDB, și am de gând să-l spun pentru a rula buggy3, și am de gând să includă un argument linie de comandă, TUI-, și vom pune acest lucru în probleme viitoare la spec. să amintesc. Și acum această interfață în alb și negru a apărut, încă o dată, este un pic copleșitoare la început, deoarece există toate astea Informații garanție aici, dar cel puțin e ceva familiar. În partea de sus a ferestrei este codul meu real, și dacă am derula aici lasă-mă să derulați până la foarte de sus a dosarul meu, și într-adevăr, nu e buggy3.c, și observați în partea de jos a acestei ferestre Am acest prompt GDB. Acest lucru nu este același ca și meu obișnuit John Harvard promptă. Acesta este un prompt care va permite-mi să controleze GDB. GDB este un program de depanare. Un debugger este un program care vă permite să se plimbe prin executarea de linie programul de linie cu linie, de-a lungul modul în care faci tot ce vrei să programului, de asteptare chiar funcții, sau caută, mai important, la valori variabile diferite lui. Să mergem mai departe și de a face acest lucru. Am de gând să merg mai departe și tastați în termen de la promptul de GDB lui, astfel observa la partea din stânga jos a ecranului am tastat alerga, și am lovit intra, și ce a făcut asta? Ea a fugit literalmente programul meu, dar nu am vedea de fapt mult mai merge pe aici pentru că nu am spus de fapt, depanatorul pentru a întrerupe la un moment dat în timp. Tastarea doar pe termen ruleaza programul. Nu văd de fapt nimic. Eu nu pot manipula. În schimb lasă-mă să fac asta. La acest prompt GDB permiteți-mi să tastați în schimb pauză, introduceți. Asta nu e ceea ce am vrut să tastați. Să tastați în schimb pauză principal. Cu alte cuvinte, vreau să setați un punct de întrerupere ceva numit, care este pe bună dreptate numit, deoarece ea va rupe sau întrerupe executarea de programul tau la locul respectiv. Principal este numele de funcția mea. Observați că GDB este destul de inteligent. A dat seama că se întâmplă principal pentru a porni de la aproximativ linia 18 de buggy3.c, și observați apoi aici, la stânga-sus b + este chiar lângă linia de 18. Asta amintindu-mi că am stabilit un punct de control la linia 18. De data aceasta, când am tip alerga, am de gând să ruleze programul meu până când se atinge breakpoint că, astfel încât programul se va opri pentru mine la linia 18. Aici vom merge, alerga. Nimic nu pare să se fi întâmplat, dar atenție la partea din stânga jos Programul de pornire, buggy3, breakpoint 1 în principal la linia buggy3.c 18. Ce pot să fac acum? Observați că pot începe tastarea lucruri, cum ar fi imprimare, Nu printf, x imprimare, și acum, că e ciudat. $ 1 este doar o curiozitate, așa cum vom vedea de fiecare dată când imprimați ceva ce obține o nouă valoare $. Asta e, astfel încât să vă puteți referi înapoi la valorile anterioare doar în cazul, dar de acum ceea ce mi-a spus de imprimare este este faptul că valoarea lui x, la acest moment, în povestea este aparent 134514032. Ce? În cazul în care a făcut asta, chiar provin de la? [Imperceptibil-elev] Într-adevăr, aceasta este ceea ce vom numi o valoare de gunoi, și nu ne-am vorbit despre asta încă, dar motivul pentru care ați inițializa variabilele este, evident, astfel încât acestea să aibă o anumită valoare pe care doriți să le aibă. Dar captura este reamintesc că puteți declara variabile cum am făcut-o clipă în urmă, în exemplul meu sigma fără de fapt, oferindu-le o valoare. Amintesc ce am făcut aici, în Sigma. Eu n declarat, dar ce valoare l-am dat? Nici una, pentru că știam că, în următoarele câteva linii GetInt va avea grijă de problema de a pune o valoare a lui n interiorul. Dar, în acest moment, în povestea line 11 și 12 linie și linia 13 și linia 14 de-a lungul acestor linii de mai multe ceea ce este valoarea lui n? În C pur si simplu nu stiu. E, în general, o valoare gunoi, un numar complet aleatoare care a rămas în esență, din peste o funcție anterioară au fost executați, în așa fel încât programul se execută Reamintim că funcția devine funcție, funcția, funcția. Toate aceste cadre se pune pe memorie, iar apoi cei retur funcții, și așa cum am sugerat, cu radiera memoria lor este în cele din urmă reutilizate. Ei bine, ea doar se întâmplă, astfel încât aceasta variabila x în acest program pare să fi conținut o valoare gunoi ca 134514032 de la unele funcția anterioară, nu una pe care am scris-o. Ar putea fi ceva care vine în mod eficient cu sistemul de operare, o anumită funcție de sub capota. Bine, asta e bine, dar hai acum trece la următoarea linie. Dacă aș tip "next" la GDB promptă meu și l-am lovit intra, observați că se mută în jos pentru a evidenția linia 19, dar implicație logică este că linia 18 acum a terminat de executare, astfel încât, dacă tip I din nou "print x" Ar trebui să vedeți acum 1, și într-adevăr, să fac. Din nou, lucrurile $ este o modalitate de a GDB, amintindu-vă ceea ce istoria de printuri sunt pe care le-ați făcut. Acum, lasă-mă să merg mai departe și tipări y, și într-adevăr, y este o anumită valoare, precum și nebun, dar nu e mare lucru, deoarece, în linia 19 suntem pe cale să le atribuie valoarea 2, asa ca lasa-ma tastați "Next" din nou. Și acum suntem pe linia printf. Lasă-mă să fac x imprimare. Lasă-mă să fac y imprimare. Sincer, eu sunt un pic cam obosit de imprimare asta. Lasă-mă să tastați în loc "afișare x" și "y ecran," si acum de fiecare dată când tastați o comandă în viitor Eu voi fi amintit de ceea ce este x și y, ceea ce este x și y, ceea ce este x și y. Eu pot, de asemenea, ca o parte, de tip în "localnici info." Info este o comandă specială. Localnicii înseamnă că-mi arată variabilele locale. Doar în cazul în care mi-am uitat sau aceasta este o funcție nebun, complicat că am sau altcineva a scris localnici informatiile vă va spune Care sunt toate variabilele locale din interiorul această funcție locală care v-ar pasa daca vrei sa scoti in jurul. Acum, printf este pe cale să execute, deci lasă-mă să merg mai departe și doar tipul "Next". Pentru că suntem în acest mediu nu suntem de fapt, să-l văd executa aici, dar observați că acesta e un pic cam mangled aici. Dar observați că acesta este imperative ecran acolo, deci nu e un program perfect aici, dar asta e bine pentru că eu pot băga mereu în jurul valorii de utilizarea de imprimare dacă vreau. Lasă-mă să tastați Next din nou, iar acum aici e partea interesanta. În acest moment, în povestea y este 2, iar x este 1, cum sa sugerat aici, și, din nou, motivul pentru care acest este automat afișarea acum este pentru că am folosit comanda afișare x și y ecran, astfel încât momentul în care am introduce următoarea în teorie x și y ar trebui să devină schimbate. Acum, știm deja că nu va fi cazul, dar vom vedea într-un moment cum putem scufunda mai adânc pentru a afla de ce e adevărat. În continuare, și, din păcate, este încă y 2 și x este încă 1, și pot să confirm la fel de mult. Imprimare x, y imprimare. Într-adevăr, nici schimbarea sa întâmplat de fapt, așa că hai să înceapă peste asta. În mod clar de swap este rupt. Să tastați loc "Run" din nou. Permiteți-mi să spun da, vreau să-l reporniți de la început, introduceți. Acum m-am întors până la linia de 18. Acum observați x și y sunt valori de gunoi din nou. Următor, în continuare, în continuare, următoarea. Dacă m-am plictisit eu pot, de asemenea, să tastați n pentru viitor. Puteți să-l abrevierea pentru secventa mai scurt posibil de caractere. Swap este acum rupt. Haideti sa patrundem in, astfel încât în ​​loc să tastați următoarea, acum am de gând să tastați pas, astfel că am pășit în interiorul acestei funcții astfel încât să pot merge prin ea, asa ca am lovit pas și apoi introduceți. Observați că sare în jos evidențiază mai mică în programul meu pentru linia 36. Acum, ce sunt variabilele locale? Info localnici. Nimic încă pentru că nu am ajuns la acea linie, așa că hai să mergem mai departe și spun "Next". Acum, se pare că avem tmp, tmp de imprimare. Valoarea gunoi, nu? Așa cred. Cum imprima despre o, imprimare b, 1 și 2? Într-un moment, de îndată ce am Următorul tip nou tmp este de gând să ia o valoare de 1, sperăm, deoarece tmp va fi atribuit valoarea unei. Acum, haideți să nu imprimați o, b imprimare, dar imprima acum tmp, și este, într-adevăr 1. Lasă-mă să fac în continuare. Lasă-mă să fac în continuare. Am terminat funcția de swap. Sunt încă în interiorul ei, în linia 40, asa ca lasa-ma imprima o, b imprimare, și nu-mi pasă ce tmp este. Se pare ca de swap este corectă atunci când vine vorba de pompare a și b. Dar dacă aș scrie acum următoare, am sări înapoi la linia 25, și, bineînțeles, dacă am tip în x și y imprimare ei sunt încă neschimbate, deci nu am rezolvat problema. Dar acum, probabil diagnostic cu acest program GDB am primit cel puțin un pas mai aproape de intelegerea ceea ce se întâmplă rău, fără a fi nevoie să așternut codul nostru de a pune o printf aici, printf aici, aici și printf apoi difuzate din nou și din nou încercând să dau seama ce se întâmplă greșit. Am de gând să mergeți mai departe și din acest renunta cu totul cu demisia. Se va spune, atunci, "Quit oricum?" Da. Acum m-am intors de la promptul meu normal, si am terminat cu ajutorul GDB. Ca o paranteza, nu aveți nevoie pentru a utiliza aceasta-tui pavilion. De fapt, dacă o veți obține în esență, omite jumătatea de jos a ecranului. Dacă aș apoi tastați pauza principal și apoi executați Eu pot rula în continuare programul meu, dar ceea ce va face este mai mult textual Doar arată-mi o linie curentă la un moment dat. TUI-, interfața cu utilizatorul textuală, doar vă arată mai mult a programului dintr-o dată, ceea ce este, probabil, un pic mai ușor conceptual. Dar, într-adevăr, pot face chiar lângă, în continuare, în continuare, și am de gând să văd o linie la un moment dat, și dacă chiar vreau să văd ce se întâmplă Am posibilitatea să tastați listă și a vedea o grămadă de linii vecine. E un film care le-am cerut să te uiți pentru problema seturi 3 în care Nate se referă la unele dintre complicațiile GDB, iar acesta este unul dintre acele lucruri, sincer, în cazul în care un anumit procentaj non-triviale de tine niciodată nu va atinge GDB, și că va fi un lucru rău deoarece literalmente vei sfârși prin a petrece mai mult timp în cursul acestui semestru alungare jos bug-uri, atunci ar fi dacă ați pus în jumătate de oră / oră în această săptămână și de învățare următoare pentru a obține confortabil cu GDB. Printf a fost prietenul tău. GDB ar trebui sa fie acum prietenul tău. Orice întrebări cu privire la GDB? Și aici o listă scurtă a unora dintre comenzile cele mai puternice si folositoare. Da. >> Se poate imprima un șir? Poți să imprimați un șir? Absolut. Aceasta nu trebuie să fie doar întregi. În cazul în care o variabila este un șir de tip doar în s. imprimare. Acesta vă va arăta ce variabila șir este. [Imperceptibil-elev] Acesta vă va oferi adresa și șirul în sine. Acesta va arăta pe amândoi. Si inca un lucru trecut, doar pentru că acestea sunt bine de știut prea. Backtrace și cadru, lasă-mă să se arunca cu capul în acest moment ultima, Programul exact aceeasi cu GDB. Lasă-mă să mergeți mai departe și a alerga textuală versiunea interfața cu utilizatorul, rupe principal. Lasă-mă să mergeți mai departe și a alerga din nou. Iată-mă. Acum, lasă-mă să mergem, în continuare, în continuare, următoarea, în continuare, pas, introduceți. Și acum să presupunem că eu sunt acum în mod deliberat de swap, dar eu zic "La naiba, ce a fost valoarea lui x?" Eu nu pot face x mai. Eu nu pot face y, deoarece acestea nu sunt în sfera de aplicare. Ei nu sunt în context, dar nici o problema. Pot tip backtrace. Asta imi arata toate funcțiile de care s-au executate până la acest moment. Observați că una pe partea de jos, principal, se aliniază cu principal fiind la partea de jos a imaginii noastre de aici. Faptul că swap este deasupra ei linii de swap cu a fi mai sus, în memoria aici, și dacă vreau să mă întorc la principala temporar pot sa spun "cadru". Ce numar? Principal este cadru # 1. Am de gând să merg mai departe și spun "cadru 1." Acum m-am întors în principal, și eu pot imprima x, si pot imprima y, dar nu pot imprima pe a sau b. Dar eu pot, dacă spun, "Bine, stai un minut În cazul în care a fost de swap?". Lasă-mă să mergeți mai departe și spun "0 cadru." Acum m-am întors de unde vreau sa fie, si ca o paranteza, există alte comenzi prea, cum ar fi dacă într-adevăr vei primi dactilografiere plictisesc următoare, în continuare, în continuare, următoarea, vă pot spune, în general, lucruri de genul "urmatoarele 10," și că va parcurge următoarele 10 de linii. Puteți scrie, de asemenea, "continua" atunci când vei ajunge într-adevăr hrănite cu intensificarea prin ea. Continua programul va rula fără întrerupere până când lovește un alt punct de întrerupere, dacă într-o buclă sau scădea în programul tău. În acest caz, am continuat până la capăt, iar programul a ieșit în mod normal. Acesta este un mod fantezist, procesul inferior. Doar programul ieșit în mod normal. Mai mult pe faptul că, în video și sesiuni de depanare în a veni. Asta a fost o foarte mult. Să luăm de 5 minute de pauză aici, iar noi vom reveni cu struct și fișiere. Dacă ați plonjat în PSET această săptămână deja veți ști pe care le folosim în codul de distribuție, codul sursă pe care vi le oferim ca un punct de plecare, unele tehnici noi. În special, am introdus acest cuvânt cheie nou numit struct, pentru structura, astfel încât să putem crea variabile personalizate de soiuri. Am introdus, de asemenea, noțiunea de intrare fișier fișier I / O, și de ieșire, și acest lucru este astfel încât să putem salva de stat de bord Scramble într-un fișier pe disc astfel încât colegii de predare și pot să înțeleg ce se întâmplă în interiorul programului, fără a fi nevoie să joace manual zeci de jocuri de Scramble. Putem face acest lucru mai automatedly. Această idee a unei structuri rezolvă o problemă destul de convingătoare. Să presupunem că dorim să pună în aplicare programul de unele care ține evidența într-un fel de informații cu privire la elevi, și studenții ar putea avea, de exemplu, un ID, un nume și o casă într-un loc ca la Harvard, astfel încât acestea sunt de 3 bucăți de informații vrem să păstreze în jurul valorii de, asa ca lasa-ma sa plec mai departe și începe să scrie un mic program aici, includ stdio.h. Lasă-mă să fac includ cs50.h. Și apoi începe funcția mea principală. Nu voi deranja cu orice argumente de linie de comandă, și aici vreau să am un student, așa că am de gând să spun un student are un nume, așa că am de gând să spun "nume șir." Apoi, am de gând să spun un student are, de asemenea, un act de identitate, codul de identificare astfel int, și un student are o casă, așa că am de gând să spun, de asemenea, "casa șir." Atunci voi comanda aceste pic mai curat-o ca asta. Ok, acum am 3 variabile cu care să reprezintă un student, deci "un student." Și acum vreau să populeze aceste valori, asa ca lasa-ma sa plec mai departe și spune ceva de genul "Id = 123." Numele este mergi la a lua pe David. Să spunem casa este mergi la a lua Mather, și apoi am de gând să fac ceva arbitrar ca printf ("% s, a cărui identitate este% d, locuiește în s.%. Și acum, ce vreau să conectați aici, unul după altul? Nume, id, casa; return 0. Bine, dacă nu am greșit undeva aici Cred că avem un program destul de bun care stochează un elev. Desigur, asta nu este tot ceea ce interesant. Ce se întâmplă dacă doriți să aveți 2 studenți? Asta nu e mare lucru. Eu pot sprijini 2 persoane. Lasă-mă să mergeți mai departe și de a evidenția acest lucru și du-te în jos aici, si eu pot spune "id = 456" pentru cineva ca Rob care locuieste in Kirkland. Bine, stai, dar eu nu pot apela aceste același lucru, si se pare ca am de gând să aibă de a copia acest lucru, asa ca lasa-mi să spun că acestea vor fi variabile lui David, și lasă-mă să iau niște copii ale acestora pentru Rob. Vom numi aceste lui Rob, dar acest lucru nu este de gând să lucreze acum deoarece am-aștept, să-mi schimbe la ID1, NAME1 și house1. Rob va fi de 2, 2. Am să schimbe acest lucru aici, aici, aici, aici, aici, aici. Stai, ce zici de Tommy? Hai să facem asta din nou. Evident, dacă încă mai cred aceasta este o modalitate buna de a face acest lucru, nu este, astfel copy / paste rău. Dar am rezolvat asta acum o săptămână. Care a fost soluția noastră atunci când ne-am dorit să avem mai multe instanțe de același tip de date? Elevii [] O matrice. O matrice, asa ca lasa-ma sa incerc sa curat asta. Lasă-mă să fac ceva loc pentru mine în partea de sus, și lasă-mă să fac asta în locul aici. Vom chema pe acești oameni, și în loc să mă duc să spun "id-uri de int," și am de gând să sprijine 3 dintre noi de acum. Am de gând să spun "nume șir," și voi sprijini 3 din noi, si apoi am de gând să spun "case de coarde," și am de gând să sprijine 3 din noi. Acum in locul lui David, aici a obține variabilele sale locale proprii putem scăpa de ele. Asta se simte bine că suntem de curățare asta. Pot spune atunci David va fi [0] și numele [0] și case [0]. Și apoi Rob ne poate salva în mod similar în acest sens. Să punem asta aici, asa ca va fi arbitrar id-uri [1]. El va fi nume [1], și apoi în cele din urmă, case [1]. Încă un pic plictisitoare, și acum am să dau asta, așa că hai să spunem "nume [0], id-ul [0], case [0], si sa trece la plural acest lucru. Id-uri de, id-uri, id-uri. Și din nou, eu o fac, așa că, din nou, eu sunt deja a recurge la copy / paste din nou, deci sansele sunt acolo e altă soluție aici. Eu pot curăța, probabil, asta în continuare, cu o buclă sau ceva de genul asta, Deci, pe scurt, e un pic mai bine, dar încă se simte ca Sunt recurge la copy / paste, dar chiar și acest lucru, eu susțin, este într-adevăr nu fundamental soluția corectă, deoarece Ce se întâmplă dacă cândva ne hotărâm știi ce? Am într-adevăr ar fi trebuit stocarea adreselor de e-mail pentru David și Rob și toată lumea în acest program. Ar trebui să stocați numere de telefon, de asemenea,. Noi ar trebui să stoca, de asemenea numere de urgență de contact. Avem toate aceste fragmente de date pe care dorim să le stoca, asa cum te duci despre a face asta? Ai declară un alt tablou în partea de sus, și apoi adăugați manual o adresă de e-mail [0], adresa de e-mail [1] pentru David și Rob și așa mai departe. Dar există cu adevărat doar o presupunere care stă la baza acestui design că eu sunt, folosind sistemul onoarea să știe că [I] în fiecare din cele tablouri mai multe doar așa se întâmplă să se refere la aceeași persoană, astfel încât [0] în actele de identitate este numărul 123, și am de gând să-și asume faptul că numele [0] este aceeași persoană numele și casele [0] este casa aceeași persoană și așa mai departe pentru toate tablouri diferite pe care le creează. Dar observați că nu există nici o legătură fundamentală printre cele 3 bucăți de informații, id-ul, numele și casa, chiar dacă entitatea noi încercăm să model în acest program nu este matrice. Matricile sunt doar acest mod programatic de a face acest lucru. Ceea ce vrem cu adevărat să modeleze în programul nostru este o persoană ca David, o persoana ca Rob interiorul căruia se sau încapsulare este un nume si ID-ul și o casă. Poate ne exprimăm într-un fel această idee de încapsulare prin care o persoană are o identitate, un nume și o casă și nu recurg la acest hack cu adevărat, prin care ne-am încredere că ceva suportul se referă la aceeași entitate umană, în fiecare din aceste tablouri disparate? Noi putem face de fapt acest lucru. Lasă-mă să merg mai sus principal de acum, și lasă-mă să creați propriul meu tip de date într-adevăr pentru prima dată. Am folosit această tehnică în Scramble, dar aici am de gând să merg mai departe și de a crea un tip de date, și știi ce, am de gând să-l sun elev sau persoană, și am de gând să utilizeze typedef pentru a defini un tip. Am de gând să spun că aceasta este o structură, și apoi această structură va fi de student tip, vom spune, chiar daca e un pic datat acum pentru mine. Vom spune "int id." Vom spune "nume șir." Apoi, vom spune "casa șir," asa ca acum, până la sfârșitul acestor câteva linii de cod Am învățat doar zăngănit că există un tip de date în afară de Ints, pe langa siruri de caractere, în afară de dublu, în afară de flotoare. Începând din acest moment, în conformitate timp 11, există acum un nou tip de date numit studenți, si acum pot declara o variabila elev oriunde vreau, asa ca lasa-ma aici, defilați în jos la oameni. Acum pot scapa de acest lucru, iar eu pot merge înapoi la David aici, și pentru David pot spune de fapt că David, putem numi literalmente variabila după mine, va fi de student tip. Acest lucru ar putea arata un pic ciudat, dar asta nu este tot ceea ce diferit de la declararea ceva ca un int sau un șir de caractere sau un flotor. Doar așa se întâmplă să fie numit elev acum, și dacă vreau să pun ceva în interiorul acestei structuri Acum trebuie să utilizeze o noua piesa de sintaxă, dar e destul de simplă, david.id = 123, david.name = "David" în capitalul D, și david.house = "Mather," și acum mă pot scăpa de aceste lucruri aici. Observați că am reproiectat acum programul nostru într-un mod într-adevăr mult mai bine în faptul că acum programul nostru reflectă lumea reală. E o noțiune lumea reala a unei persoane sau a unui elev. Aici avem acum o versiune C a unei persoane sau mai precis un student. În interiorul acelei persoane sunt aceste caracteristici relevante, ID-ul, numele și casa, așa Rob devine în esență, același lucru aici, asa elev jefuiască, și acum rob.id = 456, rob.name = "Rob". Faptul că variabila se numeste Rob este un fel de lipsită de sens. Am putut numi x sau y sau z. Noi doar a numit-o Rob să fie coerente semantic, dar de fapt numele este în interiorul acest domeniu în sine, asa ca acum am asta. Acest lucru nu prea se simt ca cel mai bun design, în care le-am codificat greu David. Am codificate greu Rob. Și eu încă mai trebuie să recurgă la unele copiați și lipiți de fiecare dată când vreau variabile noi. Mai mult decât atât, trebuie să dau aparent fiecare dintre aceste variabile un nume, chiar dacă aș mai degrabă descriu aceste variabile  elevii mai mult generic ca. Acum putem uni ideile care au fost de lucru bine pentru noi și spun în schimb, "Știi ce, dă-mi un elevilor variabilă numită, si hai sa l-au fi de marimea 3, "așa că acum pot rafina acest lucru în continuare, scăpa de David manual a declarat, si eu pot spune în schimb ceva de genul elevi [0] aici. Pot spune atunci elevii [0] aici, elevii [0] aici, și așa mai departe, și eu pot merge în jurul valorii de și curățați că pentru Rob. Am putea merge, de asemenea, despre adăugarea acum poate o buclă și utilizarea getString și GetInt pentru a obține de fapt, aceste valori de la utilizator. Aș putea merge despre adăugarea unei constante, deoarece acest lucru este, în general, de rău practică la codul de greu un numar arbitrar ca 3 chiar aici și apoi amintiți-vă doar că ar trebui să pună mai mult de 3 elevi în ea. Acesta ar fi, probabil, mai bine să folosiți # define la partea de sus a fișierului meu și factorul de asta, așa, într-adevăr, lasă-mă să mergeți mai departe și să generalizeze acest lucru. Lasă-mă să deschid un exemplu care e printre azi exemple în avans, structs1. Acesta este un program mai complet care foloseste # define aici și spune că vom avea 3 elevi în mod implicit. Aici am declara o valoare de clasa de elevi, deci o clasă de elevi, iar acum eu sunt, folosind o buclă doar pentru a face codul un pic mai elegant, populează clasa cu intrare utilizatorului, itera astfel de la i = 0, pe până la studenți, care este 3. Și apoi am cere utilizatorului în această versiune  ceea ce este ID-ul elevului, si m-am prins cu GetInt. Care e numele elevului, iar apoi am să-l cu getString. Ce e casa elevului? M-am prins cu getString. Și apoi în partea de jos aici, am decis să schimbe cum mă imprimarea pe acestea și să utilizeze o buclă de fapt, Și cine sunt eu de imprimare? Potrivit comentariul Sunt imprimarea pe nimeni în Mather, și că e atât de Rob și Tommy și așa mai departe, de fapt lui Tommy în Mather. Tommy și David ar fi tipărite în acest caz, dar cum este aceasta funcționează? Noi nu am văzut această funcție înainte, dar ia o presupunere cu privire la ce face asta. Compară siruri de caractere. E un pic non-evident cum se compară siruri de caractere, deoarece se dovedește în cazul în care returnează 0 înseamnă că șirurile sunt egale. În cazul în care returnează un -1 înseamnă că unul vine în ordine alfabetică în fața celuilalt, și dacă se returnează 1 înseamnă că alt cuvânt vine în ordine alfabetică înainte de altă parte, poti sa te uiti si on-line sau de la pagina de om pentru a vedea exact care este calea pe care, dar toate acest lucru este acum face este ea spune în cazul în care [i]. casa este egal cu "Mather" apoi mergeți mai departe și tipări așa și așa este în Mather. Dar aici e ceva ce nu am mai văzut până acum, și ne vom întoarce la asta. Nu-mi amintesc niciodată nevoie să faceți acest lucru în oricare dintre programele mele. Gratuit este aparent referindu-se la memorie, eliberarea de memorie, dar ceea ce caut eu de memorie aparent eliberând în această buclă, la partea de jos a acestui program? Se pare ca am eliberarea numele unei persoane și casa unei persoane, dar de ce e asta? Se pare că toate aceste săptămâni pe care le-ați folosit getString am fost un fel de introducere a unui bug în fiecare dintre programele dumneavoastră. GetString de memorie de design alocă astfel încât să poată reveni la un șir, ca David, sau Rob, și puteți face, atunci ce vrei cu faptul că șirul în programul dvs., deoarece ne-am rezervat de memorie pentru tine. Problema este tot acest timp de fiecare data cand suna getString Noi, autorii getString, au cerut sistemul de operare să ne dea un pic de RAM pentru acest șir. Dă-ne un pic de RAM pentru acest șir următoare. Dă-ne ceva mai mult RAM pentru acest șir următoare. Ce ai, programator, nu au făcut este oferindu-ne că înapoi de memorie, astfel încât pentru aceste câteva săptămâni toate programele pe care le-ați scris au avut ceea ce se numește un salt de memorie prin care acestea continuă să utilizeze mai multă memorie și mai mult de fiecare dată când suna getString, și asta e bine. Noi facem în mod deliberat faptul că, în primele săptămâni, pentru că nu e interesant să aibă de a vă faceți griji în cazul în care șirul este venind de la. Tot ce vreau este cuvântul Rob să vină înapoi, atunci când utilizatorul îl tipuri de inch Dar merge mai departe acum avem de a începe să obtinerea mai sofisticate despre acest lucru. De fiecare dată când vom aloca memorie mai bună preda în cele din urmă înapoi. În caz contrar, în lumea reală pe Mac sau PC-ul ar putea să aibă experiență ocazional în cazul în care simptomele computerul este rectificat la un popas în cele din urmă sau prost mingea plajă se rotește ocupă doar de calculator intreaga atentie si nu poti face lucruri. Care poate fi explicat prin orice număr de bug-uri, dar printre aceste bug-uri posibile sunt lucruri numite scurgeri de memorie în care cineva care a scris acea bucată de software pe care îl utilizați nu-mi amintesc să eliberați memorie că el sau ea a cerut pentru sistemul de operare, Nu utilizați getString, pentru că e un lucru CS50, dar folosind funcții similare că cere sistemul de operare pentru memorie. Daca tu sau ei în bară și nu se mai întorc de fapt că memoria un simptom de care poate fi faptul că un program de încetinește și încetinește și încetinește excepția cazului în care uitați să apelați gratuit. Vom reveni la când și de ce v-ar suna gratuit, dar hai sa mergem mai departe doar pentru o bună măsură și încercați să rulați acest program special. Acest lucru a fost numit structs1, introduceți. Lasă-mă să mergeți mai departe și a alerga structs1, 123, David Mather, 456, Rob Kirkland, 789, Tommy Mather, și vom vedea David în Mather, Tommy în Mather. Acesta este doar un cec bun-simț mic care programul este de lucru. Acum, din păcate, acest program este un pic frustrant, în care Am facut tot ce locul de muncă, am scris în 9 siruri de caractere diferite, a lovit introduceți, sa spus care era în Mather, dar, evident, știam care era în Mather deja pentru că l-am scris. Ar fi de cel puțin frumos dacă acest program este mai mult ca o bază de date și-l amintește de fapt ceea ce am scris în deci nu am avea din nou pentru a introduce aceste înregistrări elevilor. Poate e ca un sistem de registrarial. Putem face acest lucru utilizând această tehnică cunoscută sub numele de intrare fișier fișier I / O, și de ieșire, un mod foarte generic de a spune orice moment doriți să citiți fișiere sau scrie fișiere puteți face acest lucru cu un anumit set de funcții. Lasă-mă să merg mai departe și deschide acest structs2.c exemplu, care este aproape identic, dar să vedem ce se face acum. În partea de sus a fișierului, declar o clasă de elevi. Am popula apoi clasa cu intrarea utilizatorului, astfel încât aceste linii de cod sunt exact ca înainte. Apoi, dacă am derula în jos aici am tipărarea toți cei care se află în mod arbitrar Mather ca înainte, dar aceasta este o caracteristica interesanta nou. Aceste linii de cod sunt noi, și ei introduc ceva aici, Fișier, toate capacele, și a * aici, de asemenea. Lasă-mă să mut asta aici, o * pe aici, de asemenea. Această funcție nu am văzut până acum, fopen, dar aceasta înseamnă fișier deschis, așa că hai să degresat prin acestea, și acest lucru este ceva ce ne vom întoarce la psets viitoare, dar această linie aici se deschide în esență, un fișier numit bază de date, și în mod special acesta se deschide în așa fel încât să poată face ceea ce cu ea? [Imperceptibil-elev] Corect, așa "w" doar înseamnă că e spune sistemul de operare deschide acest fișier în așa fel încât eu pot scrie la ea. Nu vreau să-l citesc. Nu vreau să se uite doar la el. Vreau să-l schimbe și să adăugați lucruri potențial să-l, și fișierul va fi numit de baze de date. Acest lucru ar putea fi numit nimic. Acest lucru ar putea fi database.txt. Acest lucru ar putea fi. DB. Acest lucru ar putea fi un cuvânt ca foo, dar am ales arbitrar pentru a numi fișier bază de date. Aceasta este o verificare sanatatea mic care vom reveni în detaliu mare-a lungul timpului, în cazul în care fp, pentru indicatorul dosar, nu NULL egal înseamnă că totul este bine. Pe scurt, cum ar fi funcțiile fopen nu reușesc uneori. Poate că fișierul nu există. Poate ești din spațiu pe disc. Poate nu aveți permisiunea de a acel folder, așa că, dacă fopen returneaza null ceva rău sa întâmplat. În schimb, în ​​cazul în care fopen nu intoarce null totul este bine și pot începe să scrie în acest dosar. Aici e un truc nou. Aceasta este o buclă pentru care a iterarea peste fiecare dintre elevii mei, și acest lucru pare atât de asemănătoare cu ceea ce am făcut înainte, dar această funcție este un văr de printf solicitat fprintf pentru fișier printf, și observați că acesta este diferit, în doar 2 moduri. Unul, incepe cu f în loc de p, dar apoi primul argument este aparent ce? Elevii [] fișier. >> E un fișier. Acest lucru numit fp, pe care în cele din urmă vom tachineze pe lângă ceea ce un pointer fisier este, dar de acum FP reprezintă pur și simplu fișierul pe care l-am deschis, astfel fprintf aici se spune tipărarea ID-ul acestui utilizator la dosar, nu pe ecran. Imprima numele de utilizator la dosar, nu pe ecran, casa la dosar, nu pe ecran, și apoi în jos aici, în mod evident, închideți fișierul, apoi aici gratuit de memorie. Singura diferență între această versiune 2 și versiunea 1 este introducerea fopen și acest fișier cu * și această noțiune de fprintf, asa ca hai sa vedem ce rezultatul final este. Lasă-mă să intru în fereastra terminalul meu. Lasă-mă să rulați structs2, introduceți. Se pare ca totul este bine. Să reluare structs2. 123, David Mather, 456, Rob Kirkland, 789, Tommy Mather, introduceți. Se pare că s-au comportat la fel, dar daca eu fac acum ls observați ce fisierul este aici, printre tot codul, baze de date, așa că hai să deschizi, gedit de baze de date, si uita-te la asta. Nu e cea mai sexy de formate de fișiere. Este într-adevăr este una bucată de linie de date pe linie pe linie, dar cei dintre voi care folosesc fisiere Excel sau CSV, valori separate prin virgulă, Am fi putut cu siguranță folosit pentru a fprintf loc poate face ceva de genul asta astfel încât am putut crea de fapt echivalentul unui fișier Excel prin separarea lucrurile cu virgula, nu doar linii noi. În acest caz, dacă aș fi folosit în loc virgule in loc de linii noi Am putut deschide literalmente acest fișier bază de date în Excel, dacă am făcut-o în locul arate ca asta. Pe scurt, acum că avem puterea de a scrie fișiere putem incepe acum date persistente, menținându-l în jurul valorii de pe disc astfel încât să putem păstra informațiile în jurul valorii de nou și din nou. Observați o serie de alte lucruri care acum sunt un pic mai familiar. În partea de sus a acestui fișier C avem un typedef pentru că am vrut să creăm un tip de date care reprezintă un cuvânt, astfel încât acest tip este numit cuvânt, și în interiorul acestei structuri e un pic crescator acum. De ce este un cuvânt compus din aparent o matrice? Ce este un cuvânt pur și simplu intuitiv? E un tablou de caractere. E o secvență de caractere spate în spate în spate. SCRISORI în toate capacele se întâmplă să fie arbitrar am spus lungime maxima de orice cuvânt în dicționarul pe care îl utilizăm pentru Scramble. De ce am un +1? Nul caracter. Recall atunci când am făcut exemplul Bananagrams avem nevoie de o valoare deosebită la sfârșitul cuvântului, în scopul de a ține evidența de unde de fapt sa încheiat cuvinte, și ca caietul de sarcini set de probleme spune aici suntem asocierea cu un cuvânt dat o valoare boolean, un steag, ca să spunem așa, adevărat sau fals. Ați găsit deja acest cuvânt, pentru că ne dăm seama avem nevoie de o modalitate de a aminti ceea ce nu doar un cuvânt este în Scramble dar dacă sunteți sau nu, om, l-au găsit astfel încât, dacă nu găsiți cuvântul "" nu poți chiar tip, introduceți,, introduceți,, introduceți și de a lua 3 puncte, 3 puncte, 3 puncte, 3 puncte. Ne dorim să fie în măsură să lista neagra acest cuvânt prin stabilirea unui bool pentru adevărat dacă deja ați găsit-o, și deci de aceea am încapsulate-o în această structură. Acum, aici, în Scramble e un alt struct numit dicționar. Absent aici este cuvântul typedef, deoarece, în acest caz, avem nevoie pentru a îngloba ideea unui dicționar, și un dicționar conține o grămadă de cuvinte, cum implicate de această matrice, și cât de multe dintre aceste cuvinte sunt acolo? Ei bine, indiferent de această dimensiune variabilă numită spune. Dar avem nevoie doar de un dicționar. Nu avem nevoie de un tip de date numit dicționar. Avem nevoie doar de unul dintre ei, așa că se transformă în C că, dacă nu spui typedef, vă spun doar struct, apoi în interiorul acolade ai pus variabilele tale, atunci ai pus numele. Acest lucru este declarat un dicționar variabilă numită care arata ca acest lucru. În schimb, aceste linii sunt crearea unei structuri de date reutilizabil numit cuvânt pe care le pot crea mai multe copii ale, la fel cum am creat copii multiple ale elevilor. Ce înseamnă acest lucru permite în cele din urmă ne-a face? Lasă-mă să merg înapoi în, să zicem, un exemplu simplu de ori mai simple, și lasă-mă să deschid, să zicem, compare1.c. Problema aici la mana este de fapt coaja de a întoarce strat de un șir și începe să luați de pe aceste roți de formare deoarece se dovedește că un șir în tot acest timp Este așa cum am promis in saptamana 1 de fapt doar un pseudonim, un sinonim din biblioteca CS50 pentru ceva care arată un pic mai criptic, * char, și am văzut această stea înainte. Am văzut-o în contextul de fișiere. Să vedem acum de ce am fost ascuns acest detaliu pentru ceva timp acum. Aici este un fișier numit compare1.c, și-l întreabă aparent ghidul pentru 2 siruri de caractere, S și T, și apoi încearcă să-l compara aceste siruri de caractere pentru egalitatea de șanse în linia 26, și dacă ele sunt egale se spune, "Tu tastat același lucru," și dacă ei nu sunt egale se spune, "Tu tastat lucruri diferite." Lasă-mă să merg mai departe și să executați acest program. Lasă-mă să intru în directorul sursa mea, fac o compare1. Acesta compilat bine. Lasă-mă să fugi compare1. Voi mări, introduceți. Spune ceva. HELLO. Voi spune ceva nou. HELLO. Eu cu siguranta nu am tastați lucruri diferite. Lasă-mă să încerc din nou. BYE BYE. Categoric, nu diferit, deci ce se întâmplă pe aici? Ei bine, ceea ce este cu adevărat comparată, în linia 26? [Imperceptibil-elev] Da, așa se pare că un șir, tipul de date, este un fel de minciună albă. Un sir este o char *, dar ceea ce este un char *? A char *, cum se spune, este un pointer, și un pointer este efectiv o adresă, o locație de memorie în sumă, iar dacă se întâmplă să fi tastat într-un cuvânt cum ar fi HELLO, retrag de la discuțiile anterioare ale siruri de caractere acest lucru este ca și cum cuvântul HELLO. Amintiți-vă că un cuvânt ca HELLO poate fi reprezentat ca o matrice de caractere ca aceasta și apoi cu un caracter special, la sfârșitul numit caracterul nul, cum denotă \. Ce este de fapt un șir? Observați că acest lucru este bucati multiple de memorie, și, de fapt, sfârșitul este cunoscut decât după ce te uiți prin șir întreg In cautare de caracterul nul specială. Dar dacă aceasta este o bucată de memorie din memoria calculatorului meu, să arbitrar spun că acest șir avut noroc, si a fost plasat la începutul memoria RAM a computerului meu. Acest lucru este octet 0, 1, 2, 3, 4, 5, 6 ... Când spun ceva de genul getString si eu sirul s = getString ceea ce e foarte care sunt returnate? Pentru aceste ultimele câteva săptămâni, ceea ce e cu adevărat a fi depozitate într s nu este acest șir în sine, dar, în acest caz, ceea ce se depozitate este 0 Numărul că ceea ce de fapt nu getString este că nu se întoarce fizic un șir. Asta nu face cu adevărat nici un sens conceptual. Ceea ce face revenirea este un număr. Acest număr este adresa HELLO în memorie, și șirul s, apoi, dacă ne coaja de spate acest strat, șir nu există cu adevărat. E doar o simplificare în bibliotecă CS50. Acest lucru este cu adevărat ceva numit char *. Char are sens, deoarece ceea ce e un cuvânt, cum ar fi HELLO? Ei bine, este o serie de caractere, o serie de caractere. * Char înseamnă adresa unui personaj, Deci, ce înseamnă să se întoarcă un șir? Un mod frumos, simplu, de a se întoarce un șir este, mai degrabă decât să încerce să dau seama cum să mă întorc la 5 sau 6 octeți diferite permiteți-mi să se întoarcă la adresa pe care byte? Primul. Cu alte cuvinte, permiteți-mi să vă dau adresa unui personaj în memorie. Asta e ceea ce char * reprezintă, adresa un caracter unic în memorie. Numesc asta e variabila. Magazin în care s anumită adresă, care am spus arbitrar este 0, doar pentru a menține lucrurile simple, dar în realitate este, în general, un număr mai mare. Stai un minut. Dacă sunteți doar să-mi dea adresa primului caracter, cum știu ce adresă este al doilea caracter, al treilea, al patrulea și al cincilea? [Imperceptibil-elev] Știi doar în cazul în care la sfârșitul string este cu titlu de acest truc la îndemână, astfel încât atunci când utilizați ceva de genul printf, ceea ce printf literalmente ia ca argument, Reamintim că vom folosi acest substituent% s, iar apoi treci la variabila care este un șir stocarea. Ceea ce într-adevăr trece este adresa primului caracter din șir. Printf foloseste apoi un pentru buclă sau o buclă în timp ce la primirea acea adresă, de exemplu, 0, asa ca lasa-mă să fac asta acum, printf ("% s \ n", s); Când m-am apel printf ("% s \ n", s); ceea ce am cu adevărat oferi printf cu este adresa primului caracter din s., care în acest caz este arbitrară H. Cum nu știe exact ce printf pentru a afișa pe ecran? Persoana care a pus în aplicare în aplicare printf o buclă în timp sau o buclă pentru care spune acest personaj nu egală cu caracterul nul special? Dacă nu, imprima. Ce zici de asta? Dacă nu-l imprimați, imprima, imprimați-l, îl imprimați. Oh, asta este special. Opri imprimarea și a reveni la utilizator. Și asta e tot ce literalmente sa întâmplat sub capota, și că o mulțime de a digera în prima zi a unei clase, dar acum este într-adevăr bloc a tot ceea ce înțelegere care a fost întâmplă în interiorul memoriei calculatorului nostru, și în cele din urmă vom prezenta în afară tachineze cu un pic de ajutor de la unul dintre prietenii nostri de la Stanford. Profesorul Nick Parlante de la Stanford a făcut această secvență video de minunat de la tot felul de limbi diferite, care au introdus acest mic personaj claymation Binky. Vocea esti pe cale de a auzi în doar o previzualizare a furișăm câteva secunde este cea a unui profesor de la Stanford, si vei primi doar 5 sau 6 secunde de asta acum, dar aceasta este nota pe care o vom încheia astăzi și să înceapă miercuri. Eu vă dau Fun Indicator cu Binky, previzualizare. [♪ ♪ Muzică] [Profesorul Parlante] Hei, Binky. Trezește-te. E timpul pentru distracție indicatorul. [Binky] Ce e asta? Aflați mai multe despre indicii? Ce bine! Vă vom vedea miercuri. [CS50.TV]