C++ Lektion Tecken och teckenfält Teori Hittills har alla variabler du jobbat med varit olika typer av tal, men du kan också deklarera variabler som håller bokstavstecken. Denna variabeltyp kallas för char, där char står för character och som i minnesutrymme tar upp en byte av datorns minne. Deklarationen blir : char tecken; En byte består som du kommer ihåg av 8 bitar. Den första biten är i många datorsystem en s.k. paritetsbit för kontrolländamål. De resterande sju bitarna kan var och en innehålla en etta (1) eller nolla (0). Med dessa sju bitar kan man skapa 128 olika kombinationer, vilka för datorn betyder värdena 0-127. Om vi deklarerar variabeln tecken som char så tolkas varje sifferkombination som ett visst tecken enligt en standard som kallas ASCII-standard. Vi säger att talet är teckenkoden för det tecknet. T.ex. är bitkombinationen 01000001 binärt med vårt siffersystem talet 65, vilket i ASCII-standarden betyder tecknet A. I nyare datormiljöer och framför allt i icke engelskspråkiga land, använder man en utvidgad ASCIIstandard som struntar i kontrollbiten och använder alla 8 bitarna, vilket då ger 256 olika kombinationer. Det gör att vi även får med t.ex. å, ä, ö, vilket ju inte är så dumt. Sist i lektionsplaneringen finns dessa koder som bilaga. För att tilldela en teckenvariabel ett värde skriver man tecknet inom apostrofer. tecken= A ; I variabeln tecken lagras då siffervärdet 65. Det gör att vi kan jämföra två tecken-variabler (eftersom vi då jämför tecknens representationsvärden), vilket kan vara bra t.ex. vid sortering i bokstavsordning: Se sista sidan i häftet för teckenkoder. char tecken1, tecken2; if (tecken1 < tecken2) cout<<tecken1<<"är minst"; else cout<<tecken2<<"är minst"; När man skriver ut variabeln tecken1 (som är deklarerad char) förstår däremot datorn att den ska skriva ut det tecken som värdet översätts till. Inläsning och utskrift av enkla tecken Inläsning cin >> c; inläsningsoperatorn >> hoppar över inledande mellanslag (vita tecken) Utskrift cout<<c; Skriver ut tecknet c. Sida 1
Exempelfiler TECKEN1.CPP #include <stdlib.h> char tecken1, tecken2; tecken1='a'; tecken2='a'; if ( tecken1 < tecken2 ) cout << tecken1 << " är minst" << endl; else cout << tecken2 << " är minst" << endl; det går även bra att initiera variablerna i deklarationen enskilda tecken skrivs inom apostrofer tecken lagras enligt ASCII-standard t ex A=65 a=97 lagras i 1 byte = 8 bitar med ettor och nollor, 256 kombinationer TECKEN2.CPP #include <stdlib.h> char tecken; cout << " Skriv ett tecken:" << endl; cin>>tecken; cout << "Tecknet är " << tecken << endl << endl; tecken=tecken+1; cout << "Nästa tecken är " << tecken << endl; tecken kan bara lagra ett enda tecken inläsningsoperatorn << hoppar över vita (tomma) tecken om man inte vill hoppa över vita tecken får man skriva while (cin.get(tecken)) cout << tecken; körs till vi skriver Ctrl-Z eller Ctrl-D Sida 2
Teckenfält (textsträngar) och standardfunktioner Du kan givetvis också göra en array(vektor, fält, lista) med tecken, på samma sätt som du gjorde med tal förra lektionen. En array av tecken kallas (tecken)sträng. För att lagra en text måste du ha ett teckenfält, ett fält med lådor (fack) som får innehålla värden av typen char. char namn[6]; cout << "Skriv ditt namn : "<< endl; cin >> namn; cout << endl << "HEJ " << namn; I deklarationen char namn[6]; talar man om hur många lådor det ska vara. Kom ihåg att lådorna numreras från 0 till 5. Efter deklarationen ser namn ut på följande sätt där "?" betyder skräp, det som råkar ligga i datorns minne när du kör programmet.?????? 0 1 2 3 4 5 Efter inläsningen cin >> namn; ser namn ut på följande sätt. T o r e \0? 0 1 2 3 4 5 Inläsningsoperatorn >> stoppar in nolltecknet \0 efter sista bokstaven. När man på sista raden skriver ut innehållet, läser datorn fram till nolltecknet och struntar i den sista lådan. En sådan här följd av tecken som avlutas med ett nolltecken är vad som kallas en textsträng. Observera att nolltecknet måste få plats i lådorna, vilket gör att namn med max fem bokstäver kan läsas in. Om du t.ex. läser in Petter kommer datorn att skriva någonstans i minnet utanför det som bokats upp vid deklarationen, och i princip vad som helst kan hända (beror på kompilatorn). Du kan ändra i en textsträng genom att ändra innehållet i en låda, precis på samma sätt som när du arbetade med fält (med t.ex. heltal). namn[0]= B ; namn[3]= i ; namn[4]= s ; namn[5]= \0 ; B o r i s \0 0 1 2 3 4 5 Kom ihåg att om du skriver över nolltecknet måste du lägga dit det igen. Skillnader på inläsning och utskrift av texter. cout << namn; cin >> namn; cin.getline(namn,n); Skriver ut textsträngen Läser till första blanka. Lägger in nolltecknet sist. Läser in en textsträng till namn, inklusive blanka, dock max n-1 tecken Den sista är mycket användbar, t.ex. om du vill läsa in textsträngen "P & B". Du kommer ihåg att man kunde initiera ett fält redan i deklarationen, t.ex. int tal[4]=7,3,15,2; På samma sätt kan teckenfält initieras direkt i deklarationen, fast strängen skrivs här inom citationstecken. char namn[6]="pelle"; Sida 3
Exempelfil TECKEN3.CPP teckenfält och textsträngar #include <stdlib.h> char namn[20], postnrochort[30], mat[50]; cout << " Vad heter du:" << endl; cin >> namn; cout << " Var bor du (postnr och ort):" << endl; för att kunna läsa postnr och ort, dvs även mellanslag första gången vi använder getline efter en cin-sats så måste vi dubbla den (!!tyvärr!!) cin.getline(postnrochort,30); cin.getline(postnrochort,30); cout << " Vilken är din favoritmaträtt:" << endl; cin.getline(mat,50); nu ska det inte dubblas cout << "Hejsan " << namn << endl; cout << "Som bor i " << postnrochort << endl; cout << "Favoritmaträtt: " << mat << endl; variabeln namn är ett teckenfält som består av tio tecken teckenlådan numreras från noll, som array ett nolltecken \0 placeras alltid sist ( ett tecken med nollor i alla 8 bitarna) Rita bild med Kalle och \0 i bitarna detta är en textsträng vad händer om vi heter Kristoffer?? jo, C++ kollar inte om vi håller oss inom variabelns längd, FARLIGT textsträngen kan bara vara n-1 lång dvs en mindre än deklarationen NORMALT sett fungerar det som ovan! skriv in för och efternamn, vad händer?? jo, inläsningen avbryts då ett vitt tecken påträffas, dvs bara förnamnet kommer med cin.getline(mat,50); Säker inläsning, läser en rad OBS! första gången vi använder getline så måste vi dubbla kommandot!?!?! vi kan även initiera i deklarationen: namn[10]="kalle" (citationstecken runt) andra tilldelningar s[]="kalle" (blir 6 lång) för att komma åt element används indexering cout << namn[2]; skriv ut element tre if ( namn[0]=='a' ) se om första tecknet är ett a namn[0]='p'; ändra element 0 till ett b Sida 4
getline_3.cpp förklarar hur man kan hantera getline -buggen!! int tal; char s[50]; cout<<"skriv in ett tal: "; cin>>tal; cout<<"talet var :"<<tal<<endl; cout<<"skriv in två ord : "; cin.getline(s, 50); cin.getline(s, 50); OBS! Dubbleringen vid första anropet cout<<"ordet var : "<<s<<endl; cout<<"skriv in två ord : "; cin>>s ; nollställs cout<<"ordet var : "<<s<<endl; OBS! cin används och allt cout<<"skriv in två ord : "; cin.getline(s, 50); cin.getline(s, 50); OBS! Dubbleringen behövs då även här cout<<"ordet var : "<<s<<endl; TECKENLISTA.CPP För utskrift av de 128 första ASCII-kod tecknen. #include <iomanip> char tecken; int kod; for (int nr = 0;nr<128;nr++) tecken = nr; cout << setw(6) << nr << " = " << tecken ; if (nr%5==0) cout << endl; Sida 5
Läs Läs i C++-manualen på Internet om tecken och teckenfält. Titta igenom exempelfilerna så att du förstår hur de fungerar och vad de olika delarna gör. Övningar Övningar på tecken och teckenfält. 1. Skapa en meny med hopp till funktioner ( förslag på struktur bifogas sist i detta dokument). OBS! För enkelhetens skull görs, för varje val, allt i själva funktionen. På menyn ska finnas a räkna antal tecken b vänd på meningen/ordet c byt till stora tecken d byt till små tecken e jämför om två exakt lika långa ord är lika f kopiera en sträng till en annan ny tom sträng g plocka ut n tecken från vänster h plocka ut n tecken från höger x plocka ut delsträng (t.ex. delstrang(sträng, start, antal tecken)). y hur många gånger förekommer ett ord i meningen z lägg till en sträng på ett visst ställe i en annan sträng Tips! Stega fram till null-tecknet och göra en test med hjälp av en if-sats (= = \0 ) eller villkor i while-sats. OBS! Valen x, y, z är mycket svåra att skapa. 2. Skriv ett program som läser in ett personnummer och avgör om personen är man eller kvinna. ( Den näst sista siffran är udda för män och jämn för kvinnor.) 3. Skriv ett program som läser in dagens datum på formen 19åå-mm-dd, dvs en textsträng. Sen läser du in en persons födelsedag på formen ååmmdd och skriver ut Grattis! Om personen har födelsedag annars Osis!. 4. I Astrid Lindgrens Kalle Blomqvist-böcker beskrivs ett hemligt språk, det s k rövarspråket. Det bildas genom att alla konsonanter dubbleras samtidigt som bokstaven o placeras mellan dem. Vokaler och andra tecken blir oförändrade. T ex : Kalle Anka blir KoKalollole Anonkoka Skriv ett program som översätter en text till rövarspråket. 5. Skriv ett program som krypterar innehållet i en textsträng genom att byta ut varje bokstav i strängen mot en viss annan bokstav. Tänk efter hur man bäst lagrar krypteringsinformationen. Skriv också ett program som dekrypterar en krypterad textsträng, dvs som återskapar den ursprungliga texten. Läxa Lösa minst övning 1a-h, 2 (MVG: uppgift 1y-z, 5, 6). Titta igenom exempelfilernas källkod så att du förstår deras uppbyggnad. Sida 6
MENY STOMME #include <conio.h> #include <windows.h> för _getch() - funktionen för Sleep() - funktionen void A() system("cls"); cout << endl << "AAAAAAAAAAAAAAAAAAAAAAAAA" << endl; Sleep(500); void B() system("cls"); cout << endl << "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" << endl; Sleep(500); void menu() char s; while( true) system("cls"); cout << "**************** MENY ***************" << endl; cout << "*************************************" << endl; cout << "******** Välj alternativ **********" << endl; cout << "************** A. ******************" << endl; cout << "************** B. ******************" << endl; cout << "************** ******************" << endl; cout << "*********** AVSLUTA (S)*************" << endl; cout << "*************************************" << endl; s = _getch(); if (s=='a') A(); else if (s=='b') B(); else if (s=='s' s=='s') break; int main( ) menu(); return 0; Sida 7
Teckenkoder OBS! De 127 första tecken stämmer alltid men resterande kan skilja beroende på dator. 1 71 G 141 211 Ó 2 72 H 142 Ž 212 Ô 3 73 I 143 213 Õ 4 74 J 144 214 Ö 5 75 K 145 215 6 76 L 146 216 Ø 7 77 M 147 217 Ù 8 78 N 148 218 Ú 9 tabb 79 O 149 219 Û 10 ny rad 80 P 150 220 Ü 11 81 Q 151 221 Ý 12 82 R 152 222 Þ 13 radslut 83 S 153 223 ß 14 84 T 154 š 224 à 15 85 U 155 225 á 16 86 V 156 œ 226 â 17 87 W 157 227 ã 18 88 X 158 ž 228 ä 19 89 Y 159 Ÿ 229 å 20 90 Z 160 230 æ 21 91 [ 161 231 ç 22 92 \ 162 232 è 23 93 ] 163 233 é 24 94 ^ 164 234 ê 25 95 _ 165 235 ë 26 96 ` 166 236 ì 27 97 a 167 237 í 28 98 b 168 238 î 29 99 c 169 239 ï 30-100 d 170 ª 240 ð 31 101 e 171 «241 ñ 32 102 f 172 242 ò 33! 103 g 173-243 ó 34 " 104 h 174 244 ô 35 # 105 i 175 245 õ 36 $ 106 j 176 246 ö 37 % 107 k 177 ± 247 38 & 108 l 178 ² 248 ø 39 ' 109 m 179 ³ 249 ù 40 ( 110 n 180 250 ú 41 ) 111 o 181 µ 251 û 42 * 112 p 182 252 ü 43 + 113 q 183 253 ý 44, 114 r 184 254 þ 45-115 s 185 ¹ 255 ÿ 46. 116 t 186 º 47 / 117 u 187» 48 0 118 v 188 ¼ 49 1 119 w 189 ½ 50 2 120 x 190 ¾ 51 3 121 y 191 52 4 122 z 192 À 53 5 123 193 Á 54 6 124 194  55 7 125 195 à 56 8 126 ~ 196 Ä 57 9 127 197 Å 58 : 128 198 Æ 59 ; 129 199 Ç 60 < 130 200 È 61 = 131 ƒ 201 É 62 > 132 202 Ê 63? 133 203 Ë 64 @ 134 204 Ì 65 A 135 205 Í 66 B 136 ˆ 206 Î 67 C 137 207 Ï 68 D 138 Š 208 Ð 69 E 139 209 Ñ 70 F 140 Œ 210 Ò Sida 8