Inmatningsproblemet Då man matar in data med scanf() till ett C-program kan det ibland uppstå problem när man gör inmatningar flera gånger i följd. Man kan då uppleva att programmet hoppar över en inmatning. Jag ska illustrera en lösning till detta problem som inte är en professionell lösning, men som i alla fall fungerar. Problematiken uppstår på grund av att det finns en inmatningsbuffert där tangenttryckningar lagras. Då vi gör en inmatning med scanf() matchas formatsträngen i anropet till scanf() mot innehållet i bufferten och inläsning sker. Om bufferten innehåller white space, alltså mellanslag, tabulatorsteg eller nyradstecken behandlas dessa såsom formatsträngen anger. Vid inläsning av ett heltal med formatsträngen “%d” läses de tangentryckningar som motsvarar ett heltal in och rätt variabel uppdateras. Vid upprepade inläsningar av heltal verkar C vara stabilt, följande program, som bara läser in två heltal och skriver ut dem efter varandra fungerar bra i NewTinyDebian: #include <stdio.h> main() { int t1, t2; printf("Tal 1: "); scanf("%d", &t1); printf("Tal 1: %d\n", t1); printf("Tal 2: "); scanf("%d", &t2); printf("Tal 2: %d\n", t2); } En provkörning: Tal Tal Tal Tal 1: 1: 2: 2: 10 10 20 20 Här är det som användaren matar in angivet i fetstil. Programmet skriver alltså bara ut det som användaren matat in och det uppstår inga problem. Om vi däremot byter datatyp till teckentypen, char, och arbetar med motsvarande program för tecken: #include <stdio.h> main() { char ch1, ch2; printf("Tecken 1: "); scanf("%c", &ch1); printf("Tecken 1: %c\n", ch1); printf("Tecken 2: "); scanf("%c", &ch2); printf("Tecken 2: %c\n", ch2); } så får vi faktiskt problem. En provkörning visar att beteendet i programmet verkar vara det att helt enkelt hoppa över andra inmatningen: Tecken 1: A Tecken 1: A Tecken 2: Tecken 2: Det här kan kännas väldigt frustrerande, men det finns en enkel förklaring och en enkel lösning. Bakgrunden är den så kallade inmatningsbufferten och vi kan visualisera programmets beteende genom att tänka oss inmatningsbufferten som en kö till programmet. Denna kö innehåller tangenttryckningar och när vi vill mata in två tecken till programmet ovan så vill vi trycka tangenterna 'A', 'returtecken', 'B', 'returtecken' och tänka oss att programmet läser in dessa. Dock så verkar som sagt programmet ovan inte ens ge oss en chans att skriva in 'B'. Förklaringen ligger i scanf():s beteende. Formatsträngen “%c” anger att vi ska läsa in ett tecken i variabeln vars adress följer efter formatsträngen. Av någon anledning väljer scanf() att endast läsa tangenttryckningen 'A' (i det här exemplet) och lämna kvar returtangenttryckningen i kön. När sedan nästa scanf() kommer och försöker läsa så kan inte den scanf() bortse från returtangenttryckningen utan läser in den och uppfattar den som ett slags slut på inmatning. Lösningen är att tömma inmatningsbufferten på returtangenttryckningar mellan anropen till scanf(). Det kan vi göra genom att läsa en så kallad sträng istället. Vi har inte börjat med strängar ännu, men vi kan ge en specialkonstruktion för att komma tillrätta med detta problem. Vi skriver om programmet ovan, så här: #include <stdio.h> #include <string.h> main() { char ch1, ch2; char buf[2]; printf("Tecken 1: "); scanf("%c", &ch1); gets(buf); printf("Tecken 1: %c\n", ch1); printf("Tecken 2: "); scanf("%c", &ch2); gets(buf); printf("Tecken 2: %c\n", ch2); } Och nu fungerar programmet bra, en testkörning visas nedan: Tecken Tecken Tecken Tecken 1: 1: 2: 2: A A B B Vi får en varning vid kompileringen men vi kan ignorera den nu i början av kursen. Vi ska se senare hur man rättar till det. Vad vi gör är att vi anropar funktionen gets() som läser en hel rad från inmatningsbufferten, fram till nästa nyradstecken, vi läser in detta in strängen buf som är deklarerad som en array av tecken. Vi behöver inte veta vad detta är ännu, vi kan bara lägga på ett gets(buf) direkt efter varje scanf() så fungerar de program vi skriver som vi tänkt. Senare ska vi se i detalj på vad gets() och vad strängar egentligen är, men just nu kan vi göra så här för att kunna komma vidare i de situationer då inmatningen inte fungerar som vi tänkt.