Programmering C: Radslut i C

Radslut anges i C med teckenkombinationen \n inuti sträng- och teckenliteraler:
printf("Hej Olle!\n");
printf("Hur mår du?\n");
printf("Jag mår bra.\n");
printf("Hälsningar Anna.\n");
Utskrift:
Hej Olle!
Hur mår du?
Jag mår bra.
Hälsningar Anna.
Radslutstecknet hanteras som vilket tecken som helst, så det behöver inte stå sist i utskrifterna. Den här koden ger samma utskrift:
printf("Hej Olle!\n");
printf("Hur mår du?\nJag mår");
printf(" bra.\nHälsningar Anna.\n");
Även om den ger samma utskrift, är den koden svårare att läsa och förstå. Därför ska man inte skriva så.

Jag vill särskilt avråda från den fula ovanan att sätta radslutstecknet i början av utskrifterna:

printf("Hej Olle!");
printf("\nHur mår du?");
printf("\nJag mår bra.");
printf("\nHälsningar Anna.");
Jag har sett ungefär sån här kod:
void skriv_brev(int brevnummer) {
    if (brevnummer > 1)
        printf("\nHej Olle!");
    else
        printf("Hej Olle!");
    printf("\nHur mår du?");
    printf("\nJag mår bra.");
    printf("\nHälsningar Anna.");
}

void skriv_tre_brev(void) {
    skriv_brev(1);
    skriv_brev(2);
    skriv_brev(3);
Notera hur det krävs specialbehandling av de olika breven, eftersom man måste hålla reda på om man nyss skrivit text på raden.

Av någon anledning är radslut-först vanligt bland studenterna på distanskursen i C-programmering. Jag tror faktiskt att majoriteten skriver så. De som är nybörjare tror jag tittar på mina exempel och sen gör likadant, med radslutet på slutet. Men många som läser C-distanskursen har erfarenhet sen tidigare, och av dem verkar många ha lärt sig radslut-först nånstans.

Rätt sätt är förstås så här, så det behövs ingen specialbehandling alls:

void skriv_brev(void) {
    printf("Hej Olle!\n");
    printf("Hur mår du?\n");
    printf("Jag mår bra.\n");
    printf("Hälsningar Anna.\n");
}

void skriv_tre_brev(void) {
    skriv_brev();
    skriv_brev();
    skriv_brev();
}

Men då blir det ju ett radslutstecken sist också?

Det ska vara ett radslut även på den sista raden man skriver ut. Alla rader avslutas med radslutstecken.

Men om man skriver till en fil då? Då blir det ju en tom rad sist i filen?

Även när man skriver till en fil. Det betyder inte att det blir en tom rad sist i filen, utan bara att den sista raden, precis som alla andra rader, avslutas med ett radslutstecken.

Nähä! Det blir fel! Titta här!

Om man har en textfil med tal, och det finns ett radslut sist i filen, kommer följande program att läsa ett tal för mycket:
#include <stdio.h>

int main(void) {
    FILE *tsin;
    double talet;

    tsin = fopen("reella-tal.txt", "r");
    while (!feof(tsin)) {
        fscanf(tsin, "%lf", &talet);
        printf("Ett tal: %f\n", talet);
    }

    return 0;
}
Men det beror inte på att det är fel på filen, utan det beror på att while (!feof(tsin)) är fel sätt att läsa data i C. feof returnerar nämligen inte sant när man läst det sista datat från filen, utan den blir sann först efter den första misslyckade läsningen.

Det här är rätt sätt:

#include <stdio.h>

int main(void) {
    FILE *tsin;
    double talet;

    tsin = fopen("reella-tal.txt", "r");
    while (fscanf(tsin, "%lf", &talet) != EOF) {
        printf("Ett tal: %f\n", talet);
    }

    return 0;
}

Men asynkrona utskrifter då?

Ja, okej då. Där kan man göra så. När det gäller utskrifter som kan komma osynkroniserat med övrig utmatning från programmet, kanske mitt i en rad, kan det vara rimligt att börja med radslut, så den nya utmatningen garanterat kommer på en egen rad:
fprintf(stderr, "\n*** Katastrofalt fel. Programmet avbryts.\n");
Själv delar jag hellre upp det, så det syns tydligare att det kommer ett radslut först:
fprintf(stderr, "\n");
fprintf(stderr, "*** Katastrofalt fel. Programmet avbryts.\n");


Thomas Padron-McCarthy (thomas.padron-mccarthy@oru.se), 2 januari 2014