C! ja taulukot 1.2.2018
Tiedotteita Tämän jälkeen taas pari väliviikkoa (tenttiviikko) Seuraava luento 22.2. Laskareita ei tenttiviikolla 12.2. 16.2. 2
ja muisti Muisti Keskusyksikkö Suorittaa muistissa olevaa ohjelmakoodia 0x123450 0x123458 0x123460 0x123468 0x123470 0x123478 0x123480 0x123488 char *osoitin = 0x123478; Käytännössä tietokoneen käyttöjärjestelmä vahtii muistin käyttöä esim. etteivät ohjelmat sotke toistensa muistiavaruuksia Käyttöjärjestelmäkin (esim. Windows) on ohjelma joka sijaitsee muistissa 4
Osoitin: viittaus muistiosoitteeseen Osoitteeseen kirjoitetaan tai luetaan jonkin tyyppistä tietoa Keskeinen osa a Mahdollistaa tiedon tehokkaan käsittelyn Taulukot Dynaamisen muistin käsittely Rajapinnat järjestelmäkomponenttien ja ajureiden välillä Monimutkaiset tietorakenteet 5
Osoittimen määrittely char a = 10; char *d = &a; Kaikki muuttujat sijaitsevat jossain osoitteessa Myös ohjelmakoodi sijaitsee muistissa Syntaksi: tietotyyppi *muuttuja Ylläolevat määritelmät kaksi eri tietotyyppiä Osoitinmuuttujan arvot ovat muistiosoitteita & - operaattorilla saadaan annetun objektin osoite &a: palauta muuttujan a osoite &:n unohtaminen edellä tuottaisi kääntäjän varoituksen 6
Yksinkertainen esimerkki void main() { char a = 10; char b = 12; int c = 123456; char *d = &a; char *e; } Osoittimeen e viittaaminen johtaisi virheeseen (ja tod. näk. ohjelman kaatumiseen) 7
Yksinkertainen esimerkki void main() { char a = 10; char b = 12; int c = 123456; char *d = &a; char *e; e = d; } Annetaan e:lle arvo 8
Viittausoperaattori *muuttuja: viite osoittamaan osoittamaan muistipaikkaan Voi käyttää lausekkeissa kuten muitakin muuttujia Sijoitus aiheuttaa kohteen arvon muuttumisen Eräänlainen vastakohta & - osoiteoperaattorille muuttuja voi olla myös lauseke: *(a + 2) on ok Eri operaatio kuin osoitinmuuttujan määrittäminen Jos osoitin viittaa virheelliseen osoitteeseen, ja sitä yritetään käyttää, ohjelma todennäköisesti kaatuu Useimmiten Segmentation fault Joskus vain outo toiminta 10
Yksinkertainen esimerkki void main() { char a = 10; char b = 12; int c = 123456; char *d = &a; char *e; e = d; *d = 13; d = 14; } Osoitin d viittaa virheelliseen muistiosoitteeseen d:hen viittaus todennäköisesti kaataa ohjelman 11
Osoitinaritmetiikka esimerkki short arr[4]; short *ref = arr; arr 0x1000 0x1002 0x1004 0x1006 0x1000 ref 12
Osoitinaritmetiikka esimerkki *ref = 1; ref++; arr 1 0x1000 0x1002 0x1004 0x1006 0x1002 ref 13
Osoitinaritmetiikka esimerkki *ref = 10; ref = ref + 2; arr 1 10 0x1000 0x1002 0x1004 0x1006 0x1006 ref 14
Osoitinaritmetiikka esimerkki ref++; *ref = 20; arr 1 10 0x1000 0x1002 0x1004 0x1006 20 0x1008 0x1008 ref -- Kääntäjä ei huomaa virhettä -- Ohjelma ei välttämättä kaadu -- Viittaus silti väärään muistipaikkaan -- Joskus vaikea havaita, monet tietoturva-aukot perustuvat tämäntyyppisiin virheisiin 15
Taulukko Taulukko on saman tyylisiä muuttujia peräkkäisissä muistipaikoissa C-kielessä ei mekanismia taulukon koon selvittämiseen Tiedettävä/sovittava muilla tavoin Mikään ei estä taulukon käyttöä yli kokorajojen Aiheuttaa virheen joka voi olla vaikea havaita Taulukolla läheinen suhde osoitinmuuttujaan Taulukkoon voidaan viitata osoitinmuuttujalla sen ensimmäiseen alkioon Suora sijoitus osoitinmuuttujaan toimii 16
Taulukkoesimerkki short apples = 10; short slots[4]; short oranges = 20; int i; for (i = 0; i < 4; i++) { /* Here we initialize the array */ slots[i] = i + 1; } for (i = 0; i < 4; i++) { /* Output the values in array */ printf("array element %d is %d\n", i, *(slots + i)); } 17
Taulukon käyttäminen [ ] operaattori Muoto: muuttuja[indeksi] Toimii kuten yksittäinen muuttuja Indeksi voi olla vakioarvo tai toinen muuttuja tai lauseke Indeksointi alkaa 0:sta Mikään ei estä viittaamasta taulukon yli tai alle (taulu[-1]) Vaihtoehtoisesti myös *(muttuja + indeksi) toimii Indeksioperaattoria voi käyttää myös kun taulukkoon viitataan osoittimella 18
Debuggeri Mahdollistaa ohjelman suorituksen yksityiskohtaisen analysoinnin Missä suoritus keskeytyi (esim. Segmentation fault) Mitä funktioita on kutsuttu (kutsupino) Suorituksen keskeytys halutussa kohdassa Jatkaminen tarvittaessa askel kerrallaan Muuttujien tilan tarkastelu Muuttujien tilan muuttaminen Jne. Komentorivipohjaisia: gdb, lldb Graafiset IDE:t sisältävät debuggerin 19
Taulukon käyttö funktiossa Taulukko voidaan välittää osoittimena sen ensimmäiseen arvoon Taulukon pituutta ei voi nähdä osoittimen perusteella Mutta voidaan esim. kertoa funktion parametrina Taulukko ei voi olla funktion paluuarvona Mutta funktio voi muokata annettua taulukkoa osoittimen kautta 21
Taulukko ja funktio -- esimerkki void show_table(short *a, size_t n) { int i; for (i = 0; i < n; i++) { printf("%d ", a[i]); } printf("\n"); } int main() { short table[] = { 1, 4, 6, 8}; printf("size: %lu\n", sizeof(table)); /* print array size for fun */ /* below is one way to get the number of elements */ show_table(table, sizeof(table)/sizeof(short)); } // in this case the above would be equivalent to: show_table(table, 4); 22
Taulukon pituuden välittäminen Taulukon pituutta ei voi nähdä pelkästä osoittimesta Vaihtoehtoja Pituus tunnettu / sovittu (sovelluksesta riippuen) Pituus kerrotaan muuttujalla tai funktion parametrissa Ed. esimerkki Tietty arvo lopettaa taulukon Kuten merkkijonoissa Annetaan osoitin taulukon loppuun Pituus kerrotaan ensimmäisessä alkiossa Em. Vaihtoehtojen soveltuvuus riippuu käyttötarpeesta 23
Muuta huomioitavaa taulukoista Taulukkoa ei voi kopioida suoralla sijoitusoperaatiolla Kopioitava alkio kerrallaan Taulukkoja ei voi vertailla suoraan Vaan esim. alkio kerrallaan 24
Lisämääreitä Kuinka tiedän muuttujan tarvitseman tilan? sizeof(tyyppi tai muuttuja) Kertoo kuinka monta tavua muistista tarvitaan Joskus on tarpeen myös kertoa, että osoitettua muistia ei ole tarkoitus muuttaa Esim: const char *muuttuja = hei vaan ; 25
Merkkijonot 26
Merkkijono Merkkijono C-kielessä on char tyyppinen taulukko Merkkijonon loppu merkitaan arvolla \0 Nolla-arvolle varattava tila taulukossa C:ssä merkkijono-taulukoilla on erityisasema Merkkijono voidaan määrittellä lainausmerkeissä normaalin taulukkosyntaksin ohella Useita kirjastofunktioita merkkijonojen käsittelyyn printf ja scanf - formatointi käyttäen %s muotoilumäärettä Merkkijono toimii kuten mikä tahansa taulukko Indeksointi, osoitinaritmetiikka, jne 27
Merkkijonon määrittely Merkkijono voidaan määritellä kuten mikä tahansa taulukko, tai käyttäen merkkijono notaatiota Jälkimmäisessa \0 on näkymätön ja lisätään automaattisesti char *string_a = "This is first string"; char string_b[] = "Another string"; char string_c[] = { 'O','n','e',' ','m','o','r','e','\0' }; string_a on vakiomuotoinen merkkijono Ei voi muuttaa Kuten kaikissa taulukoissa, alustava merkkijono määrää taulukon pituuden kun sitä ei ole erikseen annettu \0 merkki annettava jos käytetään taulukko-notaatiota 28
Merkkijonon määrittely char *string_a = "This is first string"; char string_b[] = "Another string"; char string_c[] = { 'O','n','e',' ','m','o','r','e','\0' }; string_a olisi parempi määritellä const - tyyppisenä 29
Yleisiä virheitä sizeof ja strlen sekoittaminen strlen: merkkijonon pituus merkkeinä olettaa char-taulukon joka päättyy nollamerkkiin (ajonaikainen) sizeof: muuttujan tarvitsema tila, osoittimille aina samaa kohdetyypistä riippumatta (käännösaikainen) 0-merkin unohtaminen merkkijonon lopusta Merkkijonon (tai muun taulukon) sijoittaminen = - operaattorilla Tarvitaan esim. strcpy() - funktio Merkkijonon vertailu loogisilla operaattoreilla Tarvitaan esim. strcmp() - funktio 30